From ec00feef357f04a3eb719137737502ffd7fea606 Mon Sep 17 00:00:00 2001 From: Emil Hammarstrom Date: Mon, 19 Oct 2020 16:53:44 +0200 Subject: [PATCH] net: lib: sockets: added ALPN extension option to TLS Adds the socket option TLS_ALPN_LIST for SOL_TLS sockets Passes the configured alpn list to the mbedtls config on mbedtls init Signed-off-by: Emil Hammarstrom --- include/net/socket.h | 6 ++ modules/Kconfig.tls-generic | 4 ++ subsys/net/lib/sockets/Kconfig | 9 +++ subsys/net/lib/sockets/sockets_tls.c | 87 ++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+) diff --git a/include/net/socket.h b/include/net/socket.h index d900a225d22..76544a9ca16 100644 --- a/include/net/socket.h +++ b/include/net/socket.h @@ -119,6 +119,12 @@ struct zsock_pollfd { * - 1 - server */ #define TLS_DTLS_ROLE 6 +/** Socket option for setting the supported Application Layer Protocols. + * It accepts and returns a const char array of NULL terminated strings + * representing the supported application layer protocols listed during + * the TLS handshake. + */ +#define TLS_ALPN_LIST 7 /** @} */ diff --git a/modules/Kconfig.tls-generic b/modules/Kconfig.tls-generic index 28b4242c427..024b1376d0f 100644 --- a/modules/Kconfig.tls-generic +++ b/modules/Kconfig.tls-generic @@ -37,6 +37,10 @@ config MBEDTLS_SSL_EXPORT_KEYS bool "Enable support for exporting SSL key block and master secret" depends on MBEDTLS_TLS_VERSION_1_0 || MBEDTLS_TLS_VERSION_1_1 || MBEDTLS_TLS_VERSION_1_2 +config MBEDTLS_SSL_ALPN + bool "Enable support for setting the supported Application Layer Protocols" + depends on MBEDTLS_TLS_VERSION_1_0 || MBEDTLS_TLS_VERSION_1_1 || MBEDTLS_TLS_VERSION_1_2 + endmenu menu "Ciphersuite configuration" diff --git a/subsys/net/lib/sockets/Kconfig b/subsys/net/lib/sockets/Kconfig index aac861eb37d..c806c1c3452 100644 --- a/subsys/net/lib/sockets/Kconfig +++ b/subsys/net/lib/sockets/Kconfig @@ -100,6 +100,15 @@ config NET_SOCKETS_TLS_MAX_CIPHERSUITES By default, all ciphersuites that are available in the system are available to the socket. +config NET_SOCKETS_TLS_MAX_APP_PROTOCOLS + int "Maximum number of supported application layer protocols" + default 2 + depends on NET_SOCKETS_SOCKOPT_TLS && MBEDTLS_SSL_ALPN + help + This variable sets maximum number of supported application layer + protocols over TLS/DTL that can be set explicitly by a socket option. + By default, no supported application layer protocol is set. + config NET_SOCKETS_OFFLOAD bool "Offload Socket APIs [EXPERIMENTAL]" help diff --git a/subsys/net/lib/sockets/sockets_tls.c b/subsys/net/lib/sockets/sockets_tls.c index 81848a3b4c5..1c8f910a632 100644 --- a/subsys/net/lib/sockets/sockets_tls.c +++ b/subsys/net/lib/sockets/sockets_tls.c @@ -39,6 +39,12 @@ LOG_MODULE_REGISTER(net_sock_tls, CONFIG_NET_SOCKETS_LOG_LEVEL); #include "sockets_internal.h" #include "tls_internal.h" +#if defined(CONFIG_NET_SOCKETS_TLS_MAX_APP_PROTOCOLS) +#define ALPN_MAX_PROTOCOLS (CONFIG_NET_SOCKETS_TLS_MAX_APP_PROTOCOLS + 1) +#else +#define ALPN_MAX_PROTOCOLS 0 +#endif /* CONFIG_NET_SOCKETS_TLS_MAX_APP_PROTOCOLS */ + static const struct socket_op_vtable tls_sock_fd_op_vtable; /** A list of secure tags that TLS context should use. */ @@ -109,6 +115,11 @@ struct tls_context { /** DTLS role, client by default. */ int8_t role; + + /** NULL-terminated list of allowed application layer + * protocols. + */ + const char *alpn_list[ALPN_MAX_PROTOCOLS]; } options; #if defined(CONFIG_NET_SOCKETS_ENABLE_DTLS) @@ -920,6 +931,16 @@ static int tls_mbedtls_init(struct tls_context *context, bool is_server) return ret; } +#if defined(CONFIG_MBEDTLS_SSL_ALPN) + if (ALPN_MAX_PROTOCOLS && context->options.alpn_list[0] != NULL) { + ret = mbedtls_ssl_conf_alpn_protocols(&context->config, + context->options.alpn_list); + if (ret != 0) { + return -EINVAL; + } + } +#endif /* CONFIG_MBEDTLS_SSL_ALPN */ + ret = mbedtls_ssl_setup(&context->ssl, &context->config); if (ret != 0) { @@ -1072,6 +1093,64 @@ static int tls_opt_ciphersuite_used_get(struct tls_context *context, return 0; } +static int tls_opt_alpn_list_set(struct tls_context *context, + const void *optval, socklen_t optlen) +{ + int alpn_cnt; + + if (!ALPN_MAX_PROTOCOLS) { + return -EINVAL; + } + + if (!optval) { + return -EINVAL; + } + + if (optlen % sizeof(const char *) != 0) { + return -EINVAL; + } + + alpn_cnt = optlen / sizeof(const char *); + /* + 1 for NULL-termination. */ + if (alpn_cnt + 1 > ARRAY_SIZE(context->options.alpn_list)) { + return -EINVAL; + } + + memcpy(context->options.alpn_list, optval, optlen); + context->options.alpn_list[alpn_cnt] = NULL; + + return 0; +} + +static int tls_opt_alpn_list_get(struct tls_context *context, + void *optval, socklen_t *optlen) +{ + const char **alpn_list = context->options.alpn_list; + int alpn_cnt, i = 0; + const char **ret_list = optval; + + if (!ALPN_MAX_PROTOCOLS) { + return -EINVAL; + } + + if (*optlen % sizeof(const char *) != 0 || *optlen == 0) { + return -EINVAL; + } + + alpn_cnt = *optlen / sizeof(const char *); + while (alpn_list[i] != NULL) { + ret_list[i] = alpn_list[i]; + + if (++i == alpn_cnt) { + break; + } + } + + *optlen = i * sizeof(const char *); + + return 0; +} + static int tls_opt_peer_verify_set(struct tls_context *context, const void *optval, socklen_t optlen) { @@ -1922,6 +2001,10 @@ int ztls_getsockopt_ctx(struct tls_context *ctx, int level, int optname, err = tls_opt_ciphersuite_used_get(ctx, optval, optlen); break; + case TLS_ALPN_LIST: + err = tls_opt_alpn_list_get(ctx, optval, optlen); + break; + default: /* Unknown or write-only option. */ err = -ENOPROTOOPT; @@ -1967,6 +2050,10 @@ int ztls_setsockopt_ctx(struct tls_context *ctx, int level, int optname, err = tls_opt_dtls_role_set(ctx, optval, optlen); break; + case TLS_ALPN_LIST: + err = tls_opt_alpn_list_set(ctx, optval, optlen); + break; + default: /* Unknown or read-only option. */ err = -ENOPROTOOPT;