diff --git a/dtls.c b/dtls.c index eaf84426..2a03d464 100644 --- a/dtls.c +++ b/dtls.c @@ -123,7 +123,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 + 16 + 26 + 12 #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) @@ -558,25 +558,48 @@ static uint8 compression_methods[] = { TLS_COMPRESSION_NULL }; -/** returns true if the cipher matches TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 */ -static inline int is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(dtls_cipher_t cipher) +/** + * Get MAC length of cipher suite. + * \param cipher cipher suite + * \return MAC length of cipher. \c 0, if cipher is not supported. + */ +static inline int get_cipher_suite_mac_len(dtls_cipher_t cipher) +{ +#ifdef DTLS_ECC + if (cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8) { + return 8; + } else if (cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM) { + return 16; + } +#endif /* DTLS_ECC */ +#ifdef DTLS_PSK + if (cipher == TLS_PSK_WITH_AES_128_CCM_8) { + return 8; + } else if (cipher == TLS_PSK_WITH_AES_128_CCM) { + return 16; + } +#endif /* DTLS_PSK */ + return 0; +} + +/** returns true if the cipher matches TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 or TLS_ECDHE_ECDSA_WITH_AES_128_CCM */ +static inline int is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(dtls_cipher_t cipher) { #ifdef DTLS_ECC - return cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; + return cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 || cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM; #else (void) cipher; return 0; #endif /* DTLS_ECC */ } -/** returns true if the cipher matches TLS_PSK_WITH_AES_128_CCM_8 */ -static inline int is_tls_psk_with_aes_128_ccm_8(dtls_cipher_t cipher) +/** returns true if the cipher matches TLS_PSK_WITH_AES_128_CCM_8 or TLS_PSK_WITH_AES_128_CCM */ +static inline int is_tls_psk_with_aes_128_ccm_x(dtls_cipher_t cipher) { - (void) cipher; - #ifdef DTLS_PSK - return cipher == TLS_PSK_WITH_AES_128_CCM_8; + return cipher == TLS_PSK_WITH_AES_128_CCM_8 || cipher == TLS_PSK_WITH_AES_128_CCM; #else + (void) cipher; return 0; #endif /* DTLS_PSK */ } @@ -633,8 +656,8 @@ known_cipher(dtls_context_t *ctx, dtls_cipher_t code, int is_client) { psk = is_psk_supported(ctx); ecdsa = is_ecdsa_supported(ctx, is_client); - return (psk && is_tls_psk_with_aes_128_ccm_8(code)) || - (ecdsa && is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(code)); + return (psk && is_tls_psk_with_aes_128_ccm_x(code)) || + (ecdsa && is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(code)); } /** Dump out the cipher keys and IVs used for the symmetric cipher. */ @@ -744,6 +767,7 @@ calculate_key_block(dtls_context_t *ctx, switch (handshake->cipher) { #ifdef DTLS_PSK + case TLS_PSK_WITH_AES_128_CCM: case TLS_PSK_WITH_AES_128_CCM_8: { unsigned char psk[DTLS_PSK_MAX_KEY_LEN]; int len; @@ -773,6 +797,7 @@ calculate_key_block(dtls_context_t *ctx, } #endif /* DTLS_PSK */ #ifdef DTLS_ECC + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM: case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: { pre_master_len = dtls_ecdh_pre_master_secret(handshake->keyx.ecdsa.own_eph_priv, handshake->keyx.ecdsa.other_eph_pub_x, @@ -796,11 +821,13 @@ calculate_key_block(dtls_context_t *ctx, * default case as they do nothing but fall through. */ #ifndef DTLS_PSK + case TLS_PSK_WITH_AES_128_CCM: case TLS_PSK_WITH_AES_128_CCM_8: /* fall through to default */ #endif /* !DTLS_PSK */ #ifndef DTLS_ECC + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM: case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: /* fall through to default */ #endif /* !DTLS_ECC */ @@ -977,7 +1004,7 @@ dtls_check_tls_extension(dtls_peer_t *peer, if (data_length < sizeof(uint16)) { /* no tls extensions specified */ - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher)) { + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(handshake->cipher)) { goto error; } return 0; @@ -1060,16 +1087,17 @@ dtls_check_tls_extension(dtls_peer_t *peer, data += j; data_length -= j; } - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) && client_hello) { - if (!ext_elliptic_curve || !ext_client_cert_type || !ext_server_cert_type - || !ext_ec_point_formats) { - dtls_warn("not all required tls extensions found in client hello\n"); - goto error; - } - } else if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) && !client_hello) { - if (!ext_server_cert_type) { - dtls_warn("not all required tls extensions found in server hello\n"); - goto error; + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(handshake->cipher)) { + if (client_hello) { + if (!ext_elliptic_curve || !ext_client_cert_type || !ext_server_cert_type || !ext_ec_point_formats) { + dtls_warn("not all required tls extensions found in client hello\n"); + goto error; + } + } else { + if (!ext_server_cert_type) { + dtls_warn("not all required tls extensions found in server hello\n"); + goto error; + } } } return 0; @@ -1222,7 +1250,7 @@ check_client_keyexchange(dtls_context_t *ctx, (void) ctx; #ifdef DTLS_ECC - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher)) { + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(handshake->cipher)) { if (length < DTLS_HS_LENGTH + DTLS_CKXEC_LENGTH) { dtls_debug("The client key exchange is too short\n"); @@ -1252,7 +1280,7 @@ check_client_keyexchange(dtls_context_t *ctx, } #endif /* DTLS_ECC */ #ifdef DTLS_PSK - if (is_tls_psk_with_aes_128_ccm_8(handshake->cipher)) { + if (is_tls_psk_with_aes_128_ccm_x(handshake->cipher)) { int id_length; if (length < DTLS_HS_LENGTH + DTLS_CKXPSK_LENGTH_MIN) { @@ -1431,7 +1459,7 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, p += data_len_array[i]; res += data_len_array[i]; } - } else { /* TLS_PSK_WITH_AES_128_CCM_8 or TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 */ + } else { /* TLS_PSK_WITH_AES_128_CCM_8, TLS_PSK_WITH_AES_128_CCM, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 or TLS_ECDHE_ECDSA_WITH_AES_128_CCM */ /** * length of additional_data for the AEAD cipher which consists of * seq_num(2+6) + type(1) + version(2) + length(2) @@ -1439,16 +1467,19 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, #define A_DATA_LEN 13 unsigned char nonce[DTLS_CCM_BLOCKSIZE]; unsigned char A_DATA[A_DATA_LEN]; + uint8_t mac_len = get_cipher_suite_mac_len(security->cipher); /* For backwards-compatibility, dtls_encrypt_params is called with * M= and L=3. */ - const dtls_ccm_params_t params = { nonce, 8, 3 }; + const dtls_ccm_params_t params = { nonce, mac_len, 3 }; - if (is_tls_psk_with_aes_128_ccm_8(security->cipher)) { - dtls_debug("dtls_prepare_record(): encrypt using TLS_PSK_WITH_AES_128_CCM_8\n"); - } else if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(security->cipher)) { - dtls_debug("dtls_prepare_record(): encrypt using TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8\n"); + if (mac_len == 0) { + dtls_debug("dtls_prepare_record(): encrypt using unknown cipher\n"); } else { - dtls_debug("dtls_prepare_record(): encrypt using unknown cipher\n"); + if (is_tls_psk_with_aes_128_ccm_x(security->cipher)) { + dtls_debug("dtls_prepare_record(): encrypt using TLS_PSK_WITH_AES_128_CCM_%d\n", mac_len); + } else if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(security->cipher)) { + dtls_debug("dtls_prepare_record(): encrypt using TLS_ECDHE_ECDSA_WITH_AES_128_CCM_%d\n", mac_len); + } } /* set nonce @@ -2151,7 +2182,7 @@ check_client_certificate_verify(dtls_context_t *ctx, dtls_hash_ctx hs_hash; unsigned char sha256hash[DTLS_HMAC_DIGEST_SIZE]; - assert(is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(config->cipher)); + assert(is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(config->cipher)); data += DTLS_HS_LENGTH; data_length -= DTLS_HS_LENGTH; @@ -2202,7 +2233,7 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) uint8 extension_size; dtls_handshake_parameters_t *handshake = peer->handshake_params; - ecdsa = is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher); + ecdsa = is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(handshake->cipher); extension_size = (handshake->extended_master_secret ? 4 : 0) + (ecdsa ? 5 + 5 + 6 : 0); @@ -2537,7 +2568,7 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) } #ifdef DTLS_ECC - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) { + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(peer->handshake_params->cipher)) { const dtls_ecdsa_key_t *ecdsa_key; res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key); @@ -2560,7 +2591,7 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) return res; } - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher) && + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(peer->handshake_params->cipher) && is_ecdsa_client_auth_supported(ctx)) { res = dtls_send_server_certificate_request(ctx, peer); @@ -2573,7 +2604,7 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) #endif /* DTLS_ECC */ #ifdef DTLS_PSK - if (is_tls_psk_with_aes_128_ccm_8(peer->handshake_params->cipher)) { + if (is_tls_psk_with_aes_128_ccm_x(peer->handshake_params->cipher)) { unsigned char psk_hint[DTLS_PSK_MAX_CLIENT_IDENTITY_LEN]; int len; @@ -2628,6 +2659,7 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) memset(buf, 0, sizeof(buf)); switch (handshake->cipher) { #ifdef DTLS_PSK + case TLS_PSK_WITH_AES_128_CCM: case TLS_PSK_WITH_AES_128_CCM_8: { int len; @@ -2659,6 +2691,7 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) } #endif /* DTLS_PSK */ #ifdef DTLS_ECC + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM: case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: { uint8 *ephemeral_pub_x; uint8 *ephemeral_pub_y; @@ -2692,11 +2725,13 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) * default case as they do nothing but fall through. */ #ifndef DTLS_PSK + case TLS_PSK_WITH_AES_128_CCM: case TLS_PSK_WITH_AES_128_CCM_8: /* fall through to default */ #endif /* !DTLS_PSK */ #ifndef DTLS_ECC + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM: case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: /* fall through to default */ #endif /* !DTLS_ECC */ @@ -2801,7 +2836,7 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, psk = is_psk_supported(ctx); ecdsa = is_ecdsa_supported(ctx, 1); - cipher_size = 2 + ((ecdsa) ? 2 : 0) + ((psk) ? 2 : 0); + cipher_size = 2 + ((ecdsa) ? 4 : 0) + ((psk) ? 4 : 0); extension_size = 4 + ((ecdsa) ? 6 + 6 + 8 + 6 + 8: 0); if (cipher_size == 0) { @@ -2843,10 +2878,14 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, if (ecdsa) { dtls_int_to_uint16(p, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); p += sizeof(uint16); + dtls_int_to_uint16(p, TLS_ECDHE_ECDSA_WITH_AES_128_CCM); + p += sizeof(uint16); } if (psk) { dtls_int_to_uint16(p, TLS_PSK_WITH_AES_128_CCM_8); p += sizeof(uint16); + dtls_int_to_uint16(p, TLS_PSK_WITH_AES_128_CCM); + p += sizeof(uint16); } /* compression method */ @@ -3078,7 +3117,7 @@ check_server_certificate(dtls_context_t *ctx, update_hs_hash(peer, data, data_length); - assert(is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(config->cipher)); + assert(is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(config->cipher)); data += DTLS_HS_LENGTH; @@ -3129,7 +3168,7 @@ check_server_key_exchange_ecdsa(dtls_context_t *ctx, update_hs_hash(peer, data, data_length); - assert(is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(config->cipher)); + assert(is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(config->cipher)); data += DTLS_HS_LENGTH; data_length -= DTLS_HS_LENGTH; @@ -3216,7 +3255,7 @@ check_server_key_exchange_psk(dtls_context_t *ctx, update_hs_hash(peer, data, data_length); - assert(is_tls_psk_with_aes_128_ccm_8(config->cipher)); + assert(is_tls_psk_with_aes_128_ccm_x(config->cipher)); data += DTLS_HS_LENGTH; @@ -3260,7 +3299,7 @@ check_certificate_request(dtls_context_t *ctx, update_hs_hash(peer, data, data_length); - assert(is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)); + assert(is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(peer->handshake_params->cipher)); data += DTLS_HS_LENGTH; @@ -3427,7 +3466,7 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, if (security->cipher == TLS_NULL_WITH_NULL_NULL) { /* no cipher suite selected */ return clen; - } else { /* TLS_PSK_WITH_AES_128_CCM_8 or TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 */ + } else { /* TLS_PSK_WITH_AES_128_CCM_8, TLS_PSK_WITH_AES_128_CCM, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 or TLS_ECDHE_ECDSA_WITH_AES_128_CCM */ /** * length of additional_data for the AEAD cipher which consists of * seq_num(2+6) + type(1) + version(2) + length(2) @@ -3435,11 +3474,12 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, #define A_DATA_LEN 13 unsigned char nonce[DTLS_CCM_BLOCKSIZE]; unsigned char A_DATA[A_DATA_LEN]; + uint8_t mac_len = get_cipher_suite_mac_len(security->cipher); /* For backwards-compatibility, dtls_encrypt_params is called with * M= and L=3. */ - const dtls_ccm_params_t params = { nonce, 8, 3 }; + const dtls_ccm_params_t params = { nonce, mac_len, 3 }; - if (clen < 16) /* need at least IV and MAC */ + if (clen < 8 + mac_len) /* need at least IV and MAC */ return -1; memset(nonce, 0, DTLS_CCM_BLOCKSIZE); @@ -3464,7 +3504,7 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, memcpy(A_DATA, &DTLS_RECORD_HEADER(packet)->epoch, 8); /* epoch and seq_num */ memcpy(A_DATA + 8, &DTLS_RECORD_HEADER(packet)->content_type, 3); /* type and version */ - dtls_int_to_uint16(A_DATA + 11, clen - 8); /* length without MAC */ + dtls_int_to_uint16(A_DATA + 11, clen - mac_len); /* length without MAC */ clen = dtls_decrypt_params(¶ms, *cleartext, clen, *cleartext, dtls_kb_remote_write_key(security, peer->role), @@ -3563,7 +3603,7 @@ handle_verified_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, if (err < 0) { return err; } - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher) && + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(peer->handshake_params->cipher) && is_ecdsa_client_auth_supported(ctx)) peer->state = DTLS_STATE_WAIT_CLIENTCERTIFICATE; else @@ -3621,7 +3661,7 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, uint8 *data, size_t dtls_warn("error in check_server_hello err: %i\n", err); return err; } - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(peer->handshake_params->cipher)) peer->state = DTLS_STATE_WAIT_SERVERCERTIFICATE; else { peer->optional_handshake_message = DTLS_HT_SERVER_KEY_EXCHANGE; @@ -3659,7 +3699,7 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, uint8 *data, size_t } #ifdef DTLS_ECC - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) { + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(peer->handshake_params->cipher)) { if (state != DTLS_STATE_WAIT_SERVERKEYEXCHANGE) { return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); } @@ -3668,7 +3708,7 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, uint8 *data, size_t } #endif /* DTLS_ECC */ #ifdef DTLS_PSK - if (is_tls_psk_with_aes_128_ccm_8(peer->handshake_params->cipher)) { + if (is_tls_psk_with_aes_128_ccm_x(peer->handshake_params->cipher)) { if (state != DTLS_STATE_WAIT_SERVERHELLODONE || peer->optional_handshake_message != DTLS_HT_SERVER_KEY_EXCHANGE) { return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); } @@ -3707,7 +3747,7 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, uint8 *data, size_t if (state != DTLS_STATE_WAIT_SERVERHELLODONE || peer->optional_handshake_message != DTLS_HT_CERTIFICATE_REQUEST || - !is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) { + !is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(peer->handshake_params->cipher)) { return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); } peer->optional_handshake_message = DTLS_HT_NO_OPTIONAL_MESSAGE; @@ -3783,7 +3823,7 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, uint8 *data, size_t &peer->handshake_params->hs_state.hs_hash, sizeof(peer->handshake_params->hs_state.ext_hash)); - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher) && + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_x(peer->handshake_params->cipher) && is_ecdsa_client_auth_supported(ctx)) peer->state = DTLS_STATE_WAIT_CERTIFICATEVERIFY; else diff --git a/global.h b/global.h index 841392d9..ffc12167 100644 --- a/global.h +++ b/global.h @@ -74,7 +74,9 @@ typedef unsigned char uint48[6]; /** Known cipher suites.*/ typedef enum { TLS_NULL_WITH_NULL_NULL = 0x0000, /**< NULL cipher */ + TLS_PSK_WITH_AES_128_CCM = 0xC0A4, /**< see RFC 6655 */ TLS_PSK_WITH_AES_128_CCM_8 = 0xC0A8, /**< see RFC 6655 */ + TLS_ECDHE_ECDSA_WITH_AES_128_CCM = 0xC0AC, /**< see RFC 7251 */ TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = 0xC0AE /**< see RFC 7251 */ } dtls_cipher_t;