diff options
| author | Garrett D'Amore <garrett@damore.org> | 2018-01-09 18:42:28 -0800 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2018-01-09 18:42:28 -0800 |
| commit | 6dddc0bfcb79615b8be470a5e16918360d57cadb (patch) | |
| tree | 9f12e0db8a343d4f803da1b9420a80ee0a9cc0ee | |
| parent | 5db0c399e3a2289e5b6dacdec4035a827eb8a16d (diff) | |
| download | nng-6dddc0bfcb79615b8be470a5e16918360d57cadb.tar.gz nng-6dddc0bfcb79615b8be470a5e16918360d57cadb.tar.bz2 nng-6dddc0bfcb79615b8be470a5e16918360d57cadb.zip | |
fixes #186 Suggested API changes for nng TLS certs
| -rw-r--r-- | docs/libnng.adoc | 10 | ||||
| -rw-r--r-- | docs/nng_tls.adoc | 62 | ||||
| -rw-r--r-- | docs/nng_tls_config_alloc.adoc | 7 | ||||
| -rw-r--r-- | docs/nng_tls_config_ca_chain.adoc (renamed from docs/nng_tls_config_ca_cert.adoc) | 25 | ||||
| -rw-r--r-- | docs/nng_tls_config_key.adoc | 82 | ||||
| -rw-r--r-- | docs/nng_tls_config_own_cert.adoc (renamed from docs/nng_tls_config_cert.adoc) | 42 | ||||
| -rw-r--r-- | docs/nng_tls_config_pass.adoc | 70 | ||||
| -rw-r--r-- | src/nng.h | 28 | ||||
| -rw-r--r-- | src/supplemental/tls/mbedtls/tls.c | 294 | ||||
| -rw-r--r-- | src/transport/tls/tls.c | 113 | ||||
| -rw-r--r-- | src/transport/tls/tls.h | 38 | ||||
| -rw-r--r-- | tests/tls.c | 15 | ||||
| -rw-r--r-- | tests/wss.c | 14 |
13 files changed, 116 insertions, 684 deletions
diff --git a/docs/libnng.adoc b/docs/libnng.adoc index a0d42874..d232dfe3 100644 --- a/docs/libnng.adoc +++ b/docs/libnng.adoc @@ -4,7 +4,7 @@ libnng(3) :manmanual: nng :mansource: nng :icons: font -:copyright: Copyright 2018 Garrett D'Amore <garrett@damore.org> \ +:copyright: 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 \ @@ -163,12 +163,9 @@ The following functions are used to manipulate TLS configuration objects. |=== | <<nng_tls_config_auth_alloc#nng_tls_config_alloc(3)>>|allocate TLS configuration | <<nng_tls_config_auth_mode#nng_tls_config_auth_mode(3)>>|set authentication mode -| <<nng_tls_config_ca_cert#,nng_tls_config_ca_cert(3)>>|set certificate authority chain -| <<nng_tls_config_cert#nng_tls_config_cert(3)>>|set own certificate -| <<nng_tls_config_crl#nng_tls_config_crl(3)>>|set certificate revocation list +| <<nng_tls_config_ca_chain#,nng_tls_config_ca_chain(3)>>|set certificate authority chain +| <<nng_tls_config_own_cert#nng_tls_config_own)cert(3)>>|set own certificate and key | <<nng_tls_config_free#,nng_tls_config_free(3)>>}free TLS configuration -| <<nng_tls_config_key#,nng_tls_config_key(3)>>|set private key -| <<nng_tls_config_pass#nng_tls_config_pass(3)>>|set private key password | <<nng_tls_config_server_name#,nng_tls_config_server_name(3)>>|set remote server name |=== @@ -181,7 +178,6 @@ SEE ALSO COPYRIGHT --------- -Copyright 2018 mailto:garrett@damore.org[Garrett D'Amore] + Copyright 2018 mailto:info@staysail.tech[Staysail Systems, Inc.] + Copyright 2018 mailto:info@capitar.com[Capitar IT Group BV] diff --git a/docs/nng_tls.adoc b/docs/nng_tls.adoc index 7c7be533..404923aa 100644 --- a/docs/nng_tls.adoc +++ b/docs/nng_tls.adoc @@ -167,68 +167,6 @@ care must be taken not to access it after the endpoint is closed.) Note that configuration object is not modifiable once it has been used in a running TLS stream. -`NNG_OPT_TLS_CA_CERT`:: - -This is a write-only binay object containing a certificate -chain, consisting of one or more X.509 certificates encoded in -either PEM or DER format. These certificates are used to -validate the peer. If multiple certificates are presented, -they must be in the same format. - -`NNG_OPT_TLS_CRL`:: - -This is a write-only CRL (revocation list) in X.509 format, -specifying certificates which may not be used. - -`NNG_OPT_TLS_CERT`:: - -This is an X.509 certificate containing the peers -own public credentials. For servers, this option may be supplied -multiple times, in order to specify multiple certificates -in order to offer different algorithms. Clients can only -have a single certificate. - -`NNG_OPT_TLS_PRIVATE_KEY`:: - -This is an encoded private key, corresponding to the most -recently established certificate. - -`NNG_OPT_TLS_PRIVATE_KEY_PASSWORD`:: - -This is a string (NUL byte terminated) used to decrypt the -most recently supplied private key, if the private key -is encrypted. (If the private key is not encrypted, then -this option need not be supplied.) - -`NNG_OPT_TLS_AUTH_MODE`:: - -This is a write only integer, indicating whether the -peer should be authenticated. It can take one of the -following values: -+ -[cols="1,2"] -|=== - -| `nng_tls_auth_mode_none` -| No authentication of the peer is performed. - -| `nng_tls_auth_mode_optional` -| The peer certificate is checked if presented, but is not required to be valid or present. - -| `nng_tls_auth_mode_required` -| The peer certificate must be present and valid. -|=== -+ -The default is `nng_tls_auth_mode_required` for -clients (meaning the server must present a valid -certificate) and `nng_tls_auth_mode_none` for -servers (meaning any client may connect). -+ -TIP: For TLS client authentication, set this to -`nng_auth_mode_required` and set the value -of `NNG_OPT_TLS_CA_CERT` to a certificate corresponding -to your own Certificate Authority. - `NNG_OPT_TLS_AUTH_VERIFIED`:: This is a read-only boolean option available only for diff --git a/docs/nng_tls_config_alloc.adoc b/docs/nng_tls_config_alloc.adoc index 21b4755f..a5823e65 100644 --- a/docs/nng_tls_config_alloc.adoc +++ b/docs/nng_tls_config_alloc.adoc @@ -74,12 +74,9 @@ SEE ALSO <<nng_strerror#,nng_strerror(3)>>, <<nng_tls_config_auth_mode#,nng_tls_config_auth_mode(3)>>, -<<nng_tls_config_ca_cert#,nng_tls_config_ca_cert(3)>>, -<<nng_tls_config_cert#,nng_tls_config_cert(3)>>, -<<nng_tls_config_crl#,nng_tls_config_crl(3)>>, +<<nng_tls_config_ca_chain#,nng_tls_config_ca_chain(3)>>, +<<nng_tls_config_own_cert#,nng_tls_config_own_cert(3)>>, <<nng_tls_config_free#,nng_tls_config_free(3)>>, -<<nng_tls_config_key#,nng_tls_config_key(3)>>, -<<nng_tls_config_pass#,nng_tls_config_pass(3)>>, <<nng_tls_config_server_name#,nng_tls_config_server_name(3)>>, <<nng#,nng(7)>> diff --git a/docs/nng_tls_config_ca_cert.adoc b/docs/nng_tls_config_ca_chain.adoc index 26700139..2888c032 100644 --- a/docs/nng_tls_config_ca_cert.adoc +++ b/docs/nng_tls_config_ca_chain.adoc @@ -1,5 +1,5 @@ -nng_tls_config_ca_cert(3) -========================= +nng_tls_config_ca_chain(3) +========================== :doctype: manpage :manmanual: nng :mansource: nng @@ -15,7 +15,7 @@ nng_tls_config_ca_cert(3) NAME ---- -nng_tls_config_ca_cert - configure certificate authority certificate chain +nng_tls_config_ca_chain - configure certificate authority certificate chain SYNOPSIS -------- @@ -24,13 +24,14 @@ SYNOPSIS ----------- #include <nng/nng.h> -int nng_tls_config_ca_cert(nni_tls_config *cfg, const uint8_t *chain, size_t size) +int nng_tls_config_ca_cert(nni_tls_config *cfg, const char *chain, + const char *crl) ----------- DESCRIPTION ----------- -The `nng_tls_config_ca_cert()` function configures a certificate or +The `nng_tls_config_ca_chain()` function configures a certificate or certificate chain to be used when validating peers using the configuragion 'cfg'. @@ -41,15 +42,13 @@ no effect if the authentication mode is `NNG_TLS_AUTH_MODE_NONE`. TIP: This function may be called multiple times, to add additional chains to a configuration, without affecting those added previously. -The certificates located in 'chain' may be in either -https://tools.ietf.org/html/rfc7468[PEM] or DER format. When the 'chain' is -in PEM format, the certificates will be ASCII encoded, and concatenated -together. In this case the value of 'size' will be length of the -corresponding string (without any terminating NUL byte). - -When using DER encoding, the 'size' will be the total number of bytes, after -encoding. +The certificates located in 'chain' must be a NUL terminated C string in +https://tools.ietf.org/html/rfc7468[PEM] format. Multiple certificates may +appear concatenated together, with the leaf certificate listed first. +together. +The 'crl' may be NULL, or may also be a C string containing a PEM format +certificate revocation list for the associated authority. RETURN VALUES ------------- diff --git a/docs/nng_tls_config_key.adoc b/docs/nng_tls_config_key.adoc deleted file mode 100644 index 69e33fea..00000000 --- a/docs/nng_tls_config_key.adoc +++ /dev/null @@ -1,82 +0,0 @@ -nng_tls_config_key(3) -===================== -:doctype: manpage -:manmanual: nng -:mansource: nng -:manvolnum: 3 -:icons: font -:source-highlighter: pygments -:copyright: 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 \ - file was obtained (LICENSE.txt). A copy of the license may also \ - be found online at https://opensource.org/licenses/MIT. - -NAME ----- -nng_tls_config_key - configure certificate authority certificate chain - -SYNOPSIS --------- - -[source, c] ------------ -#include <nng/nng.h> - -int nng_tls_config_key(nni_tls_config *cfg, const uint8_t *key, size_t size) ------------ - -DESCRIPTION ------------ - -The `nng_tls_config_key()` function configures a private 'key' to be used -along with a certificate established with -<<nng_tls_config_cert#,nng_tls_config_cert(3)>>, for the given configuration -'cfg'. - -This function should be called immediately after `nng_tls_config_cert()`, -with the appropriate private key. - -The 'key' may be in either https://tools.ietf.org/html/rfc7468[PEM] or DER -format. When the 'chain' is -in PEM format, the key will be ASCII encoded. A certificate may be present -as well. The value of 'size' corresponds to the PEM encoding, not including -any terminating NUL byte. - -When using DER encoding, the 'size' will be the total number of bytes, after -encoding. - -The key material may be encrypted with a password, which can be supplied -using the <<nng_tls_config_pass#,nng_tls_config_pass(3)>> function. - -RETURN VALUES -------------- - -This function returns 0 on success, and non-zero otherwise. - -ERRORS ------- - -`NNG_ENOMEM`:: Insufficient memory is available. -`NNG_EBUSY`:: The configuration 'cfg' is already in use, and cannot be modified. -`NNG_EINVAL`:: An invalid 'key' or 'size' was supplied. - -SEE ALSO --------- - -<<nng_strerror#,nng_strerror(3)>>, -<<nng_tls_config_alloc#,nng_tls_config_alloc(3)>>, -<<nng_tls_config_cert#,nng_tls_config_cert(3)>>, -<<nng_tls_config_pass#,nng_tls_config_pass(3)>>, -<<nng#,nng(7)>> - - -COPYRIGHT ---------- - -Copyright 2018 mailto:info@staysail.tech[Staysail Systems, Inc.] + -Copyright 2018 mailto:info@capitar.com[Capitar IT Group BV] - -This document is supplied under the terms of the -https://opensource.org/licenses/MIT[MIT License]. diff --git a/docs/nng_tls_config_cert.adoc b/docs/nng_tls_config_own_cert.adoc index f0ae7351..485e44ca 100644 --- a/docs/nng_tls_config_cert.adoc +++ b/docs/nng_tls_config_own_cert.adoc @@ -1,5 +1,5 @@ -nng_tls_config_cert(3) -====================== +nng_tls_config_own_cert(3) +========================== :doctype: manpage :manmanual: nng :mansource: nng @@ -15,7 +15,7 @@ nng_tls_config_cert(3) NAME ---- -nng_tls_config_cert - configure own certificate +nng_tls_config_own_cert - configure own certificate and key SYNOPSIS -------- @@ -24,36 +24,31 @@ SYNOPSIS ----------- #include <nng/nng.h> -int nng_tls_config_cert(nni_tls_config *cfg, const uint8_t *cert, size_t size) +int nng_tls_config_own_cert(nni_tls_config *cfg, const char *cert, + const char *key, const char *pass); ----------- DESCRIPTION ----------- -The `nng_tls_config_cert()` function configures a certificate identifying -the local side of a TLS connection used with 'cfg'. The certificate may be -a chain, with the bottom-most signer first and the root at the end. The +The `nng_tls_config_own_cert()` function configures a certificate 'cert' +identifying the local side of a TLS connection used with 'cfg', along with an +associated private or secret key 'key'. The certificate may be +a chain, with the leaf signer first and the root at the end. The self-signed certificate at the end can be omitted. (The client should already have it, and will have to in order to validate this certificate anyway). -NOTE: The certificate supplied always contains public keying material. In -order to actually use this, a private key will have to be supplied as well, -using the <<nng_tls_config_key#,nnt_tls_config_key(3)>> function. +The 'key' may be encrypted with a password, in which can be supplied in +'pass'. The value NULL should be supplied for 'pass' if the key is not +encrypted. -TIP: This function may be called multiple times, to add additional chains -to a configuration, without affecting those added previously. +On servers, it is possible to call this function multiple times for the +same configuration. This can be useful for specifying different parameters +to be used for different cryptographic algorithms. -The certificate located in 'cert' may be in either -https://tools.ietf.org/html/rfc7468[PEM] or DER format. - -When the 'cert' is -in PEM format, the certificate will be ASCII encoded. Additionally a private -key may or may not be present as additional concatenated PEM data. The -value of 'size' is the length of the concatenated strings, without any -terminating NUL byte. - -When using DER encoding, the 'size' will be the total number of bytes, after -encoding. +The certificate located in 'cert' and 'key' must be NUL terminated C +strings containing +https://tools.ietf.org/html/rfc7468[PEM] formatted material. RETURN VALUES ------------- @@ -72,7 +67,6 @@ SEE ALSO <<nng_strerror#,nng_strerror(3)>>, <<nng_tls_config_alloc#,nng_tls_config_alloc(3)>>, -<<nng_tls_config_key#,nng_tls_config_key(3)>>, <<nng#,nng(7)>> diff --git a/docs/nng_tls_config_pass.adoc b/docs/nng_tls_config_pass.adoc deleted file mode 100644 index ca6a17e2..00000000 --- a/docs/nng_tls_config_pass.adoc +++ /dev/null @@ -1,70 +0,0 @@ -nng_tls_config_pass(3) -====================== -:doctype: manpage -:manmanual: nng -:mansource: nng -:manvolnum: 3 -:icons: font -:source-highlighter: pygments -:copyright: 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 \ - file was obtained (LICENSE.txt). A copy of the license may also \ - be found online at https://opensource.org/licenses/MIT. - -NAME ----- -nng_tls_config_pass - configure private key password - -SYNOPSIS --------- - -[source, c] ------------ -#include <nng/nng.h> - -int nng_tls_config_pass(nni_tls_config *cfg, const char *password) ------------ - -DESCRIPTION ------------ - -The `nng_tls_config_pass()` function configures 'password' used to decrypt -a private key previously configured on the configuration 'cfg' with -<<nng_tls_config_key#,nng_tls_config_key(3)>>. - -The 'password' is an ASCIIZ string. - -This function's affect is limited to decryption only the most recent -private key that was configured. - -RETURN VALUES -------------- - -This function returns 0 on success, and non-zero otherwise. - -ERRORS ------- - -`NNG_ENOMEM`:: Insufficient memory is available. -`NNG_EBUSY`:: The configuration 'cfg' is already in use, and cannot be modified. -`NNG_EINVAL`:: No private key was configured. - -SEE ALSO --------- - -<<nng_strerror#,nng_strerror(3)>>, -<<nng_tls_config_alloc#,nng_tls_config_alloc(3)>>, -<<nng_tls_config_key#,nng_tls_config_key(3)>>, -<<nng#,nng(7)>> - - -COPYRIGHT ---------- - -Copyright 2018 mailto:info@staysail.tech[Staysail Systems, Inc.] + -Copyright 2018 mailto:info@capitar.com[Capitar IT Group BV] - -This document is supplied under the terms of the -https://opensource.org/licenses/MIT[MIT License]. @@ -617,19 +617,21 @@ NNG_DECL int nng_tls_config_server_name(nng_tls_config *, const char *); // nng_tls_config_ca_cert configures one or more CAs used for validation // of peer certificates. Multiple CAs (and their chains) may be configured // by either calling this multiple times, or by specifying a list of -// certificates as concatenated data. The certs may be in PEM or DER -// format. -NNG_DECL int nng_tls_config_ca_cert(nng_tls_config *, const uint8_t *, size_t); - -// nng_tls_config_crl loads a certificate revocation list. Again, these -// are in X.509 format (either PEM or DER). -NNG_DECL int nng_tls_config_crl(nng_tls_config *, const uint8_t *, size_t); - -// nng_tls_config_cert is used to load our own certificate. For servers, -// this may be called more than once to configure multiple different keys, -// for example with different algorithms depending on what the peer supports. -// On the client, only a single option is available. -NNG_DECL int nng_tls_config_cert(nng_tls_config *, const uint8_t *, size_t); +// certificates as concatenated data. The final argument is an optional CRL +// (revokation list) for the CA, also in PEM. Both PEM strings are ASCIIZ +// format (except that the CRL may be NULL). +NNG_DECL int nng_tls_config_ca_chain( + nng_tls_config *, const char *, const char *); + +// nng_tls_config_own_cert is used to load our own certificate and public +// key. For servers, this may be called more than once to configure multiple +// different keys, for example with different algorithms depending on what +// the peer supports. On the client, only a single option is available. +// The first two arguments are the cert (or validation chain) and the +// key as PEM format ASCIIZ strings. The final argument is an optional +// password and may be NULL. +NNG_DECL int nng_tls_config_own_cert( + nng_tls_config *, const char *, const char *, const char *); // nng_tls_config_key is used to pass our own private key. NNG_DECL int nng_tls_config_key(nng_tls_config *, const uint8_t *, size_t); diff --git a/src/supplemental/tls/mbedtls/tls.c b/src/supplemental/tls/mbedtls/tls.c index 742265f1..c37d3d13 100644 --- a/src/supplemental/tls/mbedtls/tls.c +++ b/src/supplemental/tls/mbedtls/tls.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 @@ -52,13 +52,8 @@ #endif typedef struct nni_tls_certkey { - char * pass; - uint8_t * crt; - uint8_t * key; - size_t crtlen; - size_t keylen; - mbedtls_x509_crt mcrt; - mbedtls_pk_context mpk; + mbedtls_x509_crt crt; + mbedtls_pk_context key; nni_list_node node; } nni_tls_certkey; @@ -180,17 +175,8 @@ nni_tls_config_fini(nng_tls_config *cfg) } while ((ck = nni_list_first(&cfg->certkeys))) { nni_list_remove(&cfg->certkeys, ck); - if (ck->pass) { - nni_strfree(ck->pass); - } - if (ck->crt) { - nni_free(ck->crt, ck->crtlen); - } - if (ck->key) { - nni_free(ck->key, ck->keylen); - } - mbedtls_x509_crt_free(&ck->mcrt); - mbedtls_pk_free(&ck->mpk); + mbedtls_x509_crt_free(&ck->crt); + mbedtls_pk_free(&ck->key); NNI_FREE_STRUCT(ck); } @@ -333,44 +319,7 @@ nni_tls_init(nni_tls **tpp, nng_tls_config *cfg, nni_plat_tcp_pipe *tcp) nni_mtx_lock(&cfg->lk); // No more changes allowed to config. - if (cfg->active == false) { - nni_tls_certkey *ck; - - rv = 0; - - if (cfg->have_ca_certs || cfg->have_crl) { - mbedtls_ssl_conf_ca_chain( - &cfg->cfg_ctx, &cfg->ca_certs, &cfg->crl); - } - NNI_LIST_FOREACH (&cfg->certkeys, ck) { - if (rv != 0) { - break; - } - if (rv == 0) { - rv = mbedtls_x509_crt_parse( - &ck->mcrt, ck->crt, ck->crtlen); - } - if (rv == 0) { - rv = mbedtls_pk_parse_key(&ck->mpk, ck->key, - ck->keylen, (uint8_t *) ck->pass, - ck->pass != NULL ? strlen(ck->pass) : 0); - } - if (rv == 0) { - rv = mbedtls_ssl_conf_own_cert( - &cfg->cfg_ctx, &ck->mcrt, &ck->mpk); - } - - if (rv != 0) { - break; - } - } - if (rv != 0) { - nni_mtx_unlock(&cfg->lk); - nni_tls_fini(tp); - return (nni_tls_mkerr(rv)); - } - cfg->active = true; - } + cfg->active = true; cfg->refcnt++; tp->cfg = cfg; nni_mtx_unlock(&cfg->lk); @@ -841,228 +790,93 @@ nng_tls_config_auth_mode(nng_tls_config *cfg, nng_tls_auth_mode mode) return (0); } -#define PEMSTART "-----BEGIN " - -// nni_tls_copy_key_cert_material copies either PEM or DER encoded -// key material. It allocates an extra byte for a NUL terminator -// required by mbed TLS if the data is PEM and missing the terminator. -// It is required that the key material passed in begins with the -// PEM delimiter if it is actually PEM. -static int -nni_tls_copy_key_cert_material( - uint8_t **dstp, size_t *szp, const uint8_t *src, size_t sz) -{ - bool addz = false; - uint8_t *dst; - - if ((sz > strlen(PEMSTART)) && - (strncmp((const char *) src, PEMSTART, strlen(PEMSTART)) == 0) && - (src[sz - 1] != '\0')) { - addz = true; - } - - if (addz) { - if ((dst = nni_alloc(sz + 1)) != NULL) { - memcpy(dst, src, sz); - dst[sz] = '\0'; - sz++; - } - } else { - if ((dst = nni_alloc(sz)) != NULL) { - memcpy(dst, src, sz); - } - } - if (dst == NULL) { - return (NNG_ENOMEM); - } - *dstp = dst; - *szp = sz; - return (0); -} - int -nng_tls_config_cert(nng_tls_config *cfg, const uint8_t *key, size_t sz) +nng_tls_config_ca_chain( + nng_tls_config *cfg, const char *certs, const char *crl) { - int rv = 0; - nni_tls_certkey *ck; - bool cknew; - - if (sz < 1) { - return (NNG_EINVAL); - } + size_t len; + const uint8_t *pem; + int rv; + // Certs and CRL are in PEM data, with terminating NUL byte. nni_mtx_lock(&cfg->lk); if (cfg->active) { rv = NNG_ESTATE; goto err; } - cknew = false; - if (((ck = nni_list_last(&cfg->certkeys)) == NULL) || - (ck->crt != NULL)) { - if ((ck = NNI_ALLOC_STRUCT(ck)) == NULL) { - rv = NNG_ENOMEM; - goto err; - } - mbedtls_pk_init(&ck->mpk); - mbedtls_x509_crt_init(&ck->mcrt); - cknew = true; - } - - rv = nni_tls_copy_key_cert_material(&ck->crt, &ck->crtlen, key, sz); - if (rv != 0) { - goto err; - } - if (cknew) { - nni_list_append(&cfg->certkeys, ck); - } -err: - nni_mtx_unlock(&cfg->lk); - - return (rv); -} - -int -nng_tls_config_key(nng_tls_config *cfg, const uint8_t *key, size_t sz) -{ - int rv = 0; - nni_tls_certkey *ck; - bool cknew; - - if (sz < 1) { - return (NNG_EINVAL); - } - - nni_mtx_lock(&cfg->lk); - if (cfg->active) { - rv = NNG_ESTATE; + pem = (const uint8_t *) certs; + len = strlen(certs) + 1; + if ((rv = mbedtls_x509_crt_parse(&cfg->ca_certs, pem, len)) != 0) { + rv = nni_tls_mkerr(rv); goto err; } - cknew = false; - if (((ck = nni_list_last(&cfg->certkeys)) == NULL) || - (ck->key != NULL)) { - if ((ck = NNI_ALLOC_STRUCT(ck)) == NULL) { - rv = NNG_ENOMEM; + if (crl != NULL) { + pem = (const uint8_t *) crl; + len = strlen(crl) + 1; + if ((rv = mbedtls_x509_crl_parse(&cfg->crl, pem, len)) != 0) { + rv = nni_tls_mkerr(rv); goto err; } - cknew = true; - } - - rv = nni_tls_copy_key_cert_material(&ck->key, &ck->keylen, key, sz); - if (rv != 0) { - goto err; - } - if (cknew) { - nni_list_append(&cfg->certkeys, ck); + cfg->have_crl = true; } err: nni_mtx_unlock(&cfg->lk); - return (rv); } int -nng_tls_config_pass(nng_tls_config *cfg, const char *pass) +nng_tls_config_own_cert( + nng_tls_config *cfg, const char *cert, const char *key, const char *pass) { - int rv = 0; + size_t len; + const uint8_t * pem; nni_tls_certkey *ck; - bool cknew; + int rv; - if (pass == NULL) { - return (NNG_EINVAL); + if ((ck = NNI_ALLOC_STRUCT(ck)) == NULL) { + return (NNG_ENOMEM); } + mbedtls_x509_crt_init(&ck->crt); + mbedtls_pk_init(&ck->key); - nni_mtx_lock(&cfg->lk); - if (cfg->active) { - rv = NNG_ESTATE; + pem = (const uint8_t *) cert; + len = strlen(cert) + 1; + if ((rv = mbedtls_x509_crt_parse(&ck->crt, pem, len)) != 0) { + rv = nni_tls_mkerr(rv); goto err; } - cknew = false; - if (((ck = nni_list_last(&cfg->certkeys)) == NULL) || - (ck->pass != NULL)) { - if ((ck = NNI_ALLOC_STRUCT(ck)) == NULL) { - rv = NNG_ENOMEM; - goto err; - } - cknew = true; - } - if ((ck->pass = nni_strdup(pass)) != NULL) { - rv = NNG_ENOMEM; + pem = (const uint8_t *) key; + len = strlen(key) + 1; + rv = mbedtls_pk_parse_key(&ck->key, pem, len, (const uint8_t *) pass, + pass != NULL ? strlen(pass) : 0); + if (rv != 0) { + rv = nni_tls_mkerr(rv); goto err; } - rv = 0; - if (cknew) { - nni_list_append(&cfg->certkeys, ck); - } -err: - nni_mtx_unlock(&cfg->lk); - - return (rv); -} - -int -nng_tls_config_ca_cert(nng_tls_config *cfg, const uint8_t *data, size_t sz) -{ - uint8_t *tmp; - size_t len = sz; - int rv = 0; - - if (sz < 1) { - return (NNG_EINVAL); - } - - if ((rv = nni_tls_copy_key_cert_material(&tmp, &len, data, sz)) != 0) { - return (NNG_ENOMEM); - } nni_mtx_lock(&cfg->lk); if (cfg->active) { + nni_mtx_unlock(&cfg->lk); rv = NNG_ESTATE; goto err; } - if ((rv = mbedtls_x509_crt_parse(&cfg->ca_certs, tmp, len)) != 0) { - rv = nni_tls_mkerr(rv); - } else { - cfg->have_ca_certs = true; - } -err: - nni_mtx_unlock(&cfg->lk); - nni_free(tmp, len); + rv = mbedtls_ssl_conf_own_cert(&cfg->cfg_ctx, &ck->crt, &ck->key); if (rv != 0) { - nni_panic("panic:"); - } - return (rv); -} - -int -nng_tls_config_crl(nng_tls_config *cfg, const uint8_t *data, size_t sz) -{ - int rv; - uint8_t *tmp; - size_t len; - - if (sz < 1) { - return (NNG_EINVAL); - } - - if ((rv = nni_tls_copy_key_cert_material(&tmp, &len, data, sz)) != 0) { - return (NNG_ENOMEM); - } - - nni_mtx_lock(&cfg->lk); - if (cfg->active) { - rv = NNG_ESTATE; + nni_mtx_unlock(&cfg->lk); + rv = nni_tls_mkerr(rv); goto err; } - if ((rv = mbedtls_x509_crl_parse(&cfg->crl, tmp, len)) != 0) { - rv = nni_tls_mkerr(rv); - } else { - cfg->have_crl = true; - } -err: + // Save this structure so we can free it with the context. + nni_list_append(&cfg->certkeys, ck); nni_mtx_unlock(&cfg->lk); - nni_free(tmp, len); + return (0); + +err: + mbedtls_x509_crt_free(&ck->crt); + mbedtls_pk_free(&ck->key); + NNI_FREE_STRUCT(ck); return (rv); } diff --git a/src/transport/tls/tls.c b/src/transport/tls/tls.c index 31426a78..408ff50c 100644 --- a/src/transport/tls/tls.c +++ b/src/transport/tls/tls.c @@ -843,93 +843,6 @@ tls_getopt_config(void *arg, void *v, size_t *szp) } static int -tls_setopt_ca_cert(void *arg, const void *data, size_t sz) -{ - nni_tls_ep *ep = arg; - - if (ep == NULL) { - return (0); - } - return (nng_tls_config_ca_cert(ep->cfg, data, sz)); -} - -static int -tls_setopt_cert(void *arg, const void *data, size_t sz) -{ - nni_tls_ep *ep = arg; - - if (ep == NULL) { - return (0); - } - return (nng_tls_config_cert(ep->cfg, data, sz)); -} - -static int -tls_setopt_private_key(void *arg, const void *data, size_t sz) -{ - nni_tls_ep *ep = arg; - - if (ep == NULL) { - return (0); - } - return (nng_tls_config_key(ep->cfg, data, sz)); -} - -static int -tls_setopt_pass(void *arg, const void *data, size_t sz) -{ - nni_tls_ep *ep = arg; - size_t len; - - len = nni_strnlen(data, sz); - if (len >= sz) { - return (NNG_EINVAL); - } - - if (ep == NULL) { - return (0); - } - return (nng_tls_config_pass(ep->cfg, data)); -} - -static int -tls_getopt_auth_mode(void *arg, void *v, size_t *szp) -{ - nni_tls_ep *ep = arg; - return (nni_getopt_int(ep->authmode, v, szp)); -} - -static int -tls_setopt_auth_mode(void *arg, const void *data, size_t sz) -{ - nni_tls_ep *ep = arg; - int mode; - int rv; - - rv = nni_setopt_int(&mode, data, sz, -100, 100); - if (rv == 0) { - switch (mode) { - case NNG_TLS_AUTH_MODE_NONE: - case NNG_TLS_AUTH_MODE_OPTIONAL: - case NNG_TLS_AUTH_MODE_REQUIRED: - break; - default: - rv = NNG_EINVAL; - break; - } - } - - if ((ep == NULL) || (rv != 0)) { - return (rv); - } - - if ((rv = nng_tls_config_auth_mode(ep->cfg, mode)) == 0) { - ep->authmode = mode; - } - return (rv); -} - -static int tls_getopt_verified(void *arg, void *v, size_t *szp) { nni_tls_pipe *p = arg; @@ -973,32 +886,6 @@ static nni_tran_ep_option nni_tls_ep_options[] = { .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, - }, - { - .eo_name = NNG_OPT_TLS_CERT, - .eo_getopt = NULL, - .eo_setopt = tls_setopt_cert, - }, - { - .eo_name = NNG_OPT_TLS_PRIVATE_KEY, - .eo_getopt = NULL, - .eo_setopt = tls_setopt_private_key, - }, - { - .eo_name = NNG_OPT_TLS_PRIVATE_KEY_PASSWORD, - .eo_getopt = NULL, - .eo_setopt = tls_setopt_pass, - }, - { - .eo_name = NNG_OPT_TLS_AUTH_MODE, - .eo_getopt = tls_getopt_auth_mode, - .eo_setopt = tls_setopt_auth_mode, - }, - // terminate list { NULL, NULL, NULL }, }; diff --git a/src/transport/tls/tls.h b/src/transport/tls/tls.h index b36ee774..25edfa3a 100644 --- a/src/transport/tls/tls.h +++ b/src/transport/tls/tls.h @@ -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 @@ -19,42 +19,12 @@ NNG_DECL int nng_tls_register(void); // started. Once started, it is no longer possible to alter the TLS // configuration. -// NNG_OPT_TLS_CA_CERT is a string with one or more X.509 certificates, -// representing the entire CA chain. The content may be either PEM or DER -// encoded. -#define NNG_OPT_TLS_CA_CERT "tls:ca-cert" - -// NNG_OPT_TLS_CRL is a PEM encoded CRL (revocation list). Multiple lists -// may be loaded by using this option multiple times. -#define NNG_OPT_TLS_CRL "tls:crl" - -// NNG_OPT_TLS_CERT is used to specify our own certificate. At present -// only one certificate may be supplied. (In the future it may be -// possible to call this multiple times, for servers that select different -// certificates depending upon client capabilities.) -#define NNG_OPT_TLS_CERT "tls:cert" - -// NNG_OPT_TLS_PRIVATE_KEY is used to specify the private key used -// with the given certificate. This should be called after setting -// the certificate. The private key may be in PEM or DER format. -// If in PEM encoded, a terminating ZERO byte should be included. -#define NNG_OPT_TLS_PRIVATE_KEY "tls:private-key" - -// NNG_OPT_TLS_PRIVATE_KEY_PASSWORD is used to specify a password -// used for the private key. The value is an ASCIIZ string. -#define NNG_OPT_TLS_PRIVATE_KEY_PASSWORD "tls:private-key-password" - -// NNG_OPT_TLS_AUTH_MODE is an integer indicating whether our -// peer should be verified or not. It is required on clients/dialers, -// and off on servers/listeners, by default. -#define NNG_OPT_TLS_AUTH_MODE "tls:auth-mode" - // 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" +// NNG_OPT_TLS_CONFIG is used to access the underlying configuration +// (an nng_tls_config *). #define NNG_OPT_TLS_CONFIG "tls:config" -// XXX: TBD: Ciphersuite selection and reporting. Session reuse? - #endif // NNG_TRANSPORT_TLS_TLS_H diff --git a/tests/tls.c b/tests/tls.c index 4ce70a28..5f4f5523 100644 --- a/tests/tls.c +++ b/tests/tls.c @@ -46,7 +46,7 @@ // 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[] = +static const char cert[] = "-----BEGIN CERTIFICATE-----\n" "MIICIjCCAYMCCQDaC9ARg31kIjAKBggqhkjOPQQDAjBUMQswCQYDVQQGEwJVUzEL\n" "MAkGA1UECAwCQ0ExEjAQBgNVBAcMCVNhbiBEaWVnbzEQMA4GA1UECgwHbmFub21z\n" @@ -62,7 +62,7 @@ static const char server_cert[] = "PxkSj7s0SvD6T8j7rju5LDgkdZc35A==\n" "-----END CERTIFICATE-----\n"; -static const char server_key[] = +static const char key[] = "-----BEGIN EC PRIVATE KEY-----\n" "MIHcAgEBBEIB20OHMntU2UJW2yuQn2f+bLsuhTT5KRGorcocnqxatWLvxuF1cfUA\n" "TjQxRRS6BIUvFt1fMIklp9qedJF00JHy4qWgBwYFK4EEACOhgYkDgYYABAA3u8Mr\n" @@ -108,8 +108,7 @@ init_dialer_tls(trantest *tt, nng_dialer d) if ((rv = nng_tls_config_alloc(&cfg, NNG_TLS_MODE_CLIENT)) != 0) { return (rv); } - if ((rv = nng_tls_config_ca_cert( - cfg, (void *) server_cert, sizeof(server_cert))) != 0) { + if ((rv = nng_tls_config_ca_chain(cfg, cert, NULL)) != 0) { goto out; } if ((rv = nng_tls_config_server_name(cfg, "127.0.0.1")) != 0) { @@ -132,15 +131,9 @@ init_listener_tls(trantest *tt, nng_listener l) if ((rv = nng_tls_config_alloc(&cfg, NNG_TLS_MODE_SERVER)) != 0) { return (rv); } - if ((rv = nng_tls_config_cert( - cfg, (void *) server_cert, sizeof(server_cert))) != 0) { + if ((rv = nng_tls_config_own_cert(cfg, cert, key, NULL)) != 0) { goto out; } - if ((rv = nng_tls_config_key( - cfg, (void *) server_key, sizeof(server_key))) != 0) { - goto out; - } - if ((rv = nng_listener_setopt_ptr(l, NNG_OPT_TLS_CONFIG, cfg)) != 0) { goto out; } diff --git a/tests/wss.c b/tests/wss.c index 5394ad59..00d37621 100644 --- a/tests/wss.c +++ b/tests/wss.c @@ -44,7 +44,7 @@ // 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[] = +static const char cert[] = "-----BEGIN CERTIFICATE-----\n" "MIICIjCCAYMCCQDaC9ARg31kIjAKBggqhkjOPQQDAjBUMQswCQYDVQQGEwJVUzEL\n" "MAkGA1UECAwCQ0ExEjAQBgNVBAcMCVNhbiBEaWVnbzEQMA4GA1UECgwHbmFub21z\n" @@ -60,7 +60,7 @@ static const char server_cert[] = "PxkSj7s0SvD6T8j7rju5LDgkdZc35A==\n" "-----END CERTIFICATE-----\n"; -static const char server_key[] = +static const char key[] = "-----BEGIN EC PRIVATE KEY-----\n" "MIHcAgEBBEIB20OHMntU2UJW2yuQn2f+bLsuhTT5KRGorcocnqxatWLvxuF1cfUA\n" "TjQxRRS6BIUvFt1fMIklp9qedJF00JHy4qWgBwYFK4EEACOhgYkDgYYABAA3u8Mr\n" @@ -133,8 +133,7 @@ init_dialer_wss(trantest *tt, nng_dialer d) if ((rv = nng_tls_config_alloc(&cfg, NNG_TLS_MODE_CLIENT)) != 0) { return (rv); } - if ((rv = nng_tls_config_ca_cert( - cfg, (void *) server_cert, sizeof(server_cert))) != 0) { + if ((rv = nng_tls_config_ca_chain(cfg, cert, NULL)) != 0) { goto out; } if ((rv = nng_tls_config_server_name(cfg, "127.0.0.1")) != 0) { @@ -157,12 +156,7 @@ init_listener_wss(trantest *tt, nng_listener l) if ((rv = nng_tls_config_alloc(&cfg, NNG_TLS_MODE_SERVER)) != 0) { return (rv); } - if ((rv = nng_tls_config_cert( - cfg, (void *) server_cert, sizeof(server_cert))) != 0) { - goto out; - } - if ((rv = nng_tls_config_key( - cfg, (void *) server_key, sizeof(server_key))) != 0) { + if ((rv = nng_tls_config_own_cert(cfg, cert, key, NULL)) != 0) { goto out; } |
