aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2018-01-09 18:42:28 -0800
committerGarrett D'Amore <garrett@damore.org>2018-01-09 18:42:28 -0800
commit6dddc0bfcb79615b8be470a5e16918360d57cadb (patch)
tree9f12e0db8a343d4f803da1b9420a80ee0a9cc0ee
parent5db0c399e3a2289e5b6dacdec4035a827eb8a16d (diff)
downloadnng-6dddc0bfcb79615b8be470a5e16918360d57cadb.tar.gz
nng-6dddc0bfcb79615b8be470a5e16918360d57cadb.tar.bz2
nng-6dddc0bfcb79615b8be470a5e16918360d57cadb.zip
fixes #186 Suggested API changes for nng TLS certs
-rw-r--r--docs/libnng.adoc10
-rw-r--r--docs/nng_tls.adoc62
-rw-r--r--docs/nng_tls_config_alloc.adoc7
-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.adoc82
-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.adoc70
-rw-r--r--src/nng.h28
-rw-r--r--src/supplemental/tls/mbedtls/tls.c294
-rw-r--r--src/transport/tls/tls.c113
-rw-r--r--src/transport/tls/tls.h38
-rw-r--r--tests/tls.c15
-rw-r--r--tests/wss.c14
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].
diff --git a/src/nng.h b/src/nng.h
index 05e99771..5cb5f5ec 100644
--- a/src/nng.h
+++ b/src/nng.h
@@ -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;
}