diff options
| author | Garrett D'Amore <garrett@damore.org> | 2017-12-29 14:21:20 -0800 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2017-12-30 19:05:41 -0800 |
| commit | 6a50035b242b972c1d9b659ba63e037a0a8afe71 (patch) | |
| tree | fe2600235a01e72d1e7bd5fad1d5e2ea62aada2e /src/transport | |
| parent | a0364185784895c4bc748a6e6453a132d618c96c (diff) | |
| download | nng-6a50035b242b972c1d9b659ba63e037a0a8afe71.tar.gz nng-6a50035b242b972c1d9b659ba63e037a0a8afe71.tar.bz2 nng-6a50035b242b972c1d9b659ba63e037a0a8afe71.zip | |
fixes #166 Websocket TLS mapping
This introduces the wss:// scheme, which is available and works like
the ws:// scheme if TLS is enabled in the library.
The library modularization is refactored somewhat, to make it easier
to use. There is now a single NNG_ENABLE_TLS that enables TLS support
under the hood.
This also adds a new option for the TLS transport, NNG_OPT_TLS_CONFIG
(and a similar one for WSS, NNG_OPT_TLS_WSS_CONFIG) that offer access
to the underlying TLS configuration object, which now has a public API
to go with it as well.
Note that it is also possible to use pure HTTPS using the *private*
API, which will be exposed in a public form soon.
Diffstat (limited to 'src/transport')
| -rw-r--r-- | src/transport/tls/tls.c | 107 | ||||
| -rw-r--r-- | src/transport/tls/tls.h | 6 | ||||
| -rw-r--r-- | src/transport/ws/websocket.c | 132 | ||||
| -rw-r--r-- | src/transport/ws/websocket.h | 22 | ||||
| -rw-r--r-- | src/transport/zerotier/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/transport/zerotier/zerotier.c | 3 |
6 files changed, 219 insertions, 52 deletions
diff --git a/src/transport/tls/tls.c b/src/transport/tls/tls.c index 9c794e64..f2ca6d35 100644 --- a/src/transport/tls/tls.c +++ b/src/transport/tls/tls.c @@ -14,7 +14,7 @@ #include "core/nng_impl.h" -#include "supplemental/tls.h" +#include "supplemental/tls/tls.h" #include "tls.h" // TLS over TCP transport. Platform specific TCP operations must be @@ -61,7 +61,7 @@ struct nni_tls_ep { nni_aio * aio; nni_aio * user_aio; nni_mtx mtx; - nni_tls_config * cfg; + nng_tls_config * cfg; }; static void nni_tls_pipe_send_cb(void *); @@ -477,7 +477,7 @@ nni_tls_pipe_getopt_locaddr(void *arg, void *v, size_t *szp) nng_sockaddr sa; memset(&sa, 0, sizeof(sa)); - if ((rv = nni_plat_tcp_pipe_sockname(p->tcp, &sa)) == 0) { + if ((rv = nni_tls_sockname(p->tls, &sa)) == 0) { rv = nni_getopt_sockaddr(&sa, v, szp); } return (rv); @@ -491,7 +491,7 @@ nni_tls_pipe_getopt_remaddr(void *arg, void *v, size_t *szp) nng_sockaddr sa; memset(&sa, 0, sizeof(sa)); - if ((rv = nni_plat_tcp_pipe_peername(p->tcp, &sa)) == 0) { + if ((rv = nni_tls_peername(p->tls, &sa)) == 0) { rv = nni_getopt_sockaddr(&sa, v, szp); } return (rv); @@ -589,7 +589,7 @@ nni_tls_ep_fini(void *arg) nni_plat_tcp_ep_fini(ep->tep); } if (ep->cfg) { - nni_tls_config_fini(ep->cfg); + nng_tls_config_fini(ep->cfg); } nni_aio_fini(ep->aio); nni_mtx_fini(&ep->mtx); @@ -599,18 +599,18 @@ nni_tls_ep_fini(void *arg) static int nni_tls_ep_init(void **epp, const char *url, nni_sock *sock, int mode) { - nni_tls_ep * ep; - int rv; - char buf[NNG_MAXADDRLEN + 1]; - char * rhost; - char * rserv; - char * lhost; - char * lserv; - nni_sockaddr rsa, lsa; - nni_aio * aio; - int passive; - int tlsmode; - int authmode; + nni_tls_ep * ep; + int rv; + char buf[NNG_MAXADDRLEN + 1]; + char * rhost; + char * rserv; + char * lhost; + char * lserv; + nni_sockaddr rsa, lsa; + nni_aio * aio; + int passive; + nng_tls_mode tlsmode; + nng_tls_auth_mode authmode; // Make a copy of the url (to allow for destructive operations) if (nni_strlcpy(buf, url, sizeof(buf)) >= sizeof(buf)) { @@ -628,12 +628,12 @@ nni_tls_ep_init(void **epp, const char *url, nni_sock *sock, int mode) } if (mode == NNI_EP_MODE_DIAL) { passive = 0; - tlsmode = NNI_TLS_CONFIG_CLIENT; - authmode = NNI_TLS_CONFIG_AUTH_MODE_REQUIRED; + tlsmode = NNG_TLS_MODE_CLIENT; + authmode = NNG_TLS_AUTH_MODE_REQUIRED; } else { passive = 1; - tlsmode = NNI_TLS_CONFIG_SERVER; - authmode = NNI_TLS_CONFIG_AUTH_MODE_NONE; + tlsmode = NNG_TLS_MODE_SERVER; + authmode = NNG_TLS_AUTH_MODE_NONE; } // XXX: arguably we could defer this part to the point we do a bind @@ -684,15 +684,15 @@ nni_tls_ep_init(void **epp, const char *url, nni_sock *sock, int mode) } if (((rv = nni_plat_tcp_ep_init(&ep->tep, &lsa, &rsa, mode)) != 0) || - ((rv = nni_tls_config_init(&ep->cfg, tlsmode)) != 0) || - ((rv = nni_tls_config_auth_mode(ep->cfg, authmode)) != 0) || + ((rv = nng_tls_config_init(&ep->cfg, tlsmode)) != 0) || + ((rv = nng_tls_config_auth_mode(ep->cfg, authmode)) != 0) || ((rv = nni_aio_init(&ep->aio, nni_tls_ep_cb, ep)) != 0)) { nni_strfree(rhost); nni_tls_ep_fini(ep); return (rv); } - if ((tlsmode == NNI_TLS_CONFIG_CLIENT) && (rhost != NULL)) { - if ((rv = nni_tls_config_server_name(ep->cfg, rhost)) != 0) { + if ((tlsmode == NNG_TLS_MODE_CLIENT) && (rhost != NULL)) { + if ((rv = nng_tls_config_server_name(ep->cfg, rhost)) != 0) { nni_strfree(rhost); nni_tls_ep_fini(ep); return (rv); @@ -868,6 +868,38 @@ nni_tls_ep_getopt_linger(void *arg, void *v, size_t *szp) } static int +tls_setopt_config(void *arg, const void *data, size_t sz) +{ + nni_tls_ep * ep = arg; + nng_tls_config *cfg, *old; + + if (sz != sizeof(cfg)) { + return (NNG_EINVAL); + } + memcpy(&cfg, data, sz); + if (cfg == NULL) { + return (NNG_EINVAL); + } + if (ep == NULL) { + return (0); + } + old = ep->cfg; + nni_tls_config_hold(cfg); + ep->cfg = cfg; + if (old != NULL) { + nng_tls_config_fini(old); + } + return (0); +} + +static int +tls_getopt_config(void *arg, void *v, size_t *szp) +{ + nni_tls_ep *ep = arg; + return (nni_getopt_ptr(ep->cfg, v, szp)); +} + +static int tls_setopt_ca_cert(void *arg, const void *data, size_t sz) { nni_tls_ep *ep = arg; @@ -875,7 +907,7 @@ tls_setopt_ca_cert(void *arg, const void *data, size_t sz) if (ep == NULL) { return (0); } - return (nni_tls_config_ca_cert(ep->cfg, data, sz)); + return (nng_tls_config_ca_cert(ep->cfg, data, sz)); } static int @@ -886,7 +918,7 @@ tls_setopt_cert(void *arg, const void *data, size_t sz) if (ep == NULL) { return (0); } - return (nni_tls_config_cert(ep->cfg, data, sz)); + return (nng_tls_config_cert(ep->cfg, data, sz)); } static int @@ -897,7 +929,7 @@ tls_setopt_private_key(void *arg, const void *data, size_t sz) if (ep == NULL) { return (0); } - return (nni_tls_config_key(ep->cfg, data, sz)); + return (nng_tls_config_key(ep->cfg, data, sz)); } static int @@ -914,13 +946,9 @@ tls_setopt_pass(void *arg, const void *data, size_t sz) if (ep == NULL) { return (0); } - return (nni_tls_config_pass(ep->cfg, data)); + return (nng_tls_config_pass(ep->cfg, data)); } -int nng_tls_auth_mode_none = NNI_TLS_CONFIG_AUTH_MODE_NONE; -int nng_tls_auth_mode_required = NNI_TLS_CONFIG_AUTH_MODE_REQUIRED; -int nng_tls_auth_mode_optional = NNI_TLS_CONFIG_AUTH_MODE_OPTIONAL; - static int tls_getopt_auth_mode(void *arg, void *v, size_t *szp) { @@ -938,9 +966,9 @@ tls_setopt_auth_mode(void *arg, const void *data, size_t sz) rv = nni_setopt_int(&mode, data, sz, -100, 100); if (rv == 0) { switch (mode) { - case NNI_TLS_CONFIG_AUTH_MODE_NONE: - case NNI_TLS_CONFIG_AUTH_MODE_OPTIONAL: - case NNI_TLS_CONFIG_AUTH_MODE_REQUIRED: + case NNG_TLS_AUTH_MODE_NONE: + case NNG_TLS_AUTH_MODE_OPTIONAL: + case NNG_TLS_AUTH_MODE_REQUIRED: break; default: rv = NNG_EINVAL; @@ -952,7 +980,7 @@ tls_setopt_auth_mode(void *arg, const void *data, size_t sz) return (rv); } - if ((rv = nni_tls_config_auth_mode(ep->cfg, mode)) == 0) { + if ((rv = nng_tls_config_auth_mode(ep->cfg, mode)) == 0) { ep->authmode = mode; } return (rv); @@ -998,6 +1026,11 @@ static nni_tran_ep_option nni_tls_ep_options[] = { .eo_setopt = nni_tls_ep_setopt_linger, }, { + .eo_name = NNG_OPT_TLS_CONFIG, + .eo_getopt = tls_getopt_config, + .eo_setopt = tls_setopt_config, + }, + { .eo_name = NNG_OPT_TLS_CA_CERT, .eo_getopt = NULL, .eo_setopt = tls_setopt_ca_cert, diff --git a/src/transport/tls/tls.h b/src/transport/tls/tls.h index 4317ae55..b36ee774 100644 --- a/src/transport/tls/tls.h +++ b/src/transport/tls/tls.h @@ -49,14 +49,12 @@ NNG_DECL int nng_tls_register(void); // and off on servers/listeners, by default. #define NNG_OPT_TLS_AUTH_MODE "tls:auth-mode" -extern int nng_tls_auth_mode_required; -extern int nng_tls_auth_mode_none; -extern int nng_tls_auth_mode_optional; - // NNG_OPT_TLS_AUTH_VERIFIED is a boolean that can be read on pipes, // indicating whether the peer certificate is verified. #define NNG_OPT_TLS_AUTH_VERIFIED "tls:auth-verified" +#define NNG_OPT_TLS_CONFIG "tls:config" + // XXX: TBD: Ciphersuite selection and reporting. Session reuse? #endif // NNG_TRANSPORT_TLS_TLS_H diff --git a/src/transport/ws/websocket.c b/src/transport/ws/websocket.c index 4f948fb7..1162338e 100644 --- a/src/transport/ws/websocket.c +++ b/src/transport/ws/websocket.c @@ -15,6 +15,7 @@ #include "core/nng_impl.h" #include "supplemental/http/http.h" +#include "supplemental/tls/tls.h" #include "supplemental/websocket/websocket.h" #include "websocket.h" @@ -42,6 +43,7 @@ struct ws_ep { nni_ws_listener *listener; nni_ws_dialer * dialer; nni_list headers; // to send, res or req + nng_tls_config * tls; }; struct ws_pipe { @@ -368,9 +370,6 @@ ws_ep_setopt_headers(ws_ep *ep, const void *v, size_t sz) ws_hdr * h; int rv; - if (nni_strnlen(v, sz) >= sz) { - return (NNG_EINVAL); - } if (ep == NULL) { return (0); } @@ -449,7 +448,11 @@ ws_ep_setopt_reqhdrs(void *arg, const void *v, size_t sz) { ws_ep *ep = arg; - if (ep->mode == NNI_EP_MODE_LISTEN) { + if (nni_strnlen(v, sz) >= sz) { + return (NNG_EINVAL); + } + + if ((ep != NULL) && (ep->mode == NNI_EP_MODE_LISTEN)) { return (NNG_EREADONLY); } return (ws_ep_setopt_headers(ep, v, sz)); @@ -460,7 +463,11 @@ ws_ep_setopt_reshdrs(void *arg, const void *v, size_t sz) { ws_ep *ep = arg; - if (ep->mode == NNI_EP_MODE_DIAL) { + if (nni_strnlen(v, sz) >= sz) { + return (NNG_EINVAL); + } + + if ((ep != NULL) && (ep->mode == NNI_EP_MODE_DIAL)) { return (NNG_EREADONLY); } return (ws_ep_setopt_headers(ep, v, sz)); @@ -594,6 +601,11 @@ ws_ep_fini(void *arg) nni_strfree(ep->addr); nni_strfree(ep->protoname); nni_mtx_fini(&ep->mtx); +#ifdef NNG_TRANSPORT_WSS + if (ep->tls) { + nng_tls_config_fini(ep->tls); + } +#endif NNI_FREE_STRUCT(ep); } @@ -689,10 +701,21 @@ ws_ep_init(void **epp, const char *url, nni_sock *sock, int mode) if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { return (NNG_ENOMEM); } - nni_mtx_init(&ep->mtx); NNI_LIST_INIT(&ep->headers, ws_hdr, node); +#ifdef NNG_TRANSPORT_WSS + if (strncmp(url, "wss://", 4) == 0) { + rv = nng_tls_config_init(&ep->tls, + mode == NNI_EP_MODE_DIAL ? NNG_TLS_MODE_CLIENT + : NNG_TLS_MODE_SERVER); + if (rv != 0) { + NNI_FREE_STRUCT(ep); + return (rv); + } + } +#endif + // List of pipes (server only). nni_aio_list_init(&ep->aios); @@ -758,3 +781,100 @@ nng_ws_register(void) { return (nni_tran_register(&ws_tran)); } + +#ifdef NNG_TRANSPORT_WSS + +static int +wss_ep_getopt_tlsconfig(void *arg, void *v, size_t *szp) +{ + ws_ep *ep = arg; + return (nni_getopt_ptr(ep->tls, v, szp)); +} + +static int +wss_ep_setopt_tlsconfig(void *arg, const void *v, size_t sz) +{ + ws_ep * ep = arg; + nng_tls_config *cfg; + int rv; + + if (sz != sizeof(cfg)) { + return (NNG_EINVAL); + } + memcpy(&cfg, v, sz); + if (cfg == NULL) { + // NULL is clearly invalid. + return (NNG_EINVAL); + } + if (ep == NULL) { + return (0); + } + nni_mtx_lock(&ep->mtx); + if (ep->mode == NNI_EP_MODE_LISTEN) { + rv = nni_ws_listener_set_tls(ep->listener, cfg); + } else { + rv = nni_ws_dialer_set_tls(ep->dialer, cfg); + } + if (rv == 0) { + if (ep->tls != NULL) { + nng_tls_config_fini(ep->tls); + } + nni_tls_config_hold(cfg); + ep->tls = cfg; + } + nni_mtx_unlock(&ep->mtx); + return (rv); +} + +static nni_tran_ep_option wss_ep_options[] = { + { + .eo_name = NNG_OPT_RECVMAXSZ, + .eo_getopt = ws_ep_getopt_recvmaxsz, + .eo_setopt = ws_ep_setopt_recvmaxsz, + }, + { + .eo_name = NNG_OPT_WSS_REQUEST_HEADERS, + .eo_getopt = NULL, + .eo_setopt = ws_ep_setopt_reqhdrs, + }, + { + .eo_name = NNG_OPT_WSS_RESPONSE_HEADERS, + .eo_getopt = NULL, + .eo_setopt = ws_ep_setopt_reshdrs, + }, + { + .eo_name = NNG_OPT_WSS_TLS_CONFIG, + .eo_getopt = wss_ep_getopt_tlsconfig, + .eo_setopt = wss_ep_setopt_tlsconfig, + }, + + // terminate list + { NULL, NULL, NULL }, +}; + +static nni_tran_ep wss_ep_ops = { + .ep_init = ws_ep_init, + .ep_fini = ws_ep_fini, + .ep_connect = ws_ep_connect, + .ep_bind = ws_ep_bind, + .ep_accept = ws_ep_accept, + .ep_close = ws_ep_close, + .ep_options = wss_ep_options, +}; + +static nni_tran wss_tran = { + .tran_version = NNI_TRANSPORT_VERSION, + .tran_scheme = "wss", + .tran_ep = &wss_ep_ops, + .tran_pipe = &ws_pipe_ops, + .tran_init = ws_tran_init, + .tran_fini = ws_tran_fini, +}; + +int +nng_wss_register(void) +{ + return (nni_tran_register(&wss_tran)); +} + +#endif // NNG_TRANSPORT_WSS diff --git a/src/transport/ws/websocket.h b/src/transport/ws/websocket.h index 2e86aaf0..a0d8a6cc 100644 --- a/src/transport/ws/websocket.h +++ b/src/transport/ws/websocket.h @@ -15,12 +15,30 @@ NNG_DECL int nng_ws_register(void); -// NNG_OPT_TLS_REQUEST_HEADERS is a string containing the +// NNG_OPT_WS_REQUEST_HEADERS is a string containing the // request headers, formatted as CRLF terminated lines. #define NNG_OPT_WS_REQUEST_HEADERS "ws:request-headers" -// NNG_OPT_TLS_RESPONSE_HEADERS is a string containing the +// NNG_OPT_WS_RESPONSE_HEADERS is a string containing the // response headers, formatted as CRLF terminated lines. #define NNG_OPT_WS_RESPONSE_HEADERS "ws:response-headers" +// NNG_OPT_WSS_TLS_CONFIG is a pointer to a an nng_tls_config +// object. This property is only available for wss:// style +// endpoints. Note that when configuring the object, a hold +// is placed on the TLS configuration. When retrieving the +// object, no hold is placed, and so the caller must take care +// not to use the configuration object after the endpoint it +// is associated with is removed. Furthermore, as this is a +// pointer, applications must take care to pass only valid +// data -- incorrect pointer values will lead to undefined +// behavior. +#define NNG_OPT_WSS_TLS_CONFIG "wss:tls-config" + +// These aliases are for WSS naming consistency. +#define NNG_OPT_WSS_REQUEST_HEADERS NNG_OPT_WS_REQUEST_HEADERS +#define NNG_OPT_WSS_RESPONSE_HEADERS NNG_OPT_WS_RESPONSE_HEADERS + +NNG_DECL int nng_wss_register(void); + #endif // NNG_TRANSPORT_WS_WEBSOCKET_H diff --git a/src/transport/zerotier/CMakeLists.txt b/src/transport/zerotier/CMakeLists.txt index c1bb0c35..a4271eb7 100644 --- a/src/transport/zerotier/CMakeLists.txt +++ b/src/transport/zerotier/CMakeLists.txt @@ -11,6 +11,7 @@ # ZeroTier protocol set (NNG_TRANSPORT_ZEROTIER_SOURCE "" CACHE PATH "Location of ZeroTier source tree.") +mark_as_advanced(NNG_TRANSPORT_ZEROTIER_SOURCE) if (NNG_TRANSPORT_ZEROTIER) diff --git a/src/transport/zerotier/zerotier.c b/src/transport/zerotier/zerotier.c index 3cb2871a..f6594eb3 100644 --- a/src/transport/zerotier/zerotier.c +++ b/src/transport/zerotier/zerotier.c @@ -8,7 +8,6 @@ // found online at https://opensource.org/licenses/MIT. // -#ifdef NNG_HAVE_ZEROTIER #include <ctype.h> #include <stdio.h> #include <stdlib.h> @@ -2804,5 +2803,3 @@ nng_zt_register(void) { return (nni_tran_register(&zt_tran)); } - -#endif |
