From 336ae9c69b5bc9ad8c76f907069624058afe2441 Mon Sep 17 00:00:00 2001 From: Achim Kraus Date: Thu, 18 Nov 2021 21:50:52 +0100 Subject: [PATCH] Add client dtls connection ID. Simple client side implementation indicates support and uses the cid of the server, when negotiated by that. Signed-off-by: Achim Kraus --- crypto.h | 20 ++++++- dtls.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++------ dtls.h | 19 ++++++ global.h | 2 + 4 files changed, 198 insertions(+), 18 deletions(-) diff --git a/crypto.h b/crypto.h index 9bf17458..1f5dcc07 100644 --- a/crypto.h +++ b/crypto.h @@ -96,6 +96,11 @@ typedef struct { uint64_t bitfield; } seqnum_t; +/* Maximum CID length. */ +#ifndef DTLS_MAX_CID_LENGTH +#define DTLS_MAX_CID_LENGTH 16 +#endif + typedef struct { dtls_compression_t compression; /**< compression method */ @@ -110,7 +115,12 @@ typedef struct { * access the components of the key block. */ uint8 key_block[MAX_KEYBLOCK_LENGTH]; - + +#if (DTLS_MAX_CID_LENGTH > 0) + uint8_t write_cid[DTLS_MAX_CID_LENGTH]; + uint8_t write_cid_length; +#endif /* DTLS_MAX_CID_LENGTH > 0 */ + seqnum_t cseq; /** 0) + uint8_t write_cid[DTLS_MAX_CID_LENGTH]; + uint8_t write_cid_length; + + unsigned int use_connection_id:1; +#endif /* DTLS_MAX_CID_LENGTH > 0 */ + unsigned int do_client_auth:1; unsigned int extended_master_secret:1; union { diff --git a/dtls.c b/dtls.c index c10e3e61..5e7c274e 100644 --- a/dtls.c +++ b/dtls.c @@ -112,7 +112,7 @@ memarray_t dtlscontext_storage; #define DTLS_HS_LENGTH sizeof(dtls_handshake_header_t) #define DTLS_CH_LENGTH sizeof(dtls_client_hello_t) /* no variable length fields! */ #define DTLS_COOKIE_LENGTH_MAX 32 -#define DTLS_CH_LENGTH_MAX sizeof(dtls_client_hello_t) + DTLS_COOKIE_LENGTH_MAX + 12 + 26 + 12 +#define DTLS_CH_LENGTH_MAX sizeof(dtls_client_hello_t) + DTLS_COOKIE_LENGTH_MAX + 12 + 43 #define DTLS_HV_LENGTH sizeof(dtls_hello_verify_t) #define DTLS_SH_LENGTH (2 + DTLS_RANDOM_LENGTH + 1 + 2 + 1) #define DTLS_SKEXEC_LENGTH (1 + 2 + 1 + 1 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE + 1 + 1 + 2 + 70) @@ -841,6 +841,10 @@ calculate_key_block(dtls_context_t *ctx, security->cipher = handshake->cipher; security->compression = handshake->compression; security->rseq = 0; +#if (DTLS_MAX_CID_LENGTH > 0) + security->write_cid_length = handshake->write_cid_length; + memcpy(security->write_cid, handshake->write_cid, handshake->write_cid_length); +#endif /* DTLS_MAX_CID_LENGTH > 0 */ return 0; } @@ -945,6 +949,35 @@ static int verify_ext_sig_hash_algo(uint8 *data, size_t data_length) { return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); } +#if (DTLS_MAX_CID_LENGTH > 0) + +static int get_ext_connection_id(dtls_handshake_parameters_t *handshake, uint8 *data, size_t data_length) { + if (sizeof(uint8) > data_length) { + dtls_warn("invalid length (%d) for extension connection id\n", data_length); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + + /* length of the connection id */ + uint8_t i = dtls_uint8_to_int(data); + data += sizeof(uint8); + if (i + sizeof(uint8) != data_length) { + dtls_warn("invalid connection id length (%d)\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + + if (DTLS_MAX_CID_LENGTH < i) { + dtls_warn("connection id length (%d) exceeds maximum (%d)!\n", i, DTLS_MAX_CID_LENGTH); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + + handshake->write_cid_length = i; + memcpy(handshake->write_cid, data, i); + + return 0; +} + +#endif /* DTLS_MAX_CID_LENGTH > 0*/ + /* * Check for some TLS Extensions used by the ECDHE_ECDSA cipher. */ @@ -1037,6 +1070,12 @@ dtls_check_tls_extension(dtls_peer_t *peer, if (verify_ext_sig_hash_algo(data, j)) goto error; break; +#if (DTLS_MAX_CID_LENGTH > 0) + case TLS_EXT_CONNECTION_ID: + if (!handshake->use_connection_id || get_ext_connection_id(handshake, data, j)) + goto error; + break; +#endif /* DTLS_MAX_CID_LENGTH */ default: dtls_warn("unsupported tls extension: %i\n", i); break; @@ -1373,9 +1412,10 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, uint8 *data_array[], size_t data_len_array[], size_t data_array_len, uint8 *sendbuf, size_t *rlen) { - uint8 *p, *start; + uint8 *p; int res; unsigned int i; + uint8_t cid_length = 0; if (*rlen < DTLS_RH_LENGTH) { dtls_alert("The sendbuf (%zu bytes) is too small\n", *rlen); @@ -1388,7 +1428,6 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, } p = dtls_set_record_header(type, security->epoch, &(security->rseq), sendbuf); - start = p; if (security->cipher == TLS_NULL_WITH_NULL_NULL) { /* no cipher suite */ @@ -1407,12 +1446,28 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, } } else { /* TLS_PSK_WITH_AES_128_CCM_8 or TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 */ /** + * RFC6347 * length of additional_data for the AEAD cipher which consists of * seq_num(2+6) + type(1) + version(2) + length(2) */ #define A_DATA_LEN 13 + +#if (DTLS_MAX_CID_LENGTH > 0) + /** + * RFC9146 + * length of extra additional_data for the AEAD cipher which consists of + * seq_num_placeholder(8) + type(1) + cid_length(1) + */ +#define A_DATA_CID_EXTRA_LEN 10 +#define A_DATA_MAX_LEN (A_DATA_LEN + A_DATA_CID_EXTRA_LEN + DTLS_MAX_CID_LENGTH) +#else +#define A_DATA_MAX_LEN A_DATA_LEN +#endif + + uint8 *start = p; unsigned char nonce[DTLS_CCM_BLOCKSIZE]; - unsigned char A_DATA[A_DATA_LEN]; + unsigned char A_DATA[A_DATA_MAX_LEN]; + uint8_t a_data_len = A_DATA_LEN; /* For backwards-compatibility, dtls_encrypt_params is called with * M= and L=3. */ const dtls_ccm_params_t params = { nonce, 8, 3 }; @@ -1425,6 +1480,16 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, dtls_debug("dtls_prepare_record(): encrypt using unknown cipher\n"); } +#if (DTLS_MAX_CID_LENGTH > 0) + cid_length = security->write_cid_length; + if (cid_length > 0) { + /* add cid to record header */ + memcpy(p - sizeof(uint16_t), security->write_cid, cid_length); + p += cid_length; + start = p; + } +#endif /* DTLS_MAX_CID_LENGTH > 0 */ + /* set nonce from RFC 6655: The "nonce" input to the AEAD algorithm is exactly that of [RFC5288]: @@ -1490,31 +1555,62 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, dtls_debug_dump("key:", dtls_kb_local_write_key(security, peer->role), dtls_kb_key_size(security, peer->role)); - /* re-use N to create additional data according to RFC 5246, Section 6.2.3.3: - * - * additional_data = seq_num + TLSCompressed.type + - * TLSCompressed.version + TLSCompressed.length; - */ - memcpy(A_DATA, &DTLS_RECORD_HEADER(sendbuf)->epoch, 8); /* epoch and seq_num */ - memcpy(A_DATA + 8, &DTLS_RECORD_HEADER(sendbuf)->content_type, 3); /* type and version */ - dtls_int_to_uint16(A_DATA + 11, res - 8); /* length */ +#if (DTLS_MAX_CID_LENGTH > 0) + if (cid_length > 0) { + /* RFC 9146 */ + + /* inner content type */ + *p = *sendbuf; + *sendbuf = DTLS_CT_TLS12_CID; + p += sizeof(uint8_t); + res += sizeof(uint8_t); + + /* seq_num_placeholder: 8x 0xff */ + memset(A_DATA, 0xff, 8); + /* tls_cid: 25 */ + A_DATA[8] = DTLS_CT_TLS12_CID; + /* cid length */ + A_DATA[9] = cid_length; + /* copy record header */ + memcpy(A_DATA + A_DATA_CID_EXTRA_LEN, sendbuf, A_DATA_LEN + cid_length); + dtls_int_to_uint16(A_DATA + A_DATA_CID_EXTRA_LEN + 11 + cid_length, res - 8); /* length */ + a_data_len = A_DATA_LEN + A_DATA_CID_EXTRA_LEN + cid_length; + + } else { +#endif /* DTLS_MAX_CID_LENGTH > 0 */ + /* RFC 6347 */ + /* re-use N to create additional data according to RFC 5246, Section 6.2.3.3: + * + * additional_data = seq_num + TLSCompressed.type + + * TLSCompressed.version + TLSCompressed.length; + */ + memcpy(A_DATA, &DTLS_RECORD_HEADER(sendbuf)->epoch, 8); /* epoch and seq_num */ + memcpy(A_DATA + 8, &DTLS_RECORD_HEADER(sendbuf)->content_type, 3); /* type and version */ + dtls_int_to_uint16(A_DATA + 11, res - 8); /* length */ + a_data_len = A_DATA_LEN; +#if (DTLS_MAX_CID_LENGTH > 0) + } +#endif /* DTLS_MAX_CID_LENGTH > 0 */ + + dtls_debug_dump("adata:", A_DATA, a_data_len); + dtls_debug_dump("message:", start, res); res = dtls_encrypt_params(¶ms, start + 8, res - 8, start + 8, dtls_kb_local_write_key(security, peer->role), dtls_kb_key_size(security, peer->role), - A_DATA, A_DATA_LEN); + A_DATA, a_data_len); if (res < 0) return res; res += 8; /* increment res by size of nonce_explicit */ - dtls_debug_dump("message:", start, res); + dtls_debug_dump("encrypted-message:", start, res); } /* fix length of fragment in sendbuf */ - dtls_int_to_uint16(sendbuf + 11, res); + dtls_int_to_uint16(sendbuf + 11 + cid_length, res); - *rlen = DTLS_RH_LENGTH + res; + *rlen = DTLS_RH_LENGTH + res + cid_length; return 0; } @@ -2718,7 +2814,35 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, ecdsa = is_ecdsa_supported(ctx, 1); cipher_size = 2 + ((ecdsa) ? 2 : 0) + ((psk) ? 2 : 0); - extension_size = 4 + ((ecdsa) ? 6 + 6 + 8 + 6 + 8: 0); + /* + * session_length := 1 byte + * session := 0 bytes + * cookie_length := 1 byte + * cookie := n bytes + * cipher suites (max) := 6 bytes + * compression := 2 bytes + * extensions_length := 2 bytes => 12 + * + * client_cert_type := 6 bytes + * server_cert_type := 6 bytes + * ec curves := 8 bytes + * ec point format := 6 bytes => 26 + * sign. and hash algos := 8 bytes + * extended master secret := 4 bytes => 12 + * connection id, empty := 5 bytes + * => 26 + 12 + 5 := 43 + */ + extension_size = ((ecdsa) ? 6 + 6 + 8 + 6 + 8 : 0) + 4; + +#if (DTLS_MAX_CID_LENGTH > 0) + handshake->use_connection_id = DTLS_USE_CID_DEFAULT; + if (ctx && ctx->h && ctx->h->use_cid) { + handshake->use_connection_id = ctx->h->use_cid(ctx, &peer->session); + } + if (handshake->use_connection_id) { + extension_size += 5; + } +#endif /* DTLS_MAX_CID_LENGTH > 0 */ if (cipher_size == 0) { dtls_crit("no cipher callbacks implemented\n"); @@ -2869,8 +2993,25 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, /* length of this extension type */ dtls_int_to_uint16(p, 0); p += sizeof(uint16); + handshake->extended_master_secret = 1; +#if (DTLS_MAX_CID_LENGTH > 0) + if (handshake->use_connection_id) { + /* connection id, empty to indicate support */ + dtls_int_to_uint16(p, TLS_EXT_CONNECTION_ID); + p += sizeof(uint16); + + /* length of this extension type */ + dtls_int_to_uint16(p, sizeof(uint8)); + p += sizeof(uint16); + + /* empty cid, indicating support for cid extension */ + dtls_int_to_uint8(p, 0); + p += sizeof(uint8); + } +#endif /* DTLS_MAX_CID_LENGTH > 0 */ + handshake->hs_state.read_epoch = dtls_security_params(peer)->epoch; assert((buf <= p) && ((unsigned int)(p - buf) <= sizeof(buf))); diff --git a/dtls.h b/dtls.h index 16bf2594..d9e2c200 100644 --- a/dtls.h +++ b/dtls.h @@ -46,6 +46,12 @@ #define DTLS_VERSION 0xfefd /* DTLS v1.2 */ #endif +#if (DTLS_MAX_CID_LENGTH > 0) +#ifndef DTLS_USE_CID_DEFAULT +#define DTLS_USE_CID_DEFAULT 1 +#endif /* DTLS_USE_CID_DEFAULT */ +#endif /* DTLS_MAX_CID_LENGTH > 0 */ + typedef enum dtls_credentials_type_t { DTLS_PSK_HINT, DTLS_PSK_IDENTITY, DTLS_PSK_KEY } dtls_credentials_type_t; @@ -119,6 +125,18 @@ typedef struct { int (*event)(struct dtls_context_t *ctx, session_t *session, dtls_alert_level_t level, unsigned short code); +#if (DTLS_MAX_CID_LENGTH > 0) + /** + * Called during handshake to check, if cid is to be used. + * If callback is NULL, DTLS_USE_CID_DEFAULT is used instead + * + * @param ctx The current dtls context. + * @param session The session where cid will be used. + * @return 0, cid not used, 1 cid used. + */ + int (*use_cid)(struct dtls_context_t *ctx, session_t *session); +#endif /* DTLS_MAX_CID_LENGTH > 0 */ + #ifdef DTLS_PSK /** * Called during handshake to get information related to the @@ -323,6 +341,7 @@ void dtls_check_retransmit(dtls_context_t *context, clock_time_t *next); #define DTLS_CT_ALERT 21 #define DTLS_CT_HANDSHAKE 22 #define DTLS_CT_APPLICATION_DATA 23 +#define DTLS_CT_TLS12_CID 25 /** Generic header structure of the DTLS record layer. */ typedef struct __attribute__((__packed__)) { diff --git a/global.h b/global.h index 87153df3..ddbadda9 100644 --- a/global.h +++ b/global.h @@ -81,6 +81,8 @@ typedef enum { #define TLS_EXT_SERVER_CERTIFICATE_TYPE 20 /* see RFC 7250 */ #define TLS_EXT_ENCRYPT_THEN_MAC 22 /* see RFC 7366 */ #define TLS_EXT_EXTENDED_MASTER_SECRET 23 /* see RFC 7627 */ +#define TLS_EXT_CONNECTION_ID 54 /* see RFC 9146 */ + #define TLS_CERT_TYPE_RAW_PUBLIC_KEY 2 /* see RFC 7250 */