diff options
Diffstat (limited to 'src/supplemental/tls/mbedtls/mbedtls.c')
| -rw-r--r-- | src/supplemental/tls/mbedtls/mbedtls.c | 873 |
1 files changed, 873 insertions, 0 deletions
diff --git a/src/supplemental/tls/mbedtls/mbedtls.c b/src/supplemental/tls/mbedtls/mbedtls.c new file mode 100644 index 00000000..8250740f --- /dev/null +++ b/src/supplemental/tls/mbedtls/mbedtls.c @@ -0,0 +1,873 @@ +// +// Copyright 2025 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> +// Copyright 2019 Devolutions <info@devolutions.net> +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "mbedtls/version.h" // Must be first in order to pick up version + +#include "mbedtls/error.h" +#ifdef MBEDTLS_PSA_CRYPTO_C +#include "psa/crypto.h" +#endif + +#include "nng/nng.h" + +// We use a common cookie for our application. +#include "mbedtls/ssl_cookie.h" + +#include "../tls_engine.h" + +// mbedTLS renamed this header for 2.4.0. +#if MBEDTLS_VERSION_MAJOR > 2 || MBEDTLS_VERSION_MINOR >= 4 +#include "mbedtls/net_sockets.h" +#else +#include "mbedtls/net.h" +#endif + +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" + +#include "core/nng_impl.h" + +// pair holds a private key and the associated certificate. +typedef struct { + mbedtls_x509_crt crt; + mbedtls_pk_context key; + nni_list_node node; +} pair; + +// psk holds an identity and preshared key +typedef struct { + // NB: Technically RFC 4279 requires this be UTF-8 string, although + // others suggest making it opaque bytes. We treat it as a C string, + // so we cannot support embedded zero bytes. + char *identity; + uint8_t *key; + size_t keylen; + nni_list_node node; +} psk; + +static void +psk_free(psk *p) +{ + if (p != NULL) { + NNI_ASSERT(!nni_list_node_active(&p->node)); + if (p->identity != NULL) { + nni_strfree(p->identity); + p->identity = NULL; + } + if (p->key != NULL && p->keylen != 0) { + nni_free(p->key, p->keylen); + p->key = NULL; + p->keylen = 0; + } + NNI_FREE_STRUCT(p); + } +} + +#ifdef NNG_TLS_USE_CTR_DRBG +// Use a global RNG if we're going to override the builtin. +static mbedtls_ctr_drbg_context rng_ctx; +static nni_mtx rng_lock; +#endif + +struct nng_tls_engine_conn { + void *tls; // parent conn + mbedtls_ssl_context ctx; + nng_time exp1; + nng_time exp2; +}; + +struct nng_tls_engine_config { + mbedtls_ssl_config cfg_ctx; + char *server_name; + mbedtls_x509_crt ca_certs; + mbedtls_x509_crl crl; + int min_ver; + int max_ver; + nng_tls_mode mode; + nni_list pairs; + nni_list psks; +}; + +static mbedtls_ssl_cookie_ctx mbed_ssl_cookie_ctx; + +static void +tls_dbg(void *ctx, int level, const char *file, int line, const char *s) +{ + NNI_ARG_UNUSED(ctx); + NNI_ARG_UNUSED(level); + const char *f; + while ((f = strchr(file, '/')) != NULL) { + file = f + 1; + } + nng_log_debug("MBED", "%s: %d: %s", file, line, s); +} + +static int +tls_get_entropy(void *arg, unsigned char *buf, size_t len) +{ + NNI_ARG_UNUSED(arg); + while (len) { + uint32_t x = nni_random(); + size_t n; + + n = len < sizeof(x) ? len : sizeof(x); + memcpy(buf, &x, n); + len -= n; + buf += n; + } + return (0); +} + +static int +tls_random(void *arg, unsigned char *buf, size_t sz) +{ +#ifdef NNG_TLS_USE_CTR_DRBG + int rv; + + nni_mtx_lock(&rng_lock); + rv = mbedtls_ctr_drbg_random(&rng_ctx, buf, sz); + nni_mtx_unlock(&rng_lock); + return (rv); +#else + return (tls_get_entropy(arg, buf, sz)); +#endif +} + +static void +tls_log_err(const char *msgid, const char *context, int errnum) +{ + char errbuf[256]; + mbedtls_strerror(errnum, errbuf, sizeof(errbuf)); + nng_log_err(msgid, "%s: %s", context, errbuf); +} + +static void +tls_log_warn(const char *msgid, const char *context, int errnum) +{ + char errbuf[256]; + mbedtls_strerror(errnum, errbuf, sizeof(errbuf)); + nng_log_warn(msgid, "%s: %d - %s", context, errnum, errbuf); +} + +// tls_mk_err converts an mbed error to an NNG error. +static struct { + int tls; + int nng; +} tls_errs[] = { +#ifdef MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE + { MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE, NNG_EPEERAUTH }, +#endif +#ifdef MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED + { MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED, NNG_EPEERAUTH }, +#endif +#ifdef MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED + { MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED, NNG_EPEERAUTH }, +#endif +#ifdef MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE + { MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE, NNG_EPEERAUTH }, +#endif + { MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY, NNG_ECONNREFUSED }, + { MBEDTLS_ERR_SSL_ALLOC_FAILED, NNG_ENOMEM }, + { MBEDTLS_ERR_SSL_TIMEOUT, NNG_ETIMEDOUT }, + { MBEDTLS_ERR_SSL_CONN_EOF, NNG_ECLOSED }, +// MbedTLS 3.0 error codes +#ifdef MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE + { MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE, NNG_EPEERAUTH }, +#endif +#ifdef MBEDTLS_ERR_SSL_BAD_CERTIFICATE + { MBEDTLS_ERR_SSL_BAD_CERTIFICATE, NNG_EPEERAUTH }, +#endif + // terminator + { 0, 0 }, +}; + +static int +tls_mk_err(int err) +{ + for (int i = 0; tls_errs[i].tls != 0; i++) { + if (tls_errs[i].tls == err) { + return (tls_errs[i].nng); + } + } + return (NNG_ECRYPTO); +} + +static int +net_send(void *tls, const unsigned char *buf, size_t len) +{ + size_t sz = len; + int rv; + + rv = nng_tls_engine_send(tls, buf, &sz); + switch (rv) { + case 0: + return ((int) sz); + case NNG_EAGAIN: + return (MBEDTLS_ERR_SSL_WANT_WRITE); + default: + return (MBEDTLS_ERR_NET_SEND_FAILED); + } +} + +static int +net_recv(void *tls, unsigned char *buf, size_t len) +{ + size_t sz = len; + int rv; + + rv = nng_tls_engine_recv(tls, buf, &sz); + switch (rv) { + case 0: + return ((int) sz); + case NNG_EAGAIN: + return (MBEDTLS_ERR_SSL_WANT_READ); + default: + return (MBEDTLS_ERR_NET_RECV_FAILED); + } +} + +static void +conn_fini(nng_tls_engine_conn *ec) +{ + mbedtls_ssl_free(&ec->ctx); +} + +static void +conn_set_timer(void *arg, unsigned int t1, unsigned int t2) +{ + nng_time now = nng_clock(); + nng_tls_engine_conn *ec = arg; + ec->exp1 = t1 ? now + t1 : 0; + ec->exp2 = t2 ? now + t2 : 0; +} + +static int +conn_get_timer(void *arg) +{ + nng_tls_engine_conn *ec = arg; + nng_time now = nng_clock(); + if (ec->exp2 == 0) { + return -1; + } + if (now > ec->exp2) { + return 2; + } + if (now > ec->exp1) { + return 1; + } + return (0); +} + +static int +conn_init(nng_tls_engine_conn *ec, void *tls, nng_tls_engine_config *cfg, + const nng_sockaddr *sa) +{ + int rv; + char buf[NNG_MAXADDRSTRLEN]; + + ec->tls = tls; + + mbedtls_ssl_init(&ec->ctx); + mbedtls_ssl_set_bio(&ec->ctx, tls, net_send, net_recv, NULL); + mbedtls_ssl_set_timer_cb(&ec->ctx, ec, conn_set_timer, conn_get_timer); + + if ((rv = mbedtls_ssl_setup(&ec->ctx, &cfg->cfg_ctx)) != 0) { + tls_log_warn( + "NNG-TLS-CONN-FAIL", "Failed to setup TLS connection", rv); + return (tls_mk_err(rv)); + } + + if (cfg->server_name != NULL) { + mbedtls_ssl_set_hostname(&ec->ctx, cfg->server_name); + } + + if (cfg->mode == NNG_TLS_MODE_SERVER) { + nng_str_sockaddr(sa, buf, sizeof(buf)); + mbedtls_ssl_set_client_transport_id( + &ec->ctx, (const void *) buf, strlen(buf)); + } + + return (0); +} + +static void +conn_close(nng_tls_engine_conn *ec) +{ + // This may succeed, or it may fail. Either way we + // don't care. Implementations that depend on + // close-notify to mean anything are broken by design, + // just like RFC. Note that we do *NOT* close the TCP + // connection at this point. + (void) mbedtls_ssl_close_notify(&ec->ctx); +} + +static int +conn_recv(nng_tls_engine_conn *ec, uint8_t *buf, size_t *szp) +{ + int rv; + if ((rv = mbedtls_ssl_read(&ec->ctx, buf, *szp)) < 0) { + switch (rv) { + case MBEDTLS_ERR_SSL_WANT_READ: + case MBEDTLS_ERR_SSL_WANT_WRITE: + return (NNG_EAGAIN); + default: + return (tls_mk_err(rv)); + } + } + *szp = (size_t) rv; + return (0); +} + +static int +conn_send(nng_tls_engine_conn *ec, const uint8_t *buf, size_t *szp) +{ + int rv; + + if ((rv = mbedtls_ssl_write(&ec->ctx, buf, *szp)) < 0) { + switch (rv) { + case MBEDTLS_ERR_SSL_WANT_READ: + case MBEDTLS_ERR_SSL_WANT_WRITE: + return (NNG_EAGAIN); + default: + return (tls_mk_err(rv)); + } + } + *szp = (size_t) rv; + return (0); +} + +static int +conn_handshake(nng_tls_engine_conn *ec) +{ + int rv; + + rv = mbedtls_ssl_handshake(&ec->ctx); + switch (rv) { + case MBEDTLS_ERR_SSL_WANT_WRITE: + case MBEDTLS_ERR_SSL_WANT_READ: + // We have underlying I/O to complete first. We will + // be called again by a callback later. + return (NNG_EAGAIN); + case 0: + // The handshake is done, yay! + return (0); + + default: + tls_log_warn("NNG-TLS-HANDSHAKE", "TLS handshake failed", rv); + return (tls_mk_err(rv)); + } +} + +static bool +conn_verified(nng_tls_engine_conn *ec) +{ + return (mbedtls_ssl_get_verify_result(&ec->ctx) == 0); +} + +static char * +conn_peer_cn(nng_tls_engine_conn *ec) +{ + const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(&ec->ctx); + if (!crt) { + return (NULL); + } + + char buf[0x400]; + int len = mbedtls_x509_dn_gets(buf, sizeof(buf), &crt->subject); + if (len <= 0) { + return (NULL); + } + + const char *pos = strstr(buf, "CN="); + if (!pos) { + return (NULL); + } + + pos += 3; + len -= (int) (pos - buf - 1); + if (len <= 1) { + return (NULL); + } + + char *rv = malloc(len); + memcpy(rv, pos, len); + return (rv); +} + +static char ** +conn_peer_alt_names(nng_tls_engine_conn *ec) +{ + const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(&ec->ctx); + if (!crt) { + return (NULL); + } + + const mbedtls_asn1_sequence *seq = &crt->subject_alt_names; + + // get count + int count = 0; + do { + if (seq->buf.len > 0) + ++count; + seq = seq->next; + } while (seq); + if (count == 0) + return NULL; + + seq = &crt->subject_alt_names; + + // copy strings + char **rv = malloc((count + 1) * sizeof(char *)); + int i = 0; + do { + if (seq->buf.len == 0) + continue; + + rv[i] = malloc(seq->buf.len + 1); + memcpy(rv[i], seq->buf.p, seq->buf.len); + rv[i][seq->buf.len] = 0; + ++i; + + seq = seq->next; + } while (seq); + rv[i] = NULL; + + return rv; +} + +static void +config_fini(nng_tls_engine_config *cfg) +{ + pair *p; + psk *psk; + + mbedtls_ssl_config_free(&cfg->cfg_ctx); +#ifdef NNG_TLS_USE_CTR_DRBG + mbedtls_ctr_drbg_free(&cfg->rng_ctx); +#endif + mbedtls_x509_crt_free(&cfg->ca_certs); + mbedtls_x509_crl_free(&cfg->crl); + if (cfg->server_name) { + nni_strfree(cfg->server_name); + } + while ((p = nni_list_first(&cfg->pairs)) != NULL) { + nni_list_remove(&cfg->pairs, p); + mbedtls_x509_crt_free(&p->crt); + mbedtls_pk_free(&p->key); + + NNI_FREE_STRUCT(p); + } + while ((psk = nni_list_first(&cfg->psks)) != NULL) { + nni_list_remove(&cfg->psks, psk); + psk_free(psk); + } +} + +static int +config_init(nng_tls_engine_config *cfg, enum nng_tls_mode mode) +{ + int rv; + int ssl_mode; + int auth_mode; + + if (mode == NNG_TLS_MODE_SERVER) { + ssl_mode = MBEDTLS_SSL_IS_SERVER; + auth_mode = MBEDTLS_SSL_VERIFY_NONE; + } else { + ssl_mode = MBEDTLS_SSL_IS_CLIENT; + auth_mode = MBEDTLS_SSL_VERIFY_REQUIRED; + } + + cfg->mode = mode; + NNI_LIST_INIT(&cfg->pairs, pair, node); + NNI_LIST_INIT(&cfg->psks, psk, node); + mbedtls_ssl_config_init(&cfg->cfg_ctx); + mbedtls_x509_crt_init(&cfg->ca_certs); + mbedtls_x509_crl_init(&cfg->crl); + + rv = mbedtls_ssl_config_defaults(&cfg->cfg_ctx, ssl_mode, + MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); + if (rv != 0) { + tls_log_err("NNG-TLS-CONFIG-INIT-FAIL", + "Failed to initialize TLS configuration", rv); + config_fini(cfg); + return (tls_mk_err(rv)); + } + + mbedtls_ssl_conf_authmode(&cfg->cfg_ctx, auth_mode); + + // We *require* TLS v1.2 or newer, which is also known as SSL + // v3.3. + cfg->min_ver = MBEDTLS_SSL_MINOR_VERSION_3; +#ifdef MBEDTLS_SSL_PROTO_TLS1_3 + cfg->max_ver = MBEDTLS_SSL_MINOR_VERSION_4; +#else + cfg->max_ver = MBEDTLS_SSL_MINOR_VERSION_3; +#endif + + mbedtls_ssl_conf_min_version( + &cfg->cfg_ctx, MBEDTLS_SSL_MAJOR_VERSION_3, cfg->min_ver); + mbedtls_ssl_conf_max_version( + &cfg->cfg_ctx, MBEDTLS_SSL_MAJOR_VERSION_3, cfg->max_ver); + + mbedtls_ssl_conf_rng(&cfg->cfg_ctx, tls_random, cfg); + mbedtls_ssl_conf_dbg(&cfg->cfg_ctx, tls_dbg, cfg); + + if (cfg->mode == NNG_TLS_MODE_SERVER) { + mbedtls_ssl_conf_dtls_cookies(&cfg->cfg_ctx, + mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, + &mbed_ssl_cookie_ctx); + } + + return (0); +} + +static int +config_server_name(nng_tls_engine_config *cfg, const char *name) +{ + char *dup; + if ((dup = nni_strdup(name)) == NULL) { + return (NNG_ENOMEM); + } + if (cfg->server_name != NULL) { + nni_strfree(cfg->server_name); + } + cfg->server_name = dup; + return (0); +} + +// callback used on the server side to select the right key +static int +config_psk_cb(void *arg, mbedtls_ssl_context *ssl, + const unsigned char *identity, size_t id_len) +{ + nng_tls_engine_config *cfg = arg; + psk *psk; + NNI_LIST_FOREACH (&cfg->psks, psk) { + if (id_len == strlen(psk->identity) && + (memcmp(identity, psk->identity, id_len) == 0)) { + nng_log_debug("NNG-TLS-PSK-IDENTITY", + "TLS client using PSK identity %s", psk->identity); + return (mbedtls_ssl_set_hs_psk( + ssl, psk->key, psk->keylen)); + } + } + nng_log_warn( + "NNG-TLS-PSK-NO-IDENTITY", "TLS client PSK identity not found"); + return (MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY); +} + +static int +config_psk(nng_tls_engine_config *cfg, const char *identity, + const uint8_t *key, size_t key_len) +{ + int rv; + psk *srch; + psk *newpsk; + + if (((newpsk = NNI_ALLOC_STRUCT(newpsk)) == NULL) || + ((newpsk->identity = nni_strdup(identity)) == NULL) || + ((newpsk->key = nni_alloc(key_len)) == NULL)) { + psk_free(newpsk); + return (NNG_ENOMEM); + } + newpsk->keylen = key_len; + memcpy(newpsk->key, key, key_len); + + if (cfg->mode == NNG_TLS_MODE_SERVER) { + if (nni_list_empty(&cfg->psks)) { + mbedtls_ssl_conf_psk_cb( + &cfg->cfg_ctx, config_psk_cb, cfg); + } + } else { + if ((rv = mbedtls_ssl_conf_psk(&cfg->cfg_ctx, key, key_len, + (const unsigned char *) identity, + strlen(identity))) != 0) { + psk_free(newpsk); + tls_log_err("NNG-TLS-PSK-FAIL", + "Failed to configure PSK identity", rv); + return (tls_mk_err(rv)); + } + } + + // If the identity was previously configured, replace it. + // The rule here is that last one wins, so we always append. + NNI_LIST_FOREACH (&cfg->psks, srch) { + if (strcmp(srch->identity, identity) == 0) { + nni_list_remove(&cfg->psks, srch); + psk_free(srch); + break; + } + } + nni_list_append(&cfg->psks, newpsk); + return (0); +} + +static int +config_auth_mode(nng_tls_engine_config *cfg, nng_tls_auth_mode mode) +{ + switch (mode) { + case NNG_TLS_AUTH_MODE_NONE: + mbedtls_ssl_conf_authmode( + &cfg->cfg_ctx, MBEDTLS_SSL_VERIFY_NONE); + return (0); + case NNG_TLS_AUTH_MODE_OPTIONAL: + mbedtls_ssl_conf_authmode( + &cfg->cfg_ctx, MBEDTLS_SSL_VERIFY_OPTIONAL); + return (0); + case NNG_TLS_AUTH_MODE_REQUIRED: + mbedtls_ssl_conf_authmode( + &cfg->cfg_ctx, MBEDTLS_SSL_VERIFY_REQUIRED); + return (0); + } + return (NNG_EINVAL); +} + +static int +config_ca_chain(nng_tls_engine_config *cfg, const char *certs, const char *crl) +{ + size_t len; + const uint8_t *pem; + int rv; + + // Certs and CRL are in PEM data, with terminating NUL byte. + pem = (const uint8_t *) certs; + len = strlen(certs) + 1; + if ((rv = mbedtls_x509_crt_parse(&cfg->ca_certs, pem, len)) != 0) { + tls_log_err("NNG-TLS-CA-FAIL", + "Failed to parse CA certificate(s)", rv); + return (tls_mk_err(rv)); + } + if (crl != NULL) { + pem = (const uint8_t *) crl; + len = strlen(crl) + 1; + if ((rv = mbedtls_x509_crl_parse(&cfg->crl, pem, len)) != 0) { + tls_log_err("NNG-TLS-CRL-FAIL", + "Failed to parse revocation list", rv); + return (tls_mk_err(rv)); + } + } + + mbedtls_ssl_conf_ca_chain(&cfg->cfg_ctx, &cfg->ca_certs, &cfg->crl); + return (0); +} + +static int +config_own_cert(nng_tls_engine_config *cfg, const char *cert, const char *key, + const char *pass) +{ + size_t len; + const uint8_t *pem; + pair *p; + int rv; + + if ((p = NNI_ALLOC_STRUCT(p)) == NULL) { + return (NNG_ENOMEM); + } + mbedtls_x509_crt_init(&p->crt); + mbedtls_pk_init(&p->key); + + pem = (const uint8_t *) cert; + len = strlen(cert) + 1; + if ((rv = mbedtls_x509_crt_parse(&p->crt, pem, len)) != 0) { + tls_log_err("NNG-TLS-CRT-FAIL", + "Failure parsing our own certificate", rv); + rv = tls_mk_err(rv); + goto err; + } + + pem = (const uint8_t *) key; + len = strlen(key) + 1; +#if MBEDTLS_VERSION_MAJOR < 3 + rv = mbedtls_pk_parse_key(&p->key, pem, len, (const uint8_t *) pass, + pass != NULL ? strlen(pass) : 0); +#else + rv = mbedtls_pk_parse_key(&p->key, pem, len, (const uint8_t *) pass, + pass != NULL ? strlen(pass) : 0, tls_random, NULL); +#endif + if (rv != 0) { + tls_log_err("NNG-TLS-KEY", "Failure parsing private key", rv); + rv = tls_mk_err(rv); + goto err; + } + + rv = mbedtls_ssl_conf_own_cert(&cfg->cfg_ctx, &p->crt, &p->key); + if (rv != 0) { + tls_log_err("NNG-TLS-SELF", + "Failure configuring self certificate", rv); + rv = tls_mk_err(rv); + goto err; + } + + // Save this structure so we can free it with the context. + nni_list_append(&cfg->pairs, p); + return (0); + +err: + mbedtls_x509_crt_free(&p->crt); + mbedtls_pk_free(&p->key); + NNI_FREE_STRUCT(p); + return (rv); +} + +static int +config_version(nng_tls_engine_config *cfg, nng_tls_version min_ver, + nng_tls_version max_ver) +{ + int v1, v2; + int maj = MBEDTLS_SSL_MAJOR_VERSION_3; + + if (min_ver > max_ver) { + nng_log_err("TLS-CFG-VER", + "TLS maximum version must be larger than mimumum version"); + return (NNG_ENOTSUP); + } + switch (min_ver) { +#ifdef MBEDTLS_SSL_MINOR_VERSION_3 + case NNG_TLS_1_2: + v1 = MBEDTLS_SSL_MINOR_VERSION_3; + break; +#endif +#ifdef MBEDTLS_SSL_PROTO_TLS1_3 + case NNG_TLS_1_3: + v1 = MBEDTLS_SSL_MINOR_VERSION_4; + break; +#endif + default: + nng_log_err( + "TLS-CFG-VER", "TLS minimum version not supported"); + return (NNG_ENOTSUP); + } + + switch (max_ver) { +#ifdef MBEDTLS_SSL_MINOR_VERSION_3 + case NNG_TLS_1_2: + v2 = MBEDTLS_SSL_MINOR_VERSION_3; + break; +#endif + case NNG_TLS_1_3: // We lack support for 1.3, so treat as 1.2. +#ifdef MBEDTLS_SSL_PROTO_TLS1_3 + v2 = MBEDTLS_SSL_MINOR_VERSION_4; +#else + v2 = MBEDTLS_SSL_MINOR_VERSION_3; +#endif + break; + default: + // Note that this means that if we ever TLS 1.4 or 2.0, + // then this will break. That's sufficiently far out + // to justify not worrying about it. + nng_log_err( + "TLS-CFG-VER", "TLS maximum version not supported"); + return (NNG_ENOTSUP); + } + + cfg->min_ver = v1; + cfg->max_ver = v2; + mbedtls_ssl_conf_min_version(&cfg->cfg_ctx, maj, cfg->min_ver); + mbedtls_ssl_conf_max_version(&cfg->cfg_ctx, maj, cfg->max_ver); + return (0); +} + +static nng_tls_engine_config_ops config_ops = { + .init = config_init, + .fini = config_fini, + .size = sizeof(nng_tls_engine_config), + .auth = config_auth_mode, + .ca_chain = config_ca_chain, + .own_cert = config_own_cert, + .server = config_server_name, + .psk = config_psk, + .version = config_version, +}; + +static nng_tls_engine_conn_ops conn_ops = { + .size = sizeof(nng_tls_engine_conn), + .init = conn_init, + .fini = conn_fini, + .close = conn_close, + .recv = conn_recv, + .send = conn_send, + .handshake = conn_handshake, + .verified = conn_verified, + .peer_cn = conn_peer_cn, + .peer_alt_names = conn_peer_alt_names, +}; + +static nng_tls_engine tls_engine_mbed = { + .version = NNG_TLS_ENGINE_VERSION, + .config_ops = &config_ops, + .conn_ops = &conn_ops, + .name = "mbed", + .description = MBEDTLS_VERSION_STRING_FULL, + .fips_mode = false, +}; + +int +nng_tls_engine_init_mbed(void) +{ + int rv; + +#ifdef NNG_TLS_USE_CTR_DRBG + nni_mtx_init(&rng_lock); + + mbedtls_ctr_drbg_init(&cfg->rng_ctx); + rv = mbedtls_ctr_drbg_seed(&rng_ctx, tls_get_entropy, NULL, NULL, 0); + if (rv != 0) { + tls_log_err("NNG-TLS-RNG", "Failed initializing CTR DRBG", rv); + nni_mtx_fini(&rng_lock); + return (rv); + } +#endif +#ifdef MBEDTLS_PSA_CRYPTO_C + rv = psa_crypto_init(); + if (rv != 0) { + tls_log_err( + "NNG-TLS-INIT", "Failed initializing PSA crypto", rv); + return (rv); + } +#endif + // Uncomment the following to have noisy debug from mbedTLS. + // This may be useful when trying to debug failures. + // mbedtls_debug_set_threshold(9); + + mbedtls_ssl_cookie_init(&mbed_ssl_cookie_ctx); + rv = mbedtls_ssl_cookie_setup(&mbed_ssl_cookie_ctx, tls_random, NULL); + + if (rv == 0) { + rv = nng_tls_engine_register(&tls_engine_mbed); + } + +#ifdef NNG_TLS_USE_CTR_DRBG + if (rv != 0) { + nni_mtx_fini(&rng_lock); + } +#endif + + return (rv); +} + +void +nng_tls_engine_fini_mbed(void) +{ + mbedtls_ssl_cookie_free(&mbed_ssl_cookie_ctx); +#ifdef NNG_TLS_USE_CTR_DRBG + mbedtls_ctr_drbg_free(&rng_ctx); + nni_mtx_fini(&rng_lock); +#endif +#ifdef MBEDTLS_PSA_CRYPTO_C + mbedtls_psa_crypto_free(); +#endif +} |
