From be9d6648f81497172440efd6785f9339271168ae Mon Sep 17 00:00:00 2001 From: Hanno Becker Date: Fri, 21 Aug 2020 13:20:06 +0100 Subject: [PATCH] Implement TLS 1.3 key derivation function HKDF-Expand-Label This commit introduces a new file library/ssl_tls13_key.c which will subsequently be populated with functionality relating to the TLS 1.3 key schedule. Those functions are expected to be internal and are documented in the internal header library/ssl_tls13_keys.h. The first function to be implemented is the key expansion function `HKDF-Expand-Label`. See the documentation in library/ssl_tls13_keys.h for more information. Signed-off-by: Hanno Becker --- library/CMakeLists.txt | 1 + library/Makefile | 1 + library/ssl_tls13_keys.c | 182 +++++++++++++++++++++++++++++++++ library/ssl_tls13_keys.h | 106 +++++++++++++++++++ visualc/VS2010/mbedTLS.vcxproj | 2 + 5 files changed, 292 insertions(+) create mode 100644 library/ssl_tls13_keys.c create mode 100644 library/ssl_tls13_keys.h diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 33e2cfc855..7e11816f10 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -103,6 +103,7 @@ set(src_tls ssl_srv.c ssl_ticket.c ssl_tls.c + ssl_tls13_keys.c ) if(CMAKE_COMPILER_IS_GNUCC) diff --git a/library/Makefile b/library/Makefile index b76a84bdd2..bd5274de44 100644 --- a/library/Makefile +++ b/library/Makefile @@ -162,6 +162,7 @@ OBJS_TLS= \ ssl_srv.o \ ssl_ticket.o \ ssl_tls.o \ + ssl_tls13_keys.o \ # This line is intentionally left blank .SILENT: diff --git a/library/ssl_tls13_keys.c b/library/ssl_tls13_keys.c new file mode 100644 index 0000000000..448d03a61a --- /dev/null +++ b/library/ssl_tls13_keys.c @@ -0,0 +1,182 @@ +/* + * TLS 1.3 key schedule + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 ( the "License" ); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#include "mbedtls/hkdf.h" +#include "ssl_tls13_keys.h" + +#include +#include + +struct mbedtls_ssl_tls1_3_labels_struct const mbedtls_ssl_tls1_3_labels = +{ + /* This seems to work in C, despite the string literal being one + * character too long due to the 0-termination. */ + .finished = "finished", + .resumption = "resumption", + .traffic_upd = "traffic upd", + .export = "exporter", + .key = "key", + .iv = "iv", + .sn = "sn", + .c_hs_traffic = "c hs traffic", + .c_ap_traffic = "c ap traffic", + .c_e_traffic = "c e traffic", + .s_hs_traffic = "s hs traffic", + .s_ap_traffic = "s ap traffic", + .s_e_traffic = "s e traffic", + .exp_master = "exp master", + .res_master = "res master", + .ext_binder = "ext binder", + .res_binder = "res binder", + .derived = "derived" +}; + +/* + * This function creates a HkdfLabel structure used in the TLS 1.3 key schedule. + * + * The HkdfLabel is specified in RFC 8446 as follows: + * + * struct HkdfLabel { + * uint16 length; // Length of expanded key material + * opaque label<7..255>; // Always prefixed by "tls13 " + * opaque context<0..255>; // Usually a communication transcript hash + * }; + * + * Parameters: + * - desired_length: Length of expanded key material + * Even though the standard allows expansion to up to + * 2**16 Bytes, TLS 1.3 never uses expansion to more than + * 255 Bytes, so we require `desired_length` to be at most + * 255. This allows us to save a few Bytes of code by + * hardcoding the writing of the high bytes. + * - (label, llen): label + label length, without "tls13 " prefix + * The label length MUST be + * <= MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_LABEL_LEN + * It is the caller's responsiblity to ensure this. + * - (ctx, clen): context + context length + * The context length MUST be + * <= MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_CONTEXT_LEN + * It is the caller's responsiblity to ensure this. + * - dst: Target buffer for HkdfLabel structure, + * This MUST be a writable buffer of size + * at least SSL_TLS1_3_KEY_SCHEDULE_MAX_HKDF_LABEL_LEN Bytes. + * - dlen: Pointer at which to store the actual length of + * the HkdfLabel structure on success. + */ + +#define SSL_TLS1_3_KEY_SCHEDULE_MAX_HKDF_LABEL_LEN \ + ( 2 /* expansion length */ \ + + 1 /* label length */ \ + + MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_LABEL_LEN \ + + 1 /* context length */ \ + + MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_CONTEXT_LEN ) + +static void ssl_tls1_3_hkdf_encode_label( + size_t desired_length, + const unsigned char *label, size_t llen, + const unsigned char *ctx, size_t clen, + unsigned char *dst, size_t *dlen ) +{ + const char label_prefix[6] = { 't', 'l', 's', '1', '3', ' ' }; + size_t total_label_len = sizeof( label_prefix ) + llen; + size_t total_hkdf_lbl_len = + 2 /* length of expanded key material */ + + 1 /* label length */ + + total_label_len /* actual label, incl. prefix */ + + 1 /* context length */ + + clen; /* actual context */ + + unsigned char *p = dst; + + /* Add total length. */ + *p++ = 0; + *p++ = (unsigned char)( ( desired_length >> 0 ) & 0xFF ); + + /* Add label incl. prefix */ + *p++ = (unsigned char)( total_label_len & 0xFF ); + memcpy( p, label_prefix, sizeof(label_prefix) ); + p += sizeof(label_prefix); + memcpy( p, label, llen ); + p += llen; + + /* Add context value */ + *p++ = (unsigned char)( clen & 0xFF ); + if( ctx != NULL ) + memcpy( p, ctx, clen ); + + /* Return total length to the caller. */ + *dlen = total_hkdf_lbl_len; +} + +int mbedtls_ssl_tls1_3_hkdf_expand_label( + mbedtls_md_type_t hash_alg, + const unsigned char *secret, size_t slen, + const unsigned char *label, size_t llen, + const unsigned char *ctx, size_t clen, + unsigned char *buf, size_t blen ) +{ + const mbedtls_md_info_t *md; + unsigned char hkdf_label[ SSL_TLS1_3_KEY_SCHEDULE_MAX_HKDF_LABEL_LEN ]; + size_t hkdf_label_len; + + if( llen > MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_LABEL_LEN ) + { + /* Should never happen since this is an internal + * function, and we know statically which labels + * are allowed. */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( clen > MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_CONTEXT_LEN ) + { + /* Should not happen, as above. */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( blen > MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_EXPANSION_LEN ) + { + /* Should not happen, as above. */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + md = mbedtls_md_info_from_type( hash_alg ); + if( md == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + ssl_tls1_3_hkdf_encode_label( blen, + label, llen, + ctx, clen, + hkdf_label, + &hkdf_label_len ); + + return( mbedtls_hkdf_expand( md, + secret, slen, + hkdf_label, hkdf_label_len, + buf, blen ) ); +} + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ diff --git a/library/ssl_tls13_keys.h b/library/ssl_tls13_keys.h new file mode 100644 index 0000000000..49f4121137 --- /dev/null +++ b/library/ssl_tls13_keys.h @@ -0,0 +1,106 @@ +/* + * TLS 1.3 key schedule + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 ( the "License" ); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#if !defined(MBEDTLS_SSL_TLS1_3_KEYS_H) +#define MBEDTLS_SSL_TLS1_3_KEYS_H + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define MBEDTLS_SSL_TLS1_3_LABEL_LIST \ + const unsigned char finished [ sizeof("finished") - 1 ]; \ + const unsigned char resumption [ sizeof("resumption") - 1 ]; \ + const unsigned char traffic_upd [ sizeof("traffic upd") - 1 ]; \ + const unsigned char export [ sizeof("exporter") - 1 ]; \ + const unsigned char key [ sizeof("key") - 1 ]; \ + const unsigned char iv [ sizeof("iv") - 1 ]; \ + const unsigned char sn [ sizeof("sn") - 1 ]; \ + const unsigned char c_hs_traffic[ sizeof("c hs traffic") - 1 ]; \ + const unsigned char c_ap_traffic[ sizeof("c ap traffic") - 1 ]; \ + const unsigned char c_e_traffic [ sizeof("c e traffic") - 1 ]; \ + const unsigned char s_hs_traffic[ sizeof("s hs traffic") - 1 ]; \ + const unsigned char s_ap_traffic[ sizeof("s ap traffic") - 1 ]; \ + const unsigned char s_e_traffic [ sizeof("s e traffic") - 1 ]; \ + const unsigned char exp_master [ sizeof("exp master") - 1 ]; \ + const unsigned char res_master [ sizeof("res master") - 1 ]; \ + const unsigned char ext_binder [ sizeof("ext binder") - 1 ]; \ + const unsigned char res_binder [ sizeof("res binder") - 1 ]; \ + const unsigned char derived [ sizeof("derived") - 1 ]; \ + +union mbedtls_ssl_tls1_3_labels_union +{ + MBEDTLS_SSL_TLS1_3_LABEL_LIST +}; +struct mbedtls_ssl_tls1_3_labels_struct +{ + MBEDTLS_SSL_TLS1_3_LABEL_LIST +}; +extern const struct mbedtls_ssl_tls1_3_labels_struct mbedtls_ssl_tls1_3_labels; + +#define MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( LABEL ) \ + mbedtls_ssl_tls1_3_labels.LABEL, \ + sizeof(mbedtls_ssl_tls1_3_labels.LABEL) + +#define MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_LABEL_LEN \ + sizeof( union mbedtls_ssl_tls1_3_labels_union ) + +/* The maximum length of HKDF contexts used in the TLS 1.3 standad. + * Since contexts are always hashes of message transcripts, this can + * be approximated from above by the maximum hash size. */ +#define MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_CONTEXT_LEN \ + MBEDTLS_MD_MAX_SIZE + +/* Maximum desired length for expanded key material generated + * by HKDF-Expand-Label. */ +#define MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_EXPANSION_LEN 255 + +/** + * \brief The \c HKDF-Expand-Label function from + * the TLS 1.3 standard RFC 8446. + * + * + * HKDF-Expand-Label( Secret, Label, Context, Length ) = + * HKDF-Expand( Secret, HkdfLabel, Length ) + * + * + * \param hash_alg The identifier for the hash algorithm to use. + * \param secret The \c Secret argument to \c HKDF-Expand-Label. + * This must be a readable buffer of length \p slen Bytes. + * \param slen The length of \p secret in Bytes. + * \param label The \c Label argument to \c HKDF-Expand-Label. + * This must be a readable buffer of length \p llen Bytes. + * \param llen The length of \p label in Bytes. + * \param ctx The \c Context argument to \c HKDF-Expand-Label. + * This must be a readable buffer of length \p clen Bytes. + * \param clen The length of \p context in Bytes. + * \param buf The destination buffer to hold the expanded secret. + * This must be a writable buffe of length \p blen Bytes. + * \param blen The desired size of the expanded secret in Bytes. + * + * \returns \c 0 on success. + * \return A negative error code on failure. + */ + +int mbedtls_ssl_tls1_3_hkdf_expand_label( + mbedtls_md_type_t hash_alg, + const unsigned char *secret, size_t slen, + const unsigned char *label, size_t llen, + const unsigned char *ctx, size_t clen, + unsigned char *buf, size_t blen ); + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#endif /* MBEDTLS_SSL_TLS1_3_KEYS_H */ diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj index 578289f17f..14d978ec62 100644 --- a/visualc/VS2010/mbedTLS.vcxproj +++ b/visualc/VS2010/mbedTLS.vcxproj @@ -247,6 +247,7 @@ + @@ -325,6 +326,7 @@ +