diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h index e00ffb5a9609..3f4647a0935f 100644 --- a/include/mbedtls/check_config.h +++ b/include/mbedtls/check_config.h @@ -839,6 +839,12 @@ #error "MBEDTLS_SSL_CID_OUT_LEN_MAX too large (max 255)" #endif +#if !defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) && \ + defined(MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT) +#error "MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT defined, but not all prerequsites" +#endif + + #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) && \ !defined(MBEDTLS_SSL_PROTO_TLS1_2) #error "MBEDTLS_SSL_ENCRYPT_THEN_MAC defined, but not all prerequisites" diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h index 990dc5851297..4b5a3131ec25 100644 --- a/include/mbedtls/mbedtls_config.h +++ b/include/mbedtls/mbedtls_config.h @@ -1320,9 +1320,7 @@ /** * \def MBEDTLS_SSL_DTLS_CONNECTION_ID * - * Enable support for the DTLS Connection ID extension - * (version draft-ietf-tls-dtls-connection-id-05, - * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05) + * Enable support for the DTLS Connection ID extension, * which allows to identify DTLS connections across changes * in the underlying transport. * @@ -1331,10 +1329,6 @@ * `mbedtls_ssl_conf_cid()`. See the corresponding documentation for * more information. * - * \warning The Connection ID extension is still in draft state. - * We make no stability promises for the availability - * or the shape of the API controlled by this option. - * * The maximum lengths of outgoing and incoming CIDs can be configured * through the options * - MBEDTLS_SSL_CID_OUT_LEN_MAX @@ -1344,7 +1338,23 @@ * * Uncomment to enable the Connection ID extension. */ -//#define MBEDTLS_SSL_DTLS_CONNECTION_ID +#define MBEDTLS_SSL_DTLS_CONNECTION_ID + + +/** + * \def MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT + * + * Defines whether RFC 9146 (default) or the legacy version + * (version draft-ietf-tls-dtls-connection-id-05, + * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05) + * is used. + * + * Set the value to 0 for the standard version, and + * 1 for the legacy draft version. + * + * Requires: MBEDTLS_SSL_DTLS_CONNECTION_ID + */ +#define MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT 0 /** * \def MBEDTLS_SSL_ASYNC_PRIVATE @@ -3539,17 +3549,6 @@ //#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ //#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ -/** \def MBEDTLS_TLS_EXT_CID - * - * At the time of writing, the CID extension has not been assigned its - * final value. Set this configuration option to make Mbed TLS use a - * different value. - * - * A future minor revision of Mbed TLS may change the default value of - * this option to match evolving standards and usage. - */ -//#define MBEDTLS_TLS_EXT_CID 254 - /** * Complete list of ciphersuites to use, in order of preference. * diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 3d820a525963..67d6118045cb 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -401,7 +401,13 @@ #define MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY 16 #endif -/** \} name SECTION: Module settings */ +/* + * Default to standard CID mode + */ +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) && \ + !defined(MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT) +#define MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT 0 +#endif /* * Length of the verify data for secure renegotiation @@ -571,15 +577,10 @@ #define MBEDTLS_TLS_EXT_SIG_ALG_CERT 50 /* RFC 8446 TLS 1.3 */ #define MBEDTLS_TLS_EXT_KEY_SHARE 51 /* RFC 8446 TLS 1.3 */ -/* The value of the CID extension is still TBD as of - * draft-ietf-tls-dtls-connection-id-05 - * (https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05). - * - * A future minor revision of Mbed TLS may change the default value of - * this option to match evolving standards and usage. - */ -#if !defined(MBEDTLS_TLS_EXT_CID) -#define MBEDTLS_TLS_EXT_CID 254 /* TBD */ +#if MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT == 0 +#define MBEDTLS_TLS_EXT_CID 54 /* RFC 9146 DTLS 1.2 CID */ +#else +#define MBEDTLS_TLS_EXT_CID 254 /* Pre-RFC 9146 DTLS 1.2 CID */ #endif #define MBEDTLS_TLS_EXT_ECJPAKE_KKPP 256 /* experimental */ @@ -2003,8 +2004,9 @@ void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl, * \brief Configure the use of the Connection ID (CID) * extension in the next handshake. * - * Reference: draft-ietf-tls-dtls-connection-id-05 + * Reference: RFC 9146 (or draft-ietf-tls-dtls-connection-id-05 * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05 + * for legacy version) * * The DTLS CID extension allows the reliable association of * DTLS records to DTLS connections across changes in the diff --git a/library/ssl_msg.c b/library/ssl_msg.c index dbef29b3f967..ecf7a2b4aa49 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -388,29 +388,79 @@ static int ssl_parse_inner_plaintext( unsigned char const *content, } #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID || MBEDTLS_SSL_PROTO_TLS1_3 */ -/* `add_data` must have size 13 Bytes if the CID extension is disabled, - * and 13 + 1 + CID-length Bytes if the CID extension is enabled. */ +/* The size of the `add_data` structure depends on various + * factors, namely + * + * 1) CID functionality disabled + * + * additional_data = + * 8: seq_num + + * 1: type + + * 2: version + + * 2: length of inner plaintext + + * + * size = 13 bytes + * + * 2) CID functionality based on RFC 9146 enabled + * + * size = 8 + 1 + 1 + 1 + 2 + 2 + 6 + 2 + CID-length + * = 23 + CID-length + * + * 3) CID functionality based on legacy CID version + according to draft-ietf-tls-dtls-connection-id-05 + * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05 + * + * size = 13 + 1 + CID-length + * + * More information about the CID usage: + * + * Per Section 5.3 of draft-ietf-tls-dtls-connection-id-05 the + * size of the additional data structure is calculated as: + * + * additional_data = + * 8: seq_num + + * 1: tls12_cid + + * 2: DTLSCipherText.version + + * n: cid + + * 1: cid_length + + * 2: length_of_DTLSInnerPlaintext + * + * Per RFC 9146 the size of the add_data structure is calculated as: + * + * additional_data = + * 8: seq_num_placeholder + + * 1: tls12_cid + + * 1: cid_length + + * 1: tls12_cid + + * 2: DTLSCiphertext.version + + * 2: epoch + + * 6: sequence_number + + * n: cid + + * 2: length_of_DTLSInnerPlaintext + * + */ static void ssl_extract_add_data_from_record( unsigned char* add_data, size_t *add_data_len, mbedtls_record *rec, mbedtls_ssl_protocol_version - tls_version, + tls_version, size_t taglen ) { - /* Quoting RFC 5246 (TLS 1.2): + /* Several types of ciphers have been defined for use with TLS and DTLS, + * and the MAC calculations for those ciphers differ slightly. Further + * variants were added when the CID functionality was added with RFC 9146. + * This implementations also considers the use of a legacy version of the + * CID specification published in draft-ietf-tls-dtls-connection-id-05, + * which is used in deployments. * - * additional_data = seq_num + TLSCompressed.type + - * TLSCompressed.version + TLSCompressed.length; + * We will distinguish between the non-CID and the CID cases below. * - * For the CID extension, this is extended as follows - * (quoting draft-ietf-tls-dtls-connection-id-05, - * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05): + * --- Non-CID cases --- * - * additional_data = seq_num + DTLSPlaintext.type + - * DTLSPlaintext.version + - * cid + - * cid_length + - * length_of_DTLSInnerPlaintext; + * Quoting RFC 5246 (TLS 1.2): + * + * additional_data = seq_num + TLSCompressed.type + + * TLSCompressed.version + TLSCompressed.length; * * For TLS 1.3, the record sequence number is dropped from the AAD * and encoded within the nonce of the AEAD operation instead. @@ -427,11 +477,72 @@ static void ssl_extract_add_data_from_record( unsigned char* add_data, * * TLSCiphertext.length = TLSInnerPlaintext.length + taglen. * - */ + * --- CID cases --- + * + * RFC 9146 uses a common pattern when constructing the data + * passed into a MAC / AEAD cipher. + * + * Data concatenation for MACs used with block ciphers with + * Encrypt-then-MAC Processing (with CID): + * + * data = seq_num_placeholder + + * tls12_cid + + * cid_length + + * tls12_cid + + * DTLSCiphertext.version + + * epoch + + * sequence_number + + * cid + + * DTLSCiphertext.length + + * IV + + * ENC(content + padding + padding_length) + * + * Data concatenation for MACs used with block ciphers (with CID): + * + * data = seq_num_placeholder + + * tls12_cid + + * cid_length + + * tls12_cid + + * DTLSCiphertext.version + + * epoch + + * sequence_number + + * cid + + * length_of_DTLSInnerPlaintext + + * DTLSInnerPlaintext.content + + * DTLSInnerPlaintext.real_type + + * DTLSInnerPlaintext.zeros + * + * AEAD ciphers use the following additional data calculation (with CIDs): + * + * additional_data = seq_num_placeholder + + * tls12_cid + + * cid_length + + * tls12_cid + + * DTLSCiphertext.version + + * epoch + + * sequence_number + + * cid + + * length_of_DTLSInnerPlaintext + * + * Section 5.3 of draft-ietf-tls-dtls-connection-id-05 (for legacy CID use) + * defines the additional data calculation as follows: + * + * additional_data = seq_num + + * tls12_cid + + * DTLSCipherText.version + + * cid + + * cid_length + + * length_of_DTLSInnerPlaintext + */ unsigned char *cur = add_data; size_t ad_len_field = rec->data_len; +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) && \ + MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT == 0 + const unsigned char seq_num_placeholder[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +#endif + #if defined(MBEDTLS_SSL_PROTO_TLS1_3) if( tls_version == MBEDTLS_SSL_VERSION_TLS1_3 ) { @@ -445,25 +556,78 @@ static void ssl_extract_add_data_from_record( unsigned char* add_data, { ((void) tls_version); ((void) taglen); - memcpy( cur, rec->ctr, sizeof( rec->ctr ) ); - cur += sizeof( rec->ctr ); + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + +#if MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT == 0 + if( rec->cid_len != 0 ) + { + // seq_num_placeholder + memcpy( cur, seq_num_placeholder, sizeof(seq_num_placeholder) ); + cur += sizeof( seq_num_placeholder ); + + // tls12_cid type + *cur = rec->type; + cur++; + + // cid_length + *cur = rec->cid_len; + cur++; + } + else + { + // epoch + sequence number + memcpy( cur, rec->ctr, sizeof( rec->ctr ) ); + cur += sizeof( rec->ctr ); + } +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT == 0 */ +#else + // epoch + sequence number + memcpy(cur, rec->ctr, sizeof(rec->ctr)); + cur += sizeof(rec->ctr); +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ } + // type *cur = rec->type; cur++; + // version memcpy( cur, rec->ver, sizeof( rec->ver ) ); cur += sizeof( rec->ver ); -#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) - if( rec->cid_len != 0 ) +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) && \ + MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT == 1 + + if (rec->cid_len != 0) { - memcpy( cur, rec->cid, rec->cid_len ); + // CID + memcpy(cur, rec->cid, rec->cid_len); cur += rec->cid_len; + // cid_length *cur = rec->cid_len; cur++; + // length of inner plaintext + MBEDTLS_PUT_UINT16_BE(ad_len_field, cur, 0); + cur += 2; + } + else +#elif defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) && \ + MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT == 0 + + if( rec->cid_len != 0 ) + { + // epoch + sequence number + memcpy(cur, rec->ctr, sizeof(rec->ctr)); + cur += sizeof(rec->ctr); + + // CID + memcpy( cur, rec->cid, rec->cid_len ); + cur += rec->cid_len; + + // length of inner plaintext MBEDTLS_PUT_UINT16_BE( ad_len_field, cur, 0 ); cur += 2; } @@ -538,7 +702,14 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, mbedtls_ssl_mode_t ssl_mode; int auth_done = 0; unsigned char * data; - unsigned char add_data[13 + 1 + MBEDTLS_SSL_CID_OUT_LEN_MAX ]; + /* For an explanation of the additional data length see + * the descrpition of ssl_extract_add_data_from_record(). + */ +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + unsigned char add_data[23 + MBEDTLS_SSL_CID_OUT_LEN_MAX]; +#else + unsigned char add_data[13]; +#endif size_t add_data_len; size_t post_avail; @@ -1021,13 +1192,7 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, size_t sign_mac_length = 0; #endif /* MBEDTLS_USE_PSA_CRYPTO */ - /* - * MAC(MAC_write_key, seq_num + - * TLSCipherText.type + - * TLSCipherText.version + - * length_of( (IV +) ENC(...) ) + - * IV + - * ENC(content + padding + padding_length)); + /* MAC(MAC_write_key, add_data, IV, ENC(content + padding + padding_length)) */ if( post_avail < transform->maclen) @@ -1133,7 +1298,14 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, size_t padlen = 0, correct = 1; #endif unsigned char* data; - unsigned char add_data[13 + 1 + MBEDTLS_SSL_CID_IN_LEN_MAX ]; + /* For an explanation of the additional data length see + * the descrpition of ssl_extract_add_data_from_record(). + */ +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + unsigned char add_data[23 + MBEDTLS_SSL_CID_IN_LEN_MAX]; +#else + unsigned char add_data[13]; +#endif size_t add_data_len; #if !defined(MBEDTLS_DEBUG_C) @@ -3487,7 +3659,7 @@ static int ssl_parse_record_header( mbedtls_ssl_context const *ssl, { /* Shift pointers to account for record header including CID * struct { - * ContentType special_type = tls12_cid; + * ContentType outer_type = tls12_cid; * ProtocolVersion version; * uint16 epoch; * uint48 sequence_number; diff --git a/library/ssl_tls12_client.c b/library/ssl_tls12_client.c index f8140945da79..79f34d3457dd 100644 --- a/library/ssl_tls12_client.c +++ b/library/ssl_tls12_client.c @@ -235,9 +235,6 @@ static int ssl_write_cid_ext( mbedtls_ssl_context *ssl, size_t ext_len; /* - * Quoting draft-ietf-tls-dtls-connection-id-05 - * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05 - * * struct { * opaque cid<0..2^8-1>; * } ConnectionId; diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c index eab27768bc4b..8d1923879f71 100644 --- a/library/ssl_tls12_server.c +++ b/library/ssl_tls12_server.c @@ -358,9 +358,6 @@ static int ssl_parse_cid_ext( mbedtls_ssl_context *ssl, } /* - * Quoting draft-ietf-tls-dtls-connection-id-05 - * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05 - * * struct { * opaque cid<0..2^8-1>; * } ConnectionId; @@ -1748,9 +1745,6 @@ static void ssl_write_cid_ext( mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding CID extension" ) ); /* - * Quoting draft-ietf-tls-dtls-connection-id-05 - * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05 - * * struct { * opaque cid<0..2^8-1>; * } ConnectionId; diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index 7f259f57dc9a..e89108eb9fb2 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -2449,6 +2449,25 @@ component_test_variable_ssl_in_out_buffer_len_CID () { tests/compat.sh } +component_test_variable_ssl_in_out_buffer_len_CID_legacy () { + msg "build: MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_DTLS_CONNECTION_ID (legacy) enabled (ASan build)" + scripts/config.py set MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH + scripts/config.py set MBEDTLS_SSL_DTLS_CONNECTION_ID + scripts/config.py set MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT 1 + + CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan . + make + + msg "test: MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_DTLS_CONNECTION_ID" + make test + + msg "test: ssl-opt.sh, MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_DTLS_CONNECTION_ID enabled" + tests/ssl-opt.sh + + msg "test: compat.sh, MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_DTLS_CONNECTION_ID enabled" + tests/compat.sh +} + component_test_ssl_alloc_buffer_and_mfl () { msg "build: default config with memory buffer allocator and MFL extension" scripts/config.py set MBEDTLS_MEMORY_BUFFER_ALLOC_C diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index c4628b017e2b..36cb479d51a3 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -440,6 +440,14 @@ requires_max_content_len() { requires_config_value_at_least "MBEDTLS_SSL_OUT_CONTENT_LEN" $1 } +CID_MODE=$( get_config_value_or_default "MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT" ) + +requires_cid_compat() { + if [ "$CID_MODE" = "0" ]; then + SKIP_NEXT="YES" + fi +} + # skip next test if GnuTLS isn't available requires_gnutls() { if [ -z "${GNUTLS_AVAILABLE:-}" ]; then @@ -2386,6 +2394,17 @@ run_test "Context serialization, client serializes, with CID" \ -S "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 +requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_cid_compat +run_test "Context serialization, client serializes, with CID (legacy)" \ + "$P_SRV dtls=1 serialize=0 exchanges=2 cid=1 cid_val=dead" \ + "$P_CLI dtls=1 serialize=1 exchanges=2 cid=1 cid_val=beef" \ + 0 \ + -c "Deserializing connection..." \ + -S "Deserializing connection..." + + requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION run_test "Context serialization, server serializes, CCM" \ "$P_SRV dtls=1 serialize=1 exchanges=2" \ @@ -2422,6 +2441,16 @@ run_test "Context serialization, server serializes, with CID" \ -C "Deserializing connection..." \ -s "Deserializing connection..." +requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_cid_compat +run_test "Context serialization, server serializes, with CID (legacy)" \ + "$P_SRV dtls=1 serialize=1 exchanges=2 cid=1 cid_val=dead" \ + "$P_CLI dtls=1 serialize=0 exchanges=2 cid=1 cid_val=beef" \ + 0 \ + -C "Deserializing connection..." \ + -s "Deserializing connection..." + requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION run_test "Context serialization, both serialize, CCM" \ @@ -2460,6 +2489,17 @@ run_test "Context serialization, both serialize, with CID" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 +requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_cid_compat +run_test "Context serialization, both serialize, with CID (legacy)" \ + "$P_SRV dtls=1 serialize=1 exchanges=2 cid=1 cid_val=dead" \ + "$P_CLI dtls=1 serialize=1 exchanges=2 cid=1 cid_val=beef" \ + 0 \ + -c "Deserializing connection..." \ + -s "Deserializing connection..." + + requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION run_test "Context serialization, re-init, client serializes, CCM" \ "$P_SRV dtls=1 serialize=0 exchanges=2" \ @@ -2497,6 +2537,16 @@ run_test "Context serialization, re-init, client serializes, with CID" \ -S "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2 +requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_cid_compat +run_test "Context serialization, re-init, client serializes, with CID (legacy)" \ + "$P_SRV dtls=1 serialize=0 exchanges=2 cid=1 cid_val=dead" \ + "$P_CLI dtls=1 serialize=2 exchanges=2 cid=1 cid_val=beef" \ + 0 \ + -c "Deserializing connection..." \ + -S "Deserializing connection..." + requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION run_test "Context serialization, re-init, server serializes, CCM" \ "$P_SRV dtls=1 serialize=2 exchanges=2" \