summaryrefslogtreecommitdiff
path: root/regress/lib
diff options
context:
space:
mode:
authorJoel Sing <jsing@cvs.openbsd.org>2014-07-12 16:01:29 +0000
committerJoel Sing <jsing@cvs.openbsd.org>2014-07-12 16:01:29 +0000
commit7dbb741c19a6a70ae676e79e9a5ca1055411a3cb (patch)
tree489a8cebdd93c2740fd5f7f97fea225e9877eebe /regress/lib
parent91bec7f827239240f2a5fc351974de009dd87dd4 (diff)
Add an initial regress test for libressl, which calls ressl from Go and
makes it talk to a Go TLS server.
Diffstat (limited to 'regress/lib')
-rw-r--r--regress/lib/libressl/Makefile8
-rw-r--r--regress/lib/libressl/goressl/Makefile15
-rw-r--r--regress/lib/libressl/goressl/ressl.go157
-rw-r--r--regress/lib/libressl/goressl/ressl_test.go100
4 files changed, 280 insertions, 0 deletions
diff --git a/regress/lib/libressl/Makefile b/regress/lib/libressl/Makefile
new file mode 100644
index 00000000000..563753a1f07
--- /dev/null
+++ b/regress/lib/libressl/Makefile
@@ -0,0 +1,8 @@
+# $OpenBSD: Makefile,v 1.1 2014/07/12 16:01:28 jsing Exp $
+
+SUBDIR= \
+ goressl
+
+install:
+
+.include <bsd.subdir.mk>
diff --git a/regress/lib/libressl/goressl/Makefile b/regress/lib/libressl/goressl/Makefile
new file mode 100644
index 00000000000..d938db3f370
--- /dev/null
+++ b/regress/lib/libressl/goressl/Makefile
@@ -0,0 +1,15 @@
+# $OpenBSD: Makefile,v 1.1 2014/07/12 16:01:28 jsing Exp $
+
+GO_VERSION != sh -c "(go version) 2>/dev/null || true"
+
+.if empty(GO_VERSION)
+regress:
+ @echo golang is required for this regress... skipping
+.endif
+
+REGRESS_TARGETS=regress-goressl
+
+regress-goressl:
+ cd ${.CURDIR} && go test -test.v .
+
+.include <bsd.regress.mk>
diff --git a/regress/lib/libressl/goressl/ressl.go b/regress/lib/libressl/goressl/ressl.go
new file mode 100644
index 00000000000..b27a193814b
--- /dev/null
+++ b/regress/lib/libressl/goressl/ressl.go
@@ -0,0 +1,157 @@
+// Package ressl provides a Go interface to the libressl library.
+package ressl
+
+/*
+#cgo LDFLAGS: -lressl -lssl -lcrypto
+
+#include <stdlib.h>
+
+#include <ressl/ressl.h>
+
+typedef void *ressl;
+*/
+import "C"
+
+import (
+ "errors"
+ "fmt"
+ "unsafe"
+)
+
+// ResslConfig provides configuration options for a Ressl context.
+type ResslConfig struct {
+ caFile *C.char
+ resslCfg *C.struct_ressl_config
+}
+
+// Ressl encapsulates the context for ressl.
+type Ressl struct {
+ cfg *ResslConfig
+ ctx *C.struct_ressl
+}
+
+// Init initialises the ressl library.
+func Init() error {
+ if C.ressl_init() != 0 {
+ return errors.New("initialisation failed")
+ }
+ return nil
+}
+
+// NewConfig returns a new ressl configuration.
+func NewConfig() (*ResslConfig, error) {
+ cfg := C.ressl_config_new()
+ if cfg == nil {
+ return nil, errors.New("failed to allocate config")
+ }
+ return &ResslConfig{
+ resslCfg: cfg,
+ }, nil
+}
+
+// SetCAFile sets the CA file to be used for connections.
+func (c *ResslConfig) SetCAFile(filename string) {
+ if c.caFile != nil {
+ C.free(unsafe.Pointer(c.caFile))
+ }
+ c.caFile = C.CString(filename)
+ C.ressl_config_ca_file(c.resslCfg, c.caFile)
+}
+
+// SetInsecure disables verification for the connection.
+func (c *ResslConfig) SetInsecure() {
+ C.ressl_config_insecure(c.resslCfg)
+}
+
+// SetSecure enables verification for the connection.
+func (c *ResslConfig) SetSecure() {
+ C.ressl_config_secure(c.resslCfg)
+}
+
+// Free frees resources associated with the ressl configuration.
+func (c *ResslConfig) Free() {
+ if c.resslCfg == nil {
+ return
+ }
+ C.ressl_config_free(c.resslCfg)
+ c.resslCfg = nil
+}
+
+// New returns a new ressl context, using the optional configuration. If no
+// configuration is specified the defaults will be used.
+func New(config *ResslConfig) (*Ressl, error) {
+ var sslCfg *C.struct_ressl_config
+ if config != nil {
+ sslCfg = config.resslCfg
+ }
+ ctx := C.ressl_new(sslCfg)
+ if ctx == nil {
+ return nil, errors.New("ressl new failed")
+ }
+ return &Ressl{
+ cfg: config,
+ ctx: ctx,
+ }, nil
+}
+
+// Error returns the error message from the ressl context.
+func (r *Ressl) Error() string {
+ if msg := C.ressl_error(r.ctx); msg != nil {
+ return C.GoString(msg)
+ }
+ return ""
+}
+
+// Connect attempts to establish an SSL connection to the specified host on
+// the given port. The host may optionally contain a colon separated port
+// value if the port string is specified as an empty string.
+func (r *Ressl) Connect(host, port string) error {
+ h := C.CString(host)
+ var p *C.char
+ if port != "" {
+ p = C.CString(port)
+ }
+ defer C.free(unsafe.Pointer(h))
+ defer C.free(unsafe.Pointer(p))
+ if C.ressl_connect(r.ctx, h, p) != 0 {
+ return fmt.Errorf("connect failed: %v", r.Error())
+ }
+ return nil
+}
+
+// Read reads data the SSL connection into the given buffer.
+func (r *Ressl) Read(buf []byte) (int, error) {
+ var inlen C.size_t
+ if C.ressl_read(r.ctx, (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)), (*C.size_t)(unsafe.Pointer(&inlen))) != 0 {
+ return -1, fmt.Errorf("read failed: %v", r.Error())
+ }
+ return int(inlen), nil
+}
+
+// Write writes the given data to the SSL connection.
+func (r *Ressl) Write(buf []byte) (int, error) {
+ var outlen C.size_t
+ p := C.CString(string(buf))
+ defer C.free(unsafe.Pointer(p))
+ if C.ressl_write(r.ctx, p, C.size_t(len(buf)), (*C.size_t)(unsafe.Pointer(&outlen))) != 0 {
+ return -1, fmt.Errorf("write failed: %v", r.Error())
+ }
+ return int(outlen), nil
+}
+
+// Close closes the SSL connection.
+func (r *Ressl) Close() error {
+ if C.ressl_close(r.ctx) != 0 {
+ return fmt.Errorf("close failed: %v", r.Error())
+ }
+ return nil
+}
+
+// Free frees resources associated with the ressl context.
+func (r *Ressl) Free() {
+ if r.ctx == nil {
+ return
+ }
+ C.ressl_free(r.ctx)
+ r.ctx = nil
+}
diff --git a/regress/lib/libressl/goressl/ressl_test.go b/regress/lib/libressl/goressl/ressl_test.go
new file mode 100644
index 00000000000..665d4e0cefb
--- /dev/null
+++ b/regress/lib/libressl/goressl/ressl_test.go
@@ -0,0 +1,100 @@
+package ressl
+
+import (
+ "encoding/pem"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "os"
+ "strings"
+ "testing"
+)
+
+// createCAFile writes a PEM encoded version of the certificate out to a
+// temporary file, for use by ressl.
+func createCAFile(cert []byte) (string, error) {
+ f, err := ioutil.TempFile("", "ressl")
+ if err != nil {
+ return "", fmt.Errorf("failed to create file: %v", err)
+ }
+ defer f.Close()
+ block := &pem.Block{
+ Type: "CERTIFICATE",
+ Bytes: cert,
+ }
+ if err := pem.Encode(f, block); err != nil {
+ return "", fmt.Errorf("failed to encode certificate: %v", err)
+ }
+ return f.Name(), nil
+}
+
+const httpContent = "Hello, ressl!"
+
+func TestResslBasic(t *testing.T) {
+ ts := httptest.NewTLSServer(
+ http.HandlerFunc(
+ func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintln(w, httpContent)
+ },
+ ),
+ )
+ defer ts.Close()
+
+ u, err := url.Parse(ts.URL)
+ if err != nil {
+ t.Fatalf("Failed to parse URL %q: %v", ts.URL, err)
+ }
+
+ caFile, err := createCAFile(ts.TLS.Certificates[0].Certificate[0])
+ if err != nil {
+ t.Fatalf("Failed to create CA file: %v", err)
+ }
+ defer os.Remove(caFile)
+
+ if err := Init(); err != nil {
+ t.Fatal(err)
+ }
+
+ cfg, err := NewConfig()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer cfg.Free()
+ cfg.SetCAFile(caFile)
+
+ ssl, err := New(cfg)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ssl.Free()
+
+ t.Logf("Connecting to %s", u.Host)
+
+ if err := ssl.Connect(u.Host, ""); err != nil {
+ t.Fatal(err)
+ }
+ defer ssl.Close()
+
+ n, err := ssl.Write([]byte("GET / HTTP/1.0\n\n"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("Wrote %d bytes...", n)
+
+ buf := make([]byte, 1024)
+ n, err = ssl.Read(buf)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("Read %d bytes...", n)
+
+ if !strings.Contains(string(buf), httpContent) {
+ t.Errorf("Response does not contain %q", httpContent)
+ }
+
+ if err := ssl.Close(); err != nil {
+ t.Fatal(err)
+ }
+}