diff --git a/crypto.c b/crypto.c index cdadfddf..02b4c723 100644 --- a/crypto.c +++ b/crypto.c @@ -186,7 +186,7 @@ dtls_security_parameters_t *dtls_security_new(void) memset(security, 0, sizeof(*security)); if (security) { - security->cipher = TLS_NULL_WITH_NULL_NULL; + security->cipher_index = DTLS_CIPHER_INDEX_NULL; security->compression = TLS_COMPRESSION_NULL; } return security; diff --git a/crypto.h b/crypto.h index 5df6047a..04b11709 100644 --- a/crypto.h +++ b/crypto.h @@ -49,6 +49,8 @@ #define DTLS_MASTER_SECRET_LENGTH 48 #define DTLS_RANDOM_LENGTH 32 +#define DTLS_CIPHER_INDEX_NULL 0 + typedef enum { AES128=0 } dtls_crypto_alg; @@ -105,7 +107,7 @@ typedef struct { typedef struct { dtls_compression_t compression; /**< compression method */ - dtls_cipher_t cipher; /**< cipher type */ + int cipher_index; /**< internal index for cipher_suite_params, DTLS_CIPHER_INDEX_NULL for TLS_NULL_WITH_NULL_NULL */ uint16_t epoch; /**< counter for cipher state changes*/ uint64_t rseq; /**< sequence number of last record sent */ @@ -135,7 +137,7 @@ typedef struct { dtls_hs_state_t hs_state; /**< handshake protocol status */ dtls_compression_t compression; /**< compression method */ - dtls_cipher_t cipher; /**< cipher type */ + int cipher_index; /**< internal index for cipher_suite_params, DTLS_CIPHER_INDEX_NULL for TLS_NULL_WITH_NULL_NULL */ unsigned int do_client_auth:1; unsigned int extended_master_secret:1; union { diff --git a/dtls.c b/dtls.c index e42a30fd..9374f0ba 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 + 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) @@ -541,27 +541,73 @@ 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) -{ +typedef enum { + DTLS_KEY_EXCHANGE_NONE, + DTLS_KEY_EXCHANGE_PSK, + DTLS_KEY_EXCHANGE_ECDHE_ECDSA +} cipher_suite_key_exchange_algorithm_t; + +typedef struct cipher_suite_param_t { + dtls_cipher_t cipher_suite; + uint8_t mac_length; + cipher_suite_key_exchange_algorithm_t key_exchange_algorithm; +} cipher_suite_param_t; + +static const struct cipher_suite_param_t cipher_suite_params[] = { + { TLS_NULL_WITH_NULL_NULL, 0, DTLS_KEY_EXCHANGE_NONE }, +#ifdef DTLS_PSK + { TLS_PSK_WITH_AES_128_CCM_8, 8, DTLS_KEY_EXCHANGE_PSK }, + { TLS_PSK_WITH_AES_128_CCM, 16, DTLS_KEY_EXCHANGE_PSK }, +#endif /* DTLS_PSK */ #ifdef DTLS_ECC - return cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; -#else - (void) cipher; - return 0; + { TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, 8, DTLS_KEY_EXCHANGE_ECDHE_ECDSA }, + { TLS_ECDHE_ECDSA_WITH_AES_128_CCM, 16, DTLS_KEY_EXCHANGE_ECDHE_ECDSA }, #endif /* DTLS_ECC */ + }; + +static const int last_cipher_suite_param = sizeof(cipher_suite_params) / sizeof(cipher_suite_param_t); + +static inline int get_cipher_index(dtls_cipher_t cipher) +{ + for (int index = 0; index < last_cipher_suite_param ; ++index) { + if (cipher_suite_params[index].cipher_suite == cipher) { + return index; + } + } + return 0; } -/** 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) +/** + * Get cipher suite. + * \param cipher_index index to cipher suite params + * \return cipher suite. + */ +static inline dtls_cipher_t get_cipher_suite(int cipher_index) { - (void) cipher; + assert(0 <= cipher_index && cipher_index < last_cipher_suite_param); + return cipher_suite_params[cipher_index].cipher_suite; +} -#ifdef DTLS_PSK - return cipher == TLS_PSK_WITH_AES_128_CCM_8; -#else - return 0; -#endif /* DTLS_PSK */ +/** + * Get key exchange algorithm of ciphher suite. + * \param cipher_index index to cipher suite params + * \return key exchange algorithm. \c DTLS_KEY_EXCHANGE_NONE, if cipher is not supported. + */ +static inline cipher_suite_key_exchange_algorithm_t get_key_exchange_algorithm(int cipher_index) +{ + assert(0 <= cipher_index && cipher_index < last_cipher_suite_param); + return cipher_suite_params[cipher_index].key_exchange_algorithm; +} + +/** + * Get MAC length of cipher suite. + * \param cipher_index index to cipher suite params + * \return MAC length of cipher. \c 0, if cipher is not supported. + */ +static inline int get_cipher_suite_mac_len(int cipher_index) +{ + assert(0 <= cipher_index && cipher_index < last_cipher_suite_param); + return cipher_suite_params[cipher_index].mac_length; } /** returns true if the application is configured for psk */ @@ -605,19 +651,18 @@ static inline int is_ecdsa_client_auth_supported(dtls_context_t *ctx) * TLS_NULL_WITH_NULL_NULL that we recognize. * * @param ctx The current DTLS context - * @param code The cipher suite identifier to check + * @param cipher_index The index to cipher suite params to check * @param is_client 1 for a dtls client, 0 for server * @return @c 1 iff @p code is recognized, */ static int -known_cipher(dtls_context_t *ctx, dtls_cipher_t code, int is_client) { - int psk; - int ecdsa; +known_cipher(dtls_context_t *ctx, int cipher_index, int is_client) { + const int psk = is_psk_supported(ctx); + const int ecdsa = is_ecdsa_supported(ctx, is_client); + const cipher_suite_key_exchange_algorithm_t key_exchange_algorithm = get_key_exchange_algorithm(cipher_index); - 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 && key_exchange_algorithm == DTLS_KEY_EXCHANGE_PSK) || + (ecdsa && key_exchange_algorithm == DTLS_KEY_EXCHANGE_ECDHE_ECDSA); } /** Dump out the cipher keys and IVs used for the symmetric cipher. */ @@ -724,73 +769,62 @@ calculate_key_block(dtls_context_t *ctx, } pre_master_secret = security->key_block; - - switch (handshake->cipher) { + switch (get_key_exchange_algorithm(handshake->cipher_index)) { + case DTLS_KEY_EXCHANGE_PSK: #ifdef DTLS_PSK - case TLS_PSK_WITH_AES_128_CCM_8: { - unsigned char psk[DTLS_PSK_MAX_KEY_LEN]; - int len; - - len = CALL(ctx, get_psk_info, session, DTLS_PSK_KEY, - handshake->keyx.psk.identity, - handshake->keyx.psk.id_length, - psk, DTLS_PSK_MAX_KEY_LEN); - if (len < 0) { - dtls_crit("no psk key for session available\n"); - return len; - } - /* Temporarily use the key_block storage space for the pre master secret. */ - pre_master_len = dtls_psk_pre_master_secret(psk, len, - pre_master_secret, - MAX_KEYBLOCK_LENGTH); + { + unsigned char psk[DTLS_PSK_MAX_KEY_LEN]; + int len; + + len = CALL(ctx, get_psk_info, session, DTLS_PSK_KEY, + handshake->keyx.psk.identity, + handshake->keyx.psk.id_length, + psk, DTLS_PSK_MAX_KEY_LEN); + if (len < 0) { + dtls_crit("no psk key for session available\n"); + return len; + } + /* Temporarily use the key_block storage space for the pre master secret. */ + pre_master_len = dtls_psk_pre_master_secret(psk, len, + pre_master_secret, + MAX_KEYBLOCK_LENGTH); - dtls_debug_hexdump("psk", psk, len); + dtls_debug_hexdump("psk", psk, len); - memset(psk, 0, DTLS_PSK_MAX_KEY_LEN); - if (pre_master_len < 0) { - dtls_crit("the psk was too long, for the pre master secret\n"); - return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + memset(psk, 0, DTLS_PSK_MAX_KEY_LEN); + if (pre_master_len < 0) { + dtls_crit("the psk was too long, for the pre master secret\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + break; } - - break; - } +#else /* DTLS_PSK */ + dtls_crit("calculate_key_block: PSK not supported!\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); #endif /* DTLS_PSK */ + case DTLS_KEY_EXCHANGE_ECDHE_ECDSA: #ifdef DTLS_ECC - 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, - handshake->keyx.ecdsa.other_eph_pub_y, - sizeof(handshake->keyx.ecdsa.own_eph_priv), - pre_master_secret, - MAX_KEYBLOCK_LENGTH); - if (pre_master_len < 0) { - dtls_crit("the curve was too long, for the pre master secret\n"); - return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + { + pre_master_len = dtls_ecdh_pre_master_secret(handshake->keyx.ecdsa.own_eph_priv, + handshake->keyx.ecdsa.other_eph_pub_x, + handshake->keyx.ecdsa.other_eph_pub_y, + sizeof(handshake->keyx.ecdsa.own_eph_priv), + pre_master_secret, + MAX_KEYBLOCK_LENGTH); + if (pre_master_len < 0) { + dtls_crit("the curve was too long, for the pre master secret\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + break; } - break; - } +#else /* DTLS_ECC */ + dtls_crit("calculate_key_block: ECC not supported!\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); #endif /* DTLS_ECC */ - case TLS_NULL_WITH_NULL_NULL: - assert(!"calculate_key_block: tried to use NULL cipher\n"); - return dtls_alert_fatal_create(DTLS_ALERT_INSUFFICIENT_SECURITY); - - /* The following cases cover the enum symbols that are not - * included in this build. These must be kept just above the - * default case as they do nothing but fall through. - */ -#ifndef DTLS_PSK - 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_8: - /* fall through to default */ -#endif /* !DTLS_ECC */ - + case DTLS_KEY_EXCHANGE_NONE: default: - dtls_crit("calculate_key_block: unknown cipher %04x\n", handshake->cipher); - return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + assert(!"calculate_key_block: not supported key exchange algorithm\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INSUFFICIENT_SECURITY); } dtls_debug_dump("client_random", handshake->tmp.random.client, DTLS_RANDOM_LENGTH); @@ -837,7 +871,7 @@ calculate_key_block(dtls_context_t *ctx, memcpy(handshake->tmp.master_secret, master_secret, DTLS_MASTER_SECRET_LENGTH); dtls_debug_keyblock(security); - security->cipher = handshake->cipher; + security->cipher_index = handshake->cipher_index; security->compression = handshake->compression; security->rseq = 0; @@ -960,7 +994,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 (DTLS_KEY_EXCHANGE_ECDHE_ECDSA == get_key_exchange_algorithm(handshake->cipher_index)) { goto error; } return 0; @@ -1043,16 +1077,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 (DTLS_KEY_EXCHANGE_ECDHE_ECDSA == get_key_exchange_algorithm(handshake->cipher_index)) { + 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; @@ -1129,8 +1164,8 @@ dtls_update_parameters(dtls_context_t *ctx, ok = 0; while ((i >= (int)sizeof(uint16)) && !ok) { - config->cipher = dtls_uint16_to_int(data); - ok = known_cipher(ctx, config->cipher, 0); + config->cipher_index = get_cipher_index(dtls_uint16_to_int(data)); + ok = known_cipher(ctx, config->cipher_index, 0); i -= sizeof(uint16); data += sizeof(uint16); } @@ -1140,7 +1175,7 @@ dtls_update_parameters(dtls_context_t *ctx, if (!ok) { /* reset config cipher to a well-defined value */ - config->cipher = TLS_NULL_WITH_NULL_NULL; + config->cipher_index = DTLS_CIPHER_INDEX_NULL; dtls_warn("No matching cipher found\n"); goto error; } @@ -1203,9 +1238,12 @@ check_client_keyexchange(dtls_context_t *ctx, dtls_handshake_parameters_t *handshake, uint8 *data, size_t length) { + const cipher_suite_key_exchange_algorithm_t key_exchange_algorithm = + get_key_exchange_algorithm(handshake->cipher_index); + (void) ctx; #ifdef DTLS_ECC - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher)) { + if (key_exchange_algorithm == DTLS_KEY_EXCHANGE_ECDHE_ECDSA) { if (length < DTLS_HS_LENGTH + DTLS_CKXEC_LENGTH) { dtls_debug("The client key exchange is too short\n"); @@ -1235,7 +1273,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 (key_exchange_algorithm == DTLS_KEY_EXCHANGE_PSK) { int id_length; if (length < DTLS_HS_LENGTH + DTLS_CKXPSK_LENGTH_MIN) { @@ -1399,7 +1437,7 @@ 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) { + if (security->cipher_index == DTLS_CIPHER_INDEX_NULL) { /* no cipher suite */ res = 0; @@ -1414,7 +1452,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) @@ -1422,16 +1460,21 @@ 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]; + const uint8_t mac_len = get_cipher_suite_mac_len(security->cipher_index); + const cipher_suite_key_exchange_algorithm_t key_exchange_algorithm = + get_key_exchange_algorithm(security->cipher_index); /* 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 (key_exchange_algorithm == DTLS_KEY_EXCHANGE_PSK) { + dtls_debug("dtls_prepare_record(): encrypt using TLS_PSK_WITH_AES_128_CCM_%d\n", mac_len); + } else if (key_exchange_algorithm == DTLS_KEY_EXCHANGE_ECDHE_ECDSA) { + dtls_debug("dtls_prepare_record(): encrypt using TLS_ECDHE_ECDSA_WITH_AES_128_CCM_%d\n", mac_len); + } } /* set nonce @@ -2132,7 +2175,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(DTLS_KEY_EXCHANGE_ECDHE_ECDSA == get_key_exchange_algorithm(config->cipher_index)); data += DTLS_HS_LENGTH; data_length -= DTLS_HS_LENGTH; @@ -2179,11 +2222,10 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) * encoding function, so we do not need to guess.) */ uint8 buf[DTLS_SH_LENGTH + 2 + 5 + 5 + 8 + 6 + 4]; uint8 *p; - int ecdsa; uint8 extension_size; - dtls_handshake_parameters_t *handshake = peer->handshake_params; - - ecdsa = is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher); + dtls_handshake_parameters_t * handshake = peer->handshake_params; + const dtls_cipher_t cipher_suite = get_cipher_suite(handshake->cipher_index); + const int ecdsa = DTLS_KEY_EXCHANGE_ECDHE_ECDSA == get_key_exchange_algorithm(handshake->cipher_index); extension_size = (handshake->extended_master_secret ? 4 : 0) + (ecdsa ? 5 + 5 + 6 : 0); @@ -2203,9 +2245,9 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) *p++ = 0; /* no session id */ - if (handshake->cipher != TLS_NULL_WITH_NULL_NULL) { + if (cipher_suite != TLS_NULL_WITH_NULL_NULL) { /* selected cipher suite */ - dtls_int_to_uint16(p, handshake->cipher); + dtls_int_to_uint16(p, cipher_suite); p += sizeof(uint16); /* selected compression method */ @@ -2509,6 +2551,7 @@ static int dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) { int res; + cipher_suite_key_exchange_algorithm_t key_exchange_algorithm; res = dtls_send_server_hello(ctx, peer); @@ -2516,9 +2559,10 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) dtls_debug("dtls_server_hello: cannot prepare ServerHello record\n"); return res; } + key_exchange_algorithm = get_key_exchange_algorithm(peer->handshake_params->cipher_index); #ifdef DTLS_ECC - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) { + if (DTLS_KEY_EXCHANGE_ECDHE_ECDSA == key_exchange_algorithm) { const dtls_ecdsa_key_t *ecdsa_key; res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key); @@ -2541,8 +2585,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) && - is_ecdsa_client_auth_supported(ctx)) { + if (is_ecdsa_client_auth_supported(ctx)) { res = dtls_send_server_certificate_request(ctx, peer); if (res < 0) { @@ -2554,7 +2597,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 (DTLS_KEY_EXCHANGE_PSK == key_exchange_algorithm) { unsigned char psk_hint[DTLS_PSK_MAX_CLIENT_IDENTITY_LEN]; int len; @@ -2602,15 +2645,18 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) uint8 buf[DTLS_CKXEC_LENGTH]; uint8 *p; dtls_handshake_parameters_t *handshake = peer->handshake_params; + const cipher_suite_key_exchange_algorithm_t key_exchange_algorithm = + get_key_exchange_algorithm(handshake->cipher_index); int ret; p = buf; memset(buf, 0, sizeof(buf)); - switch (handshake->cipher) { + switch (key_exchange_algorithm) { + case DTLS_KEY_EXCHANGE_PSK: #ifdef DTLS_PSK - case TLS_PSK_WITH_AES_128_CCM_8: { - int len; + { + int len; len = CALL(ctx, get_psk_info, &peer->session, DTLS_PSK_IDENTITY, handshake->keyx.psk.identity, handshake->keyx.psk.id_length, @@ -2638,52 +2684,45 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) break; } +#else /* DTLS_PSK */ + dtls_crit("PSK not supported\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); #endif /* DTLS_PSK */ + case DTLS_KEY_EXCHANGE_ECDHE_ECDSA: #ifdef DTLS_ECC - case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: { - uint8 *ephemeral_pub_x; - uint8 *ephemeral_pub_y; + { + uint8 *ephemeral_pub_x; + uint8 *ephemeral_pub_y; - dtls_int_to_uint8(p, 1 + 2 * DTLS_EC_KEY_SIZE); - p += sizeof(uint8); + dtls_int_to_uint8(p, 1 + 2 * DTLS_EC_KEY_SIZE); + p += sizeof(uint8); - /* This should be an uncompressed point, but I do not have access to the spec. */ - dtls_int_to_uint8(p, 4); - p += sizeof(uint8); + /* This should be an uncompressed point, but I do not have access to the spec. */ + dtls_int_to_uint8(p, 4); + p += sizeof(uint8); - ephemeral_pub_x = p; - p += DTLS_EC_KEY_SIZE; - ephemeral_pub_y = p; - p += DTLS_EC_KEY_SIZE; + ephemeral_pub_x = p; + p += DTLS_EC_KEY_SIZE; + ephemeral_pub_y = p; + p += DTLS_EC_KEY_SIZE; dtls_ecdsa_generate_key(peer->handshake_params->keyx.ecdsa.own_eph_priv, ephemeral_pub_x, ephemeral_pub_y, DTLS_EC_KEY_SIZE); - break; - } + break; + } +#else /* DTLS_ECC */ + dtls_crit("ECC not supported\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); #endif /* DTLS_ECC */ - case TLS_NULL_WITH_NULL_NULL: + case DTLS_KEY_EXCHANGE_NONE: assert(!"NULL cipher requested"); return dtls_alert_fatal_create(DTLS_ALERT_INSUFFICIENT_SECURITY); - /* The following cases cover the enum symbols that are not - * included in this build. These must be kept just above the - * default case as they do nothing but fall through. - */ -#ifndef DTLS_PSK - 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_8: - /* fall through to default */ -#endif /* !DTLS_ECC */ - default: - dtls_crit("cipher %04x not supported\n", handshake->cipher); + dtls_crit("key exchange algorithm %d not supported\n", key_exchange_algorithm); return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); } @@ -2782,7 +2821,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) { @@ -2824,10 +2863,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 */ @@ -3000,8 +3043,8 @@ check_server_hello(dtls_context_t *ctx, /* Check cipher suite. As we offer all we have, it is sufficient * to check if the cipher suite selected by the server is in our * list of known cipher suites. Subsets are not supported. */ - handshake->cipher = dtls_uint16_to_int(data); - if (!known_cipher(ctx, handshake->cipher, 1)) { + handshake->cipher_index = get_cipher_index(dtls_uint16_to_int(data)); + if (!known_cipher(ctx, handshake->cipher_index, 1)) { dtls_alert("unsupported cipher 0x%02x 0x%02x\n", data[0], data[1]); return dtls_alert_fatal_create(DTLS_ALERT_INSUFFICIENT_SECURITY); @@ -3059,7 +3102,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(DTLS_KEY_EXCHANGE_ECDHE_ECDSA == get_key_exchange_algorithm(config->cipher_index)); data += DTLS_HS_LENGTH; @@ -3110,7 +3153,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(DTLS_KEY_EXCHANGE_ECDHE_ECDSA == get_key_exchange_algorithm(config->cipher_index)); data += DTLS_HS_LENGTH; data_length -= DTLS_HS_LENGTH; @@ -3197,7 +3240,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(DTLS_KEY_EXCHANGE_PSK == get_key_exchange_algorithm(config->cipher_index)); data += DTLS_HS_LENGTH; @@ -3241,7 +3284,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(DTLS_KEY_EXCHANGE_ECDHE_ECDSA == get_key_exchange_algorithm(peer->handshake_params->cipher_index)); data += DTLS_HS_LENGTH; @@ -3405,10 +3448,10 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, return -1; } - if (security->cipher == TLS_NULL_WITH_NULL_NULL) { + if (security->cipher_index == DTLS_CIPHER_INDEX_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) @@ -3416,11 +3459,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]; + const uint8_t mac_len = get_cipher_suite_mac_len(security->cipher_index); /* 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); @@ -3445,7 +3489,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), @@ -3544,7 +3588,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 (DTLS_KEY_EXCHANGE_ECDHE_ECDSA == get_key_exchange_algorithm(peer->handshake_params->cipher_index) && is_ecdsa_client_auth_supported(ctx)) peer->state = DTLS_STATE_WAIT_CLIENTCERTIFICATE; else @@ -3559,6 +3603,7 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, uint8 *data, size_t int err = 0; const dtls_peer_type role = peer->role; const dtls_state_t state = peer->state; + const cipher_suite_key_exchange_algorithm_t key_exchange_algorithm = get_key_exchange_algorithm(peer->handshake_params->cipher_index); /* This will clear the retransmission buffer if we get an expected * handshake message. We have to make sure that no handshake message @@ -3602,7 +3647,8 @@ 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)) + /* check_server_hello sets the cipher_index */ + if (DTLS_KEY_EXCHANGE_ECDHE_ECDSA == get_key_exchange_algorithm(peer->handshake_params->cipher_index)) peer->state = DTLS_STATE_WAIT_SERVERCERTIFICATE; else { peer->optional_handshake_message = DTLS_HT_SERVER_KEY_EXCHANGE; @@ -3637,7 +3683,7 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, uint8 *data, size_t case DTLS_HT_SERVER_KEY_EXCHANGE: #ifdef DTLS_ECC - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) { + if (key_exchange_algorithm == DTLS_KEY_EXCHANGE_ECDHE_ECDSA) { if (state != DTLS_STATE_WAIT_SERVERKEYEXCHANGE) { return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); } @@ -3646,7 +3692,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 (key_exchange_algorithm == DTLS_KEY_EXCHANGE_PSK) { if (state != DTLS_STATE_WAIT_SERVERHELLODONE || peer->optional_handshake_message != DTLS_HT_SERVER_KEY_EXCHANGE) { return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); } @@ -3685,7 +3731,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)) { + key_exchange_algorithm != DTLS_KEY_EXCHANGE_ECDHE_ECDSA) { return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); } peer->optional_handshake_message = DTLS_HT_NO_OPTIONAL_MESSAGE; @@ -3761,8 +3807,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) && - is_ecdsa_client_auth_supported(ctx)) + if (key_exchange_algorithm == DTLS_KEY_EXCHANGE_ECDHE_ECDSA && is_ecdsa_client_auth_supported(ctx)) peer->state = DTLS_STATE_WAIT_CERTIFICATEVERIFY; else peer->state = DTLS_STATE_WAIT_CHANGECIPHERSPEC; diff --git a/global.h b/global.h index 87153df3..787adb54 100644 --- a/global.h +++ b/global.h @@ -65,7 +65,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;