summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2017-11-09 14:09:14 -0800
committerGarrett D'Amore <garrett@damore.org>2017-11-20 21:49:09 -0800
commit02178a8b5843a2c5a59fb7b104e4f9f5df1ff5ee (patch)
tree122ee2bebf060aa26d6fa0778b877a6b7ca9b864 /tests
parente8694d15d0a108895bf869f292d59e11d834361e (diff)
downloadnng-02178a8b5843a2c5a59fb7b104e4f9f5df1ff5ee.tar.gz
nng-02178a8b5843a2c5a59fb7b104e4f9f5df1ff5ee.tar.bz2
nng-02178a8b5843a2c5a59fb7b104e4f9f5df1ff5ee.zip
fixes #3 TLS transport
This introduces a new transport (compatible with the TLS transport from mangos), using TLS v1.2. To use the new transport, you must have the mbed TLS library available on your system (Xenial libmbedtls-dev). You can use version 2.x or newer -- 1.3.x and PolarSSL versions are not supported. You enable the TLS transport with -DNNG_TRANSPORT_TLS=ON in the CMake configuration. You must configure the server certificate by default, and this can only be done using nng options. See the nng_tls man page for details. This work is experimental, and was made possible by Capitar IT Group BV, and Staysail Systems, Inc.
Diffstat (limited to 'tests')
-rw-r--r--tests/CMakeLists.txt1
-rw-r--r--tests/tls.c186
-rw-r--r--tests/trantest.h90
3 files changed, 261 insertions, 16 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index f6a476ab..30f76a1d 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -139,6 +139,7 @@ add_nng_test(sock 5)
add_nng_test(survey 5)
add_nng_test(synch 5)
add_nng_test(transport 5)
+add_nng_test(tls 10)
add_nng_test(tcp 5)
add_nng_test(tcp6 5)
add_nng_test(scalability 20)
diff --git a/tests/tls.c b/tests/tls.c
new file mode 100644
index 00000000..e4e430af
--- /dev/null
+++ b/tests/tls.c
@@ -0,0 +1,186 @@
+//
+// Copyright 2017 Garrett D'Amore <garrett@damore.org>
+// Copyright 2017 Capitar IT Group BV <info@capitar.com>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#include "convey.h"
+#include "nng.h"
+#include "protocol/pair1/pair.h"
+
+#include "transport/tls/tls.h"
+
+#include "trantest.h"
+
+#include "stubs.h"
+// TCP tests.
+
+#ifndef _WIN32
+#include <arpa/inet.h>
+#endif
+
+// These keys are for demonstration purposes ONLY. DO NOT USE.
+// The certificate is valid for 100 years, because I don't want to
+// have to regenerate it ever again. The CN is 127.0.0.1, and self-signed.
+//
+// Generated using openssl:
+//
+// % openssl ecparam -name secp521r1 -noout -genkey -out key.key
+// % openssl req -new -key key.key -out cert.csr
+// % openssl x509 -req -in cert.csr -days 36500 -out cert.crt -signkey key.key
+//
+// Relevant metadata:
+//
+// Certificate:
+// Data:
+// Version: 1 (0x0)
+// Serial Number: 9808857926806240008 (0x882010509b8f7b08)
+// Signature Algorithm: ecdsa-with-SHA1
+// Issuer: C=US, ST=CA, L=San Diego, O=nanomsg, CN=127.0.0.1
+// Validity
+// Not Before: Nov 17 20:08:06 2017 GMT
+// Not After : Oct 24 20:08:06 2117 GMT
+// Subject: C=US, ST=CA, L=San Diego, O=nanomsg, CN=127.0.0.1
+//
+static const char server_cert[] =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIICIjCCAYMCCQDaC9ARg31kIjAKBggqhkjOPQQDAjBUMQswCQYDVQQGEwJVUzEL\n"
+ "MAkGA1UECAwCQ0ExEjAQBgNVBAcMCVNhbiBEaWVnbzEQMA4GA1UECgwHbmFub21z\n"
+ "ZzESMBAGA1UEAwwJMTI3LjAuMC4xMCAXDTE3MTExNzIwMjczMloYDzIxMTcxMDI0\n"
+ "MjAyNzMyWjBUMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCVNh\n"
+ "biBEaWVnbzEQMA4GA1UECgwHbmFub21zZzESMBAGA1UEAwwJMTI3LjAuMC4xMIGb\n"
+ "MBAGByqGSM49AgEGBSuBBAAjA4GGAAQAN7vDK6GEiSguMsOuhfOvGyiVc37Sog0b\n"
+ "UkpaiS6+SagTmXFSN1Rgh9isxKFYJvcCtAko3v0I8rAVQucdhf5B3hEBMQlbBIuM\n"
+ "rMKT6ZQJ+eiwyb4O3Scgd7DoL3tc/kOqijwB/5hJ4sZdquDKP5DDFe5fAf4MNtzY\n"
+ "4C+iApWlKq/LoXkwCgYIKoZIzj0EAwIDgYwAMIGIAkIBOuJAWmNSdd6Ovmr6Ebg3\n"
+ "UF9ZrsNwARd9BfYbBk5OQhUOjCLB6d8aLi49WOm1WoRvOS5PaVvmvSfNhaw8b5nV\n"
+ "hnYCQgC+EmJ6C3bEcZrndhfbqvCaOGkc7/SrKhC6fS7mJW4wL90QUV9WjQ2Ll6X5\n"
+ "PxkSj7s0SvD6T8j7rju5LDgkdZc35A==\n"
+ "-----END CERTIFICATE-----\n";
+
+static const char server_key[] =
+ "-----BEGIN EC PRIVATE KEY-----\n"
+ "MIHcAgEBBEIB20OHMntU2UJW2yuQn2f+bLsuhTT5KRGorcocnqxatWLvxuF1cfUA\n"
+ "TjQxRRS6BIUvFt1fMIklp9qedJF00JHy4qWgBwYFK4EEACOhgYkDgYYABAA3u8Mr\n"
+ "oYSJKC4yw66F868bKJVzftKiDRtSSlqJLr5JqBOZcVI3VGCH2KzEoVgm9wK0CSje\n"
+ "/QjysBVC5x2F/kHeEQExCVsEi4yswpPplAn56LDJvg7dJyB3sOgve1z+Q6qKPAH/\n"
+ "mEnixl2q4Mo/kMMV7l8B/gw23NjgL6IClaUqr8uheQ==\n"
+ "-----END EC PRIVATE KEY-----\n";
+
+static int
+check_props_v4(nng_msg *msg, nng_listener l, nng_dialer d)
+{
+ nng_pipe p;
+ size_t z;
+ p = nng_msg_get_pipe(msg);
+ So(p > 0);
+
+ Convey("Local address property works", {
+ nng_sockaddr la;
+ z = sizeof(nng_sockaddr);
+ So(nng_pipe_getopt(p, NNG_OPT_LOCADDR, &la, &z) == 0);
+ So(z == sizeof(la));
+ So(la.s_un.s_family == NNG_AF_INET);
+ So(la.s_un.s_in.sa_port == htons(trantest_port - 1));
+ So(la.s_un.s_in.sa_port != 0);
+ So(la.s_un.s_in.sa_addr == htonl(0x7f000001));
+ });
+
+ Convey("Remote address property works", {
+ nng_sockaddr ra;
+ z = sizeof(nng_sockaddr);
+ So(nng_pipe_getopt(p, NNG_OPT_REMADDR, &ra, &z) == 0);
+ So(z == sizeof(ra));
+ So(ra.s_un.s_family == NNG_AF_INET);
+ So(ra.s_un.s_in.sa_port != 0);
+ So(ra.s_un.s_in.sa_addr == htonl(0x7f000001));
+ });
+
+ return (0);
+}
+
+static int
+init_tls(trantest *tt)
+{
+ const char *own[3];
+
+ So(nng_setopt(tt->reqsock, NNG_OPT_TLS_CA_CERT, server_cert,
+ sizeof(server_cert)) == 0);
+ own[0] = server_cert;
+ own[1] = server_key;
+ own[2] = NULL;
+ So(nng_setopt(tt->repsock, NNG_OPT_TLS_CERT, server_cert,
+ sizeof(server_cert)) == 0);
+ So(nng_setopt(tt->repsock, NNG_OPT_TLS_PRIVATE_KEY, server_key,
+ sizeof(server_key)) == 0);
+
+ return (0);
+}
+
+TestMain("TLS Transport", {
+
+ static trantest tt;
+
+ tt.init = init_tls;
+ tt.tmpl = "tls://127.0.0.1:%u";
+
+ trantest_test(&tt);
+
+ Convey("We can register the TLS transport",
+ { So(nng_tls_register() == 0); });
+
+ Convey("We cannot connect to wild cards", {
+ nng_socket s;
+ char addr[NNG_MAXADDRLEN];
+
+ So(nng_tls_register() == 0);
+ So(nng_pair_open(&s) == 0);
+ Reset({ nng_close(s); });
+ trantest_next_address(addr, "tls://*:%u");
+ So(nng_dial(s, addr, NULL, 0) == NNG_EADDRINVAL);
+ });
+
+ Convey("We can bind to wild card", {
+ nng_socket s1;
+ nng_socket s2;
+ char addr[NNG_MAXADDRLEN];
+
+ So(nng_tls_register() == 0);
+ So(nng_pair_open(&s1) == 0);
+ So(nng_pair_open(&s2) == 0);
+ Reset({
+ nng_close(s2);
+ nng_close(s1);
+ });
+ trantest_next_address(addr, "tls://*:%u");
+ So(nng_listen(s1, addr, NULL, 0) == 0);
+ // reset port back one
+ trantest_prev_address(addr, "tls://127.0.0.1:%u");
+ So(nng_dial(s2, addr, NULL, 0) == 0);
+ });
+
+ Convey("Malformed TLS addresses do not panic", {
+ nng_socket s1;
+
+ So(nng_tls_register() == 0);
+ So(nng_pair_open(&s1) == 0);
+ Reset({ nng_close(s1); });
+ So(nng_dial(s1, "tls://127.0.0.1", NULL, 0) == NNG_EADDRINVAL);
+ So(nng_dial(s1, "tls://127.0.0.1.32", NULL, 0) ==
+ NNG_EADDRINVAL);
+ So(nng_dial(s1, "tls://127.0.x.1.32", NULL, 0) ==
+ NNG_EADDRINVAL);
+ So(nng_listen(s1, "tls://127.0.0.1", NULL, 0) ==
+ NNG_EADDRINVAL);
+ So(nng_listen(s1, "tls://127.0.0.1.32", NULL, 0) ==
+ NNG_EADDRINVAL);
+ So(nng_listen(s1, "tls://127.0.x.1.32", NULL, 0) ==
+ NNG_EADDRINVAL);
+ });
+
+ nng_fini();
+})
diff --git a/tests/trantest.h b/tests/trantest.h
index d334c257..21a9c893 100644
--- a/tests/trantest.h
+++ b/tests/trantest.h
@@ -19,19 +19,29 @@
// Transport common tests. By making a common test framework for transports,
// we can avoid rewriting the same tests for each new transport. Include this
// file once in your test code. The test framework uses the REQ/REP protocol
-// for comms.
+// for messaging.
+typedef int (*trantest_proptest_t)(nng_msg *, nng_listener, nng_dialer);
-typedef struct {
- char addr[NNG_MAXADDRLEN + 1];
- nng_socket reqsock;
- nng_socket repsock;
- nni_tran * tran;
-} trantest;
+typedef struct trantest trantest;
+
+struct trantest {
+ const char * tmpl;
+ char addr[NNG_MAXADDRLEN + 1];
+ nng_socket reqsock;
+ nng_socket repsock;
+ nni_tran * tran;
+ nng_dialer dialer;
+ nng_listener listener;
+ int (*init)(struct trantest *);
+ void (*fini)(struct trantest *);
+ int (*dialer_init)(struct trantest *);
+ int (*listener_init)(struct trantest *);
+ int (*proptest)(nng_msg *, nng_listener, nng_dialer);
+ void *private; // transport specific private data
+};
unsigned trantest_port = 0;
-typedef int (*trantest_proptest_t)(nng_msg *, nng_listener, nng_dialer);
-
#ifndef NNG_HAVE_ZEROTIER
#define nng_zt_register notransport
#endif
@@ -44,6 +54,9 @@ typedef int (*trantest_proptest_t)(nng_msg *, nng_listener, nng_dialer);
#ifndef NNG_HAVE_TCP
#define nng_tcp_register notransport
#endif
+#ifndef NNG_HAVE_TLS
+#define nng_tls_register notransport
+#endif
int
notransport(void)
@@ -71,6 +84,9 @@ trantest_checktran(const char *url)
#ifndef NNG_HAVE_TCP
CHKTRAN(url, "tcp:");
#endif
+#ifndef NNG_HAVE_TLS
+ CHKTRAN(url, "tls:");
+#endif
(void) url;
}
@@ -122,6 +138,16 @@ trantest_fini(trantest *tt)
nng_close(tt->repsock);
}
+int
+trantest_dial(trantest *tt)
+{
+ So(nng_dialer_create(&tt->dialer, tt->reqsock, tt->addr) == 0);
+ if (tt->dialer_init != NULL) {
+ So(tt->dialer_init(tt) == 0);
+ }
+ return (nng_dialer_start(tt->dialer, 0));
+}
+
void
trantest_scheme(trantest *tt)
{
@@ -150,10 +176,12 @@ trantest_duplicate_listen(trantest *tt)
{
Convey("Duplicate listen rejected", {
nng_listener l;
- So(nng_listen(tt->repsock, tt->addr, &l, 0) == 0);
+ int rv;
+ rv = nng_listen(tt->repsock, tt->addr, &l, 0);
+ So(rv == 0);
So(l != 0);
l = 0;
- So(nng_listen(tt->reqsock, tt->addr, &l, 0) == NNG_EADDRINUSE);
+ So(nng_listen(tt->repsock, tt->addr, &l, 0) == NNG_EADDRINUSE);
So(l == 0);
})
}
@@ -178,7 +206,6 @@ trantest_send_recv(trantest *tt)
{
Convey("Send and recv", {
nng_listener l;
- nng_dialer d;
nng_msg * send;
nng_msg * recv;
size_t len;
@@ -188,8 +215,7 @@ trantest_send_recv(trantest *tt)
So(nng_listen(tt->repsock, tt->addr, &l, 0) == 0);
So(l != 0);
- So(nng_dial(tt->reqsock, tt->addr, &d, 0) == 0);
- So(d != 0);
+ So(trantest_dial(tt) == 0);
nng_msleep(20); // listener may be behind slightly
@@ -238,7 +264,7 @@ trantest_check_properties(trantest *tt, trantest_proptest_t f)
So(nng_dial(tt->reqsock, tt->addr, &d, 0) == 0);
So(d != 0);
- nng_msleep(20); // listener may be behind slightly
+ nng_msleep(10); // listener may be behind slightly
send = NULL;
So(nng_msg_alloc(&send, 0) == 0);
@@ -280,7 +306,7 @@ trantest_send_recv_large(trantest *tt)
So(nng_dial(tt->reqsock, tt->addr, &d, 0) == 0);
So(d != 0);
- nng_msleep(20); // listener may be behind slightly
+ nng_msleep(10); // listener may be behind slightly
send = NULL;
So(nng_msg_alloc(&send, size) == 0);
@@ -315,6 +341,7 @@ trantest_test_all(const char *addr)
{
trantest tt;
+ memset(&tt, 0, sizeof(tt));
Convey("Given transport", {
trantest_init(&tt, addr);
@@ -334,6 +361,7 @@ trantest_test_extended(const char *addr, trantest_proptest_t f)
{
trantest tt;
+ memset(&tt, 0, sizeof(tt));
Convey("Given transport", {
trantest_init(&tt, addr);
@@ -348,3 +376,33 @@ trantest_test_extended(const char *addr, trantest_proptest_t f)
trantest_check_properties(&tt, f);
})
}
+
+void
+trantest_test(trantest *tt)
+{
+ Convey("Given transport", {
+ trantest_init(tt, tt->tmpl);
+ if (tt->init != NULL) {
+ So(tt->init(tt) == 0);
+ }
+
+ Reset({
+ if (tt->fini != NULL) {
+ tt->fini(tt);
+ }
+ trantest_fini(tt);
+ });
+
+ trantest_scheme(tt);
+
+ trantest_conn_refused(tt);
+ trantest_duplicate_listen(tt);
+ trantest_listen_accept(tt);
+
+ trantest_send_recv(tt);
+ trantest_send_recv_large(tt);
+ if (tt->proptest != NULL) {
+ trantest_check_properties(tt, tt->proptest);
+ }
+ })
+}