diff options
Diffstat (limited to 'src/transport/ws')
| -rw-r--r-- | src/transport/ws/websocket.c | 162 | ||||
| -rw-r--r-- | src/transport/ws/websocket.h | 42 |
2 files changed, 175 insertions, 29 deletions
diff --git a/src/transport/ws/websocket.c b/src/transport/ws/websocket.c index 05cb9513..16cdf47b 100644 --- a/src/transport/ws/websocket.c +++ b/src/transport/ws/websocket.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Staysail Systems, Inc. <info@staysail.tech> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 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 @@ -43,7 +43,6 @@ 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 { @@ -222,7 +221,6 @@ ws_pipe_init(ws_pipe **pipep, ws_ep *ep, void *ws) p->mode = ep->mode; p->rcvmax = ep->rcvmax; - // p->addr = ep->addr; p->rproto = ep->rproto; p->lproto = ep->lproto; p->ws = ws; @@ -603,11 +601,6 @@ 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) { - nni_tls_config_fini(ep->tls); - } -#endif NNI_FREE_STRUCT(ep); } @@ -706,18 +699,6 @@ ws_ep_init(void **epp, const char *url, nni_sock *sock, int mode) nni_mtx_init(&ep->mtx); NNI_LIST_INIT(&ep->headers, ws_hdr, node); -#ifdef NNG_TRANSPORT_WSS - if (strncmp(url, "wss://", 4) == 0) { - rv = nni_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); @@ -798,10 +779,29 @@ nng_ws_register(void) #ifdef NNG_TRANSPORT_WSS static int +wss_get_tls(ws_ep *ep, nng_tls_config **tlsp) +{ + switch (ep->mode) { + case NNI_EP_MODE_DIAL: + return (nni_ws_dialer_get_tls(ep->dialer, tlsp)); + case NNI_EP_MODE_LISTEN: + return (nni_ws_listener_get_tls(ep->listener, tlsp)); + } + return (NNG_EINVAL); +} + +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)); + ws_ep * ep = arg; + nng_tls_config *tls; + int rv; + + if (((rv = wss_get_tls(ep, &tls)) != 0) || + ((rv = nni_getopt_ptr(tls, v, szp)) != 0)) { + return (rv); + } + return (0); } static int @@ -828,13 +828,98 @@ wss_ep_setopt_tlsconfig(void *arg, const void *v, size_t sz) } else { rv = nni_ws_dialer_set_tls(ep->dialer, cfg); } - if (rv == 0) { - if (ep->tls != NULL) { - nni_tls_config_fini(ep->tls); + nni_mtx_unlock(&ep->mtx); + return (rv); +} + +static int +wss_ep_setopt_tls_cert_key_file(void *arg, const void *v, size_t sz) +{ + ws_ep * ep = arg; + int rv; + nng_tls_config *tls; + + if (ep == NULL) { + if (nni_strnlen(v, sz) >= sz) { + return (NNG_EINVAL); } - nni_tls_config_hold(cfg); - ep->tls = cfg; + return (0); + } + nni_mtx_lock(&ep->mtx); + if (((rv = wss_get_tls(ep, &tls)) != 0) || + ((rv = nng_tls_config_cert_key_file(tls, v, NULL)) != 0)) { + goto done; } +done: + nni_mtx_unlock(&ep->mtx); + return (rv); +} + +static int +wss_ep_setopt_tls_ca_file(void *arg, const void *v, size_t sz) +{ + ws_ep * ep = arg; + int rv; + nng_tls_config *tls; + + if (ep == NULL) { + if (nni_strnlen(v, sz) >= sz) { + return (NNG_EINVAL); + } + return (0); + } + nni_mtx_lock(&ep->mtx); + if (((rv = wss_get_tls(ep, &tls)) != 0) || + ((rv = nng_tls_config_ca_file(tls, v)) != 0)) { + goto done; + } +done: + nni_mtx_unlock(&ep->mtx); + return (rv); +} + +static int +wss_ep_setopt_tls_auth_mode(void *arg, const void *v, size_t sz) +{ + ws_ep * ep = arg; + int rv; + nng_tls_config *tls; + int mode; + + rv = nni_setopt_int( + &mode, v, sz, NNG_TLS_AUTH_MODE_NONE, NNG_TLS_AUTH_MODE_REQUIRED); + if ((rv != 0) || (ep == NULL)) { + return (rv); + } + nni_mtx_lock(&ep->mtx); + if (((rv = wss_get_tls(ep, &tls)) != 0) || + ((rv = nng_tls_config_auth_mode(tls, mode)) != 0)) { + goto done; + } +done: + nni_mtx_unlock(&ep->mtx); + return (rv); +} + +static int +wss_ep_setopt_tls_server_name(void *arg, const void *v, size_t sz) +{ + ws_ep * ep = arg; + int rv; + nng_tls_config *tls; + + if (ep == NULL) { + if (nni_strnlen(v, sz) >= sz) { + return (NNG_EINVAL); + } + return (0); + } + nni_mtx_lock(&ep->mtx); + if (((rv = wss_get_tls(ep, &tls)) != 0) || + ((rv = nng_tls_config_server_name(tls, v)) != 0)) { + goto done; + } +done: nni_mtx_unlock(&ep->mtx); return (rv); } @@ -860,7 +945,26 @@ static nni_tran_ep_option wss_ep_options[] = { .eo_getopt = wss_ep_getopt_tlsconfig, .eo_setopt = wss_ep_setopt_tlsconfig, }, - + { + .eo_name = NNG_OPT_WSS_TLS_CERT_KEY_FILE, + .eo_getopt = NULL, + .eo_setopt = wss_ep_setopt_tls_cert_key_file, + }, + { + .eo_name = NNG_OPT_WSS_TLS_CA_FILE, + .eo_getopt = NULL, + .eo_setopt = wss_ep_setopt_tls_ca_file, + }, + { + .eo_name = NNG_OPT_WSS_TLS_AUTH_MODE, + .eo_getopt = NULL, + .eo_setopt = wss_ep_setopt_tls_auth_mode, + }, + { + .eo_name = NNG_OPT_WSS_TLS_SERVER_NAME, + .eo_getopt = NULL, + .eo_setopt = wss_ep_setopt_tls_server_name, + }, // terminate list { NULL, NULL, NULL }, }; diff --git a/src/transport/ws/websocket.h b/src/transport/ws/websocket.h index a0d8a6cc..1f261067 100644 --- a/src/transport/ws/websocket.h +++ b/src/transport/ws/websocket.h @@ -35,6 +35,48 @@ NNG_DECL int nng_ws_register(void); // behavior. #define NNG_OPT_WSS_TLS_CONFIG "wss:tls-config" +// NNG_OPT_WSS_TLS_CERT_KEY_FILE names a single file that +// contains a certificate and key identifying ourself. This +// is a write-only value. Listeners can call this multiple +// times for different keys/certs corresponding to different +// algorithms, whereas clients only get one. The file must +// contain both cert and key as PEM blocks, and the key must +// not be encrypted. (If more flexibility is needed, use the +// TLS configuration directly.) Note that TLS configuration +// cannot be changed if the listener, or any other from the same +// server and port, is already started. +#define NNG_OPT_WSS_TLS_CERT_KEY_FILE "wss:tls-cert-key-file" + +// NNG_OPT_WSS_TLS_CA_FILE names a single file that +// contains certificate(s) for a CA, and optinally CRLs. This +// is a write-only value. Listeners can call this multiple +// times for different keys/certs corresponding to different +// algorithms, whereas clients only get one. The file must +// contain certs as PEM blocks, and may contain CRLs as PEM +// as well. (If more flexibility is needed, use the +// TLS configuration directly.) Note that TLS configuration +// cannot be changed if the listener, or any other from the same +// server and port, is already started. +#define NNG_OPT_WSS_TLS_CA_FILE "wss:tls-ca-file" + +// NNG_OPT_WSS_TLS_AUTH_MODE is a write-only integer (int) option +// that specifies whether the peer is verified or not. The option +// can take one of the values of NNG_TLS_AUTH_MODE_NONE, +// NNG_TLS_AUTH_MODE_OPTIONAL, or NNG_TLS_AUTH_MODE_REQUIRED. +// The default is NNG_TLS_AUTH_MODE_NONE for listeners, and +// NNG_TLS_AUTH_MODE_REQUIRED for dialers. +#define NNG_OPT_WSS_TLS_AUTH_MODE "wss:tls-auth-mode" + +// NNG_OPT_WSS_TLS_SERVER_NAME is a write-only string that can be +// set on dialers to check the CN of the server for a match. This +// can also affect SNI (server name indication). +#define NNG_OPT_WSS_TLS_SERVER_NAME "wss:tls-server-name" + +// NNG_OPT_WSS_TLS_VERIFIED returns a single integer, indicating +// whether the peer was verified or not. This is a read-only value +// available only on pipes. +#define NNT_OPT_WSS_TLS_VERIFIED "wss:tls-verified" + // 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 |
