X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=extlibs%2Ftinydtls%2Fdtls.c;h=6cf26b4a38ccc085b6bb9d6b92c7ccd43a2d8fca;hb=390866079e285d2c74918432c0d597d5da52f8a0;hp=a923386523d3751d5b6946226aaeff726bfd0df0;hpb=935fdb9b67b6c10d007e652e9e2e028fd6ccfe09;p=platform%2Fupstream%2Fiotivity.git diff --git a/extlibs/tinydtls/dtls.c b/extlibs/tinydtls/dtls.c index a923386..6cf26b4 100644 --- a/extlibs/tinydtls/dtls.c +++ b/extlibs/tinydtls/dtls.c @@ -79,6 +79,7 @@ #define DTLS_SH_LENGTH (2 + DTLS_RANDOM_LENGTH + 1 + 2 + 1) #define DTLS_CE_LENGTH (3 + 3 + 27 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE) #define DTLS_SKEXEC_LENGTH (1 + 2 + 1 + 1 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE + 1 + 1 + 2 + 70) +#define DTLS_SKEXEC_ECDH_ANON_LENGTH (1 + 2 + 1 + 1 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE) #define DTLS_SKEXECPSK_LENGTH_MIN 2 #define DTLS_SKEXECPSK_LENGTH_MAX 2 + DTLS_PSK_MAX_CLIENT_IDENTITY_LEN #define DTLS_CKXPSK_LENGTH_MIN 2 @@ -167,6 +168,24 @@ dtls_init() { peer_init(); } + void + dtls_enables_anon_ecdh(dtls_context_t* ctx, dtls_cipher_enable_t is_enable) +{ + if(ctx) + { + ctx->is_anon_ecdh_eabled = is_enable; + } +} + +void +dtls_select_cipher(dtls_context_t* ctx, const dtls_cipher_t cipher) +{ + if(ctx) + { + ctx->selected_cipher = cipher; + } +} + /* Calls cb_alert() with given arguments if defined, otherwise an * error message is logged and the result is -1. This is just an * internal helper. @@ -460,7 +479,7 @@ static uint8 compression_methods[] = { /** 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) { -#ifdef DTLS_ECC +#if defined(DTLS_ECC) || defined(DTLS_X509) return cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; #else return 0; @@ -477,6 +496,28 @@ static inline int is_tls_psk_with_aes_128_ccm_8(dtls_cipher_t cipher) #endif /* DTLS_PSK */ } +/** returns true if the cipher matches TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 */ +static inline int is_tls_ecdh_anon_with_aes_128_cbc_sha_256(dtls_cipher_t cipher) +{ +#ifdef DTLS_ECC + return cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256; +#else + return 0; +#endif +} + +/** returns true if the cipher matches TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 */ +static inline int is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(dtls_cipher_t cipher) +{ +#if defined(DTLS_ECC) && defined(DTLS_PSK) + return cipher == TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256; +#else + return 0; +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ +} + + + /** returns true if the application is configured for psk */ static inline int is_psk_supported(dtls_context_t *ctx) { @@ -491,13 +532,24 @@ static inline int is_psk_supported(dtls_context_t *ctx) static inline int is_ecdsa_supported(dtls_context_t *ctx, int is_client) { #ifdef DTLS_ECC - return ctx && ctx->h && ((!is_client && ctx->h->get_ecdsa_key) || + return ctx && ctx->h && ((!is_client && ctx->h->get_ecdsa_key) || (is_client && ctx->h->verify_ecdsa_key)); #else return 0; #endif /* DTLS_ECC */ } +/** returns true if the application is configured for x509 */ +static inline int is_x509_supported(dtls_context_t *ctx, int is_client) +{ +#ifdef DTLS_X509 + return ctx && ctx->h && ((!is_client && ctx->h->get_x509_cert) || + (is_client && ctx->h->verify_x509_cert)); +#else + return 0; +#endif /* DTLS_X509 */ +} + /** Returns true if the application is configured for ecdhe_ecdsa with * client authentication */ static inline int is_ecdsa_client_auth_supported(dtls_context_t *ctx) @@ -509,6 +561,38 @@ static inline int is_ecdsa_client_auth_supported(dtls_context_t *ctx) #endif /* DTLS_ECC */ } +/** Returns true if the application is configured for x509 with + * client authentication */ +static inline int is_x509_client_auth_supported(dtls_context_t *ctx) +{ +#ifdef DTLS_X509 + return ctx && ctx->h && ctx->h->get_x509_cert && ctx->h->verify_x509_cert; +#else + return 0; +#endif /* DTLS_X509 */ +} + +/** returns true if ecdh_anon_with_aes_128_cbc_sha is supported */ +static inline int is_ecdh_anon_supported(dtls_context_t *ctx) +{ +#ifdef DTLS_ECC + return ctx && (ctx->is_anon_ecdh_eabled == DTLS_CIPHER_ENABLE); +#else + return 0; +#endif +} + +/** returns true if ecdhe_psk_with_aes_128_cbc_sha_256 is supported */ +static inline int is_ecdhe_psk_supported(dtls_context_t *ctx) +{ +#if defined(DTLS_ECC) && defined(DTLS_PSK) + return is_psk_supported(ctx); +#else + return 0; +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ +} + + /** * Returns @c 1 if @p code is a cipher suite other than @c * TLS_NULL_WITH_NULL_NULL that we recognize. @@ -522,11 +606,21 @@ static int known_cipher(dtls_context_t *ctx, dtls_cipher_t code, int is_client) { int psk; int ecdsa; + int ecdh_anon; + int ecdhe_psk; + int x509; psk = is_psk_supported(ctx); ecdsa = is_ecdsa_supported(ctx, is_client); + ecdh_anon = is_ecdh_anon_supported(ctx); + ecdhe_psk = is_ecdhe_psk_supported(ctx); + x509 = is_x509_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)); + (ecdsa && is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(code)) || + (ecdh_anon && is_tls_ecdh_anon_with_aes_128_cbc_sha_256(code)) || + (ecdhe_psk && is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(code)) || + (x509 && is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(code)); } /** @@ -566,11 +660,11 @@ static void dtls_debug_keyblock(dtls_security_parameters_t *config) dtls_debug("key_block (%d bytes):\n", dtls_kb_size(config, peer->role)); dtls_debug_dump(" client_MAC_secret", dtls_kb_client_mac_secret(config, peer->role), - dtls_kb_mac_secret_size(config, peer->role)); + dtls_kb_mac_secret_size(config->cipher)); dtls_debug_dump(" server_MAC_secret", dtls_kb_server_mac_secret(config, peer->role), - dtls_kb_mac_secret_size(config, peer->role)); + dtls_kb_mac_secret_size(config->cipher)); dtls_debug_dump(" client_write_key", dtls_kb_client_write_key(config, peer->role), @@ -582,11 +676,11 @@ static void dtls_debug_keyblock(dtls_security_parameters_t *config) dtls_debug_dump(" client_IV", dtls_kb_client_iv(config, peer->role), - dtls_kb_iv_size(config, peer->role)); + dtls_kb_iv_size(config->cipher)); dtls_debug_dump(" server_IV", dtls_kb_server_iv(config, peer->role), - dtls_kb_iv_size(config, peer->role)); + dtls_kb_iv_size(config->cipher)); } /** returns the name of the goven handshake type number. @@ -632,7 +726,11 @@ calculate_key_block(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session, dtls_peer_type role) { - unsigned char *pre_master_secret; +#if defined(DTLS_PSK) && defined(DTLS_ECC) + unsigned char pre_master_secret[MAX_KEYBLOCK_LENGTH + uECC_BYTES]; +#else + unsigned char pre_master_secret[MAX_KEYBLOCK_LENGTH]; +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ int pre_master_len = 0; dtls_security_parameters_t *security = dtls_security_params_next(peer); uint8 master_secret[DTLS_MASTER_SECRET_LENGTH]; @@ -641,8 +739,6 @@ calculate_key_block(dtls_context_t *ctx, return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); } - pre_master_secret = security->key_block; - switch (handshake->cipher) { #ifdef DTLS_PSK case TLS_PSK_WITH_AES_128_CCM_8: { @@ -673,12 +769,13 @@ calculate_key_block(dtls_context_t *ctx, break; } #endif /* DTLS_PSK */ -#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), +#if defined(DTLS_ECC) || defined(DTLS_X509) + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: + case TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256: { + pre_master_len = dtls_ecdh_pre_master_secret(handshake->keyx.ecc.own_eph_priv, + handshake->keyx.ecc.other_eph_pub_x, + handshake->keyx.ecc.other_eph_pub_y, + sizeof(handshake->keyx.ecc.own_eph_priv), pre_master_secret, MAX_KEYBLOCK_LENGTH); if (pre_master_len < 0) { @@ -688,6 +785,35 @@ calculate_key_block(dtls_context_t *ctx, break; } #endif /* DTLS_ECC */ +#if defined(DTLS_PSK) && defined(DTLS_ECC) + case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256: { + unsigned char psk[DTLS_PSK_MAX_KEY_LEN]; + int psklen; + + psklen = 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 (psklen < 0) { + dtls_crit("no psk key for session available\n"); + return psklen; + } + + pre_master_len = dtls_ecdhe_psk_pre_master_secret(psk, psklen, + handshake->keyx.ecc.own_eph_priv, + handshake->keyx.ecc.other_eph_pub_x, + handshake->keyx.ecc.other_eph_pub_y, + sizeof(handshake->keyx.ecc.own_eph_priv), + pre_master_secret, + MAX_KEYBLOCK_LENGTH + uECC_BYTES); + + 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; + } +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ default: dtls_crit("calculate_key_block: unknown cipher\n"); return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); @@ -709,6 +835,9 @@ calculate_key_block(dtls_context_t *ctx, /* create key_block from master_secret * key_block = PRF(master_secret, "key expansion" + tmp.random.server + tmp.random.client) */ + security->cipher = handshake->cipher; + security->compression = handshake->compression; + security->rseq = 0; dtls_prf(master_secret, DTLS_MASTER_SECRET_LENGTH, @@ -721,9 +850,6 @@ 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->compression = handshake->compression; - security->rseq = 0; return 0; } @@ -769,8 +895,13 @@ static int verify_ext_cert_type(uint8 *data, size_t data_length) { cert_type = dtls_uint8_to_int(data); data += sizeof(uint8); + if (cert_type == TLS_CERT_TYPE_RAW_PUBLIC_KEY) - return 0; + return 0; +#ifdef DTLS_X509 + if (cert_type == TLS_CERT_TYPE_X509) + return 0; +#endif } dtls_warn("no supported certificate type found\n"); @@ -861,7 +992,12 @@ dtls_check_tls_extension(dtls_peer_t *peer, if (verify_ext_cert_type(data, j)) goto error; } else { +#ifndef DTLS_X509 if (dtls_uint8_to_int(data) != TLS_CERT_TYPE_RAW_PUBLIC_KEY) +#else + if ((dtls_uint8_to_int(data) != TLS_CERT_TYPE_RAW_PUBLIC_KEY) && + (dtls_uint8_to_int(data) != TLS_CERT_TYPE_X509)) +#endif goto error; } break; @@ -871,7 +1007,12 @@ dtls_check_tls_extension(dtls_peer_t *peer, if (verify_ext_cert_type(data, j)) goto error; } else { +#ifndef DTLS_X509 if (dtls_uint8_to_int(data) != TLS_CERT_TYPE_RAW_PUBLIC_KEY) +#else + if ((dtls_uint8_to_int(data) != TLS_CERT_TYPE_RAW_PUBLIC_KEY) && + (dtls_uint8_to_int(data) != TLS_CERT_TYPE_X509)) +#endif goto error; } break; @@ -1037,8 +1178,9 @@ check_client_keyexchange(dtls_context_t *ctx, dtls_handshake_parameters_t *handshake, uint8 *data, size_t length) { -#ifdef DTLS_ECC - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher)) { +#if defined(DTLS_ECC) || defined(DTLS_X509) + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) || + is_tls_ecdh_anon_with_aes_128_cbc_sha_256(handshake->cipher) ) { if (length < DTLS_HS_LENGTH + DTLS_CKXEC_LENGTH) { dtls_debug("The client key exchange is too short\n"); @@ -1058,15 +1200,65 @@ check_client_keyexchange(dtls_context_t *ctx, } data += sizeof(uint8); - memcpy(handshake->keyx.ecdsa.other_eph_pub_x, data, - sizeof(handshake->keyx.ecdsa.other_eph_pub_x)); - data += sizeof(handshake->keyx.ecdsa.other_eph_pub_x); + memcpy(handshake->keyx.ecc.other_eph_pub_x, data, + sizeof(handshake->keyx.ecc.other_eph_pub_x)); + data += sizeof(handshake->keyx.ecc.other_eph_pub_x); - memcpy(handshake->keyx.ecdsa.other_eph_pub_y, data, - sizeof(handshake->keyx.ecdsa.other_eph_pub_y)); - data += sizeof(handshake->keyx.ecdsa.other_eph_pub_y); + memcpy(handshake->keyx.ecc.other_eph_pub_y, data, + sizeof(handshake->keyx.ecc.other_eph_pub_y)); + data += sizeof(handshake->keyx.ecc.other_eph_pub_y); } #endif /* DTLS_ECC */ +#if defined(DTLS_PSK) && defined(DTLS_ECC) + if (is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(handshake->cipher)) { + int id_length; + + if (length < DTLS_HS_LENGTH + DTLS_CKXEC_LENGTH) { + dtls_debug("The client key exchange is too short\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + data += DTLS_HS_LENGTH; + + //PSK hint + id_length = dtls_uint16_to_int(data); + data += sizeof(uint16); + + if (DTLS_HS_LENGTH + DTLS_CKXPSK_LENGTH_MIN + DTLS_CKXEC_LENGTH + id_length != length) { + dtls_debug("The identity has a wrong length\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + + if (id_length > DTLS_PSK_MAX_CLIENT_IDENTITY_LEN) { + dtls_warn("please use a smaller client identity\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + + handshake->keyx.psk.id_length = id_length; + memcpy(handshake->keyx.psk.identity, data, id_length); + data += id_length; + + //ECDH public + if (dtls_uint8_to_int(data) != 1 + 2 * DTLS_EC_KEY_SIZE) { + dtls_alert("expected 65 bytes long public point\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + data += sizeof(uint8); + + if (dtls_uint8_to_int(data) != 4) { + dtls_alert("expected uncompressed public point\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + data += sizeof(uint8); + + memcpy(handshake->keyx.ecc.other_eph_pub_x, data, + sizeof(handshake->keyx.ecc.other_eph_pub_x)); + data += sizeof(handshake->keyx.ecc.other_eph_pub_x); + + memcpy(handshake->keyx.ecc.other_eph_pub_y, data, + sizeof(handshake->keyx.ecc.other_eph_pub_y)); + data += sizeof(handshake->keyx.ecc.other_eph_pub_y); + } +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ #ifdef DTLS_PSK if (is_tls_psk_with_aes_128_ccm_8(handshake->cipher)) { int id_length; @@ -1240,6 +1432,54 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, p += data_len_array[i]; res += data_len_array[i]; } + } else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(security->cipher) || + is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(security->cipher)) { + + unsigned char nonce[DTLS_CBC_IV_LENGTH]; + + /** Add IV into body of packet in case of AES CBC mode according to RFC 5246, Section 6.2.3.2 + * + * opaque IV[SecurityParameters.record_iv_length]; + * block-ciphered struct { + * opaque content[TLSCompressed.length]; + * opaque MAC[SecurityParameters.mac_length]; + * uint8 padding[GenericBlockCipher.padding_length]; + * uint8 padding_length; + * }; + * + */ + + res = 0; + dtls_prng(nonce, DTLS_CBC_IV_LENGTH); + memcpy(p , nonce, DTLS_CBC_IV_LENGTH); + p += DTLS_CBC_IV_LENGTH; + res += DTLS_CBC_IV_LENGTH; + + for (i = 0; i < data_array_len; i++) { + /* check the minimum that we need for packets that are not encrypted */ + if (*rlen < res + DTLS_RH_LENGTH + data_len_array[i]) { + dtls_debug("dtls_prepare_record: send buffer too small\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + + memcpy(p, data_array[i], data_len_array[i]); + p += data_len_array[i]; + res += data_len_array[i]; + } + + res = dtls_encrypt(start + DTLS_CBC_IV_LENGTH, res - DTLS_CBC_IV_LENGTH, + start + DTLS_CBC_IV_LENGTH, nonce, + dtls_kb_local_write_key(security, peer->role), + dtls_kb_key_size(security, peer->role), + dtls_kb_local_mac_secret(security, peer->role), + dtls_kb_mac_secret_size(security->cipher), + NULL, 0, + security->cipher); + if (res < 0) + return res; + + res += DTLS_CBC_IV_LENGTH; + } else { /* TLS_PSK_WITH_AES_128_CCM_8 or TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 */ /** * length of additional_data for the AEAD cipher which consists of @@ -1315,8 +1555,8 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, memset(nonce, 0, DTLS_CCM_BLOCKSIZE); memcpy(nonce, dtls_kb_local_iv(security, peer->role), - dtls_kb_iv_size(security, peer->role)); - memcpy(nonce + dtls_kb_iv_size(security, peer->role), start, 8); /* epoch + seq_num */ + dtls_kb_iv_size(security->cipher)); + memcpy(nonce + dtls_kb_iv_size(security->cipher), start, 8); /* epoch + seq_num */ dtls_debug_dump("nonce:", nonce, DTLS_CCM_BLOCKSIZE); dtls_debug_dump("key:", dtls_kb_local_write_key(security, peer->role), @@ -1330,16 +1570,19 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, 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 */ - + res = dtls_encrypt(start + 8, res - 8, start + 8, nonce, - dtls_kb_local_write_key(security, peer->role), - dtls_kb_key_size(security, peer->role), - A_DATA, A_DATA_LEN); + dtls_kb_local_write_key(security, peer->role), + dtls_kb_key_size(security, peer->role), + dtls_kb_local_mac_secret(security, peer->role), + dtls_kb_mac_secret_size(security->cipher), + A_DATA, A_DATA_LEN, + security->cipher); if (res < 0) return res; - res += 8; /* increment res by size of nonce_explicit */ + res += 8; /* increment res by size of nonce_explicit */ dtls_debug_dump("message:", start, res); } @@ -1641,7 +1884,7 @@ dtls_verify_peer(dtls_context_t *ctx, #undef mycookie } -#ifdef DTLS_ECC +#if defined(DTLS_ECC) || defined(DTLS_X509) static int dtls_check_ecdsa_signature_elem(uint8 *data, size_t data_length, unsigned char **result_r, @@ -1754,12 +1997,12 @@ check_client_certificate_verify(dtls_context_t *ctx, dtls_hash_finalize(sha256hash, &hs_hash); - ret = dtls_ecdsa_verify_sig_hash(config->keyx.ecdsa.other_pub_x, config->keyx.ecdsa.other_pub_y, - sizeof(config->keyx.ecdsa.other_pub_x), - sha256hash, sizeof(sha256hash), - result_r, result_s); + ret = dtls_ecdsa_verify_sig_hash(config->keyx.ecc.other_pub_x, config->keyx.ecc.other_pub_y, + sizeof(config->keyx.ecc.other_pub_x), + sha256hash, sizeof(sha256hash), + result_r, result_s); - if (ret < 0) { + if (ret <= 0) { dtls_alert("wrong signature err: %i\n", ret); return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); } @@ -1825,8 +2068,13 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) /* length of this extension type */ dtls_int_to_uint16(p, 1); p += sizeof(uint16); +#ifdef DTLS_X509 + if (CALL(ctx, is_x509_active) == 0) + dtls_int_to_uint8(p, TLS_CERT_TYPE_X509); + else +#endif /* DTLS_X509 */ + dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY); - dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY); p += sizeof(uint8); /* client certificate type extension */ @@ -1837,7 +2085,13 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) dtls_int_to_uint16(p, 1); p += sizeof(uint16); - dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY); +#ifdef DTLS_X509 + if (CALL(ctx, is_x509_active) == 0) + dtls_int_to_uint8(p, TLS_CERT_TYPE_X509); + else +#endif /* DTLS_X509 */ + dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY); + p += sizeof(uint8); /* ec_point_formats */ @@ -1865,24 +2119,24 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) } #ifdef DTLS_ECC +#define DTLS_EC_SUBJECTPUBLICKEY_SIZE (2 * DTLS_EC_KEY_SIZE + sizeof(cert_asn1_header)) + static int dtls_send_certificate_ecdsa(dtls_context_t *ctx, dtls_peer_t *peer, - const dtls_ecdsa_key_t *key) + const dtls_ecc_key_t *key) { uint8 buf[DTLS_CE_LENGTH]; uint8 *p; - /* Certificate + /* Certificate * * Start message construction at beginning of buffer. */ p = buf; - dtls_int_to_uint24(p, 94); /* certificates length */ + /* length of this certificate */ + dtls_int_to_uint24(p, DTLS_EC_SUBJECTPUBLICKEY_SIZE); p += sizeof(uint24); - dtls_int_to_uint24(p, 91); /* length of this certificate */ - p += sizeof(uint24); - memcpy(p, &cert_asn1_header, sizeof(cert_asn1_header)); p += sizeof(cert_asn1_header); @@ -1897,7 +2151,46 @@ dtls_send_certificate_ecdsa(dtls_context_t *ctx, dtls_peer_t *peer, return dtls_send_handshake_msg(ctx, peer, DTLS_HT_CERTIFICATE, buf, p - buf); } +#endif /* DTLS_ECC */ + +#ifdef DTLS_X509 +static int +dtls_send_certificate_x509(dtls_context_t *ctx, dtls_peer_t *peer) +{ + uint8 buf[DTLS_MAX_CERT_SIZE]; + uint8 *p; + int ret; + unsigned char *cert; + size_t cert_size; + + dtls_info("\n dtls_send_certificate_ecdsa\n"); + ret = CALL(ctx, get_x509_cert, &peer->session, + (const unsigned char **)&cert, &cert_size); + + if (ret < 0) { + dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + return ret; + } + + /* Certificate + * + * Start message construction at beginning of buffer. */ + p = buf; + + dtls_int_to_uint24(p, cert_size); /* certificates length */ + p += sizeof(uint24); + + memcpy(p, cert, cert_size); + p += cert_size; + + assert(p - buf <= sizeof(buf)); + + return dtls_send_handshake_msg(ctx, peer, DTLS_HT_CERTIFICATE, + buf, p - buf); +} +#endif /* DTLS_X509 */ +#if defined(DTLS_X509) || defined(DTLS_ECC) static uint8 * dtls_add_ecdsa_signature_elem(uint8 *p, uint32_t *point_r, uint32_t *point_s) { @@ -1957,7 +2250,7 @@ dtls_add_ecdsa_signature_elem(uint8 *p, uint32_t *point_r, uint32_t *point_s) static int dtls_send_server_key_exchange_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, - const dtls_ecdsa_key_t *key) + const dtls_ecc_key_t *key) { /* The ASN.1 Integer representation of an 32 byte unsigned int could be * 33 bytes long add space for that */ @@ -1968,9 +2261,11 @@ dtls_send_server_key_exchange_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, uint8 *ephemeral_pub_y; uint32_t point_r[9]; uint32_t point_s[9]; + int ecdsa; dtls_handshake_parameters_t *config = peer->handshake_params; - /* ServerKeyExchange + ecdsa = is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher); + /* ServerKeyExchange * * Start message construction at beginning of buffer. */ p = buf; @@ -1999,25 +2294,100 @@ dtls_send_server_key_exchange_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, ephemeral_pub_y = p; p += DTLS_EC_KEY_SIZE; - dtls_ecdsa_generate_key(config->keyx.ecdsa.own_eph_priv, - ephemeral_pub_x, ephemeral_pub_y, - DTLS_EC_KEY_SIZE); + dtls_ecdsa_generate_key(config->keyx.ecc.own_eph_priv, + ephemeral_pub_x, ephemeral_pub_y, + DTLS_EC_KEY_SIZE); + if(ecdsa) { + /* sign the ephemeral and its paramaters */ + dtls_ecdsa_create_sig(key->priv_key, DTLS_EC_KEY_SIZE, + config->tmp.random.client, DTLS_RANDOM_LENGTH, + config->tmp.random.server, DTLS_RANDOM_LENGTH, + key_params, p - key_params, + point_r, point_s); - /* sign the ephemeral and its paramaters */ - dtls_ecdsa_create_sig(key->priv_key, DTLS_EC_KEY_SIZE, - config->tmp.random.client, DTLS_RANDOM_LENGTH, - config->tmp.random.server, DTLS_RANDOM_LENGTH, - key_params, p - key_params, - point_r, point_s); + p = dtls_add_ecdsa_signature_elem(p, point_r, point_s); + } - p = dtls_add_ecdsa_signature_elem(p, point_r, point_s); + assert(p - buf <= sizeof(buf)); + + return dtls_send_handshake_msg(ctx, peer, DTLS_HT_SERVER_KEY_EXCHANGE, + buf, p - buf); +} +#endif /* defined(DTLS_X509) || defined(DTLS_ECC) */ + +#if defined(DTLS_PSK) && defined(DTLS_ECC) +static int dtls_send_server_key_exchange_ecdhe_psk(dtls_context_t *ctx, dtls_peer_t *peer, + const unsigned char *psk_hint, size_t psk_hint_len) +{ + /* The ASN.1 Integer representation of an 32 byte unsigned int could be + * 33 bytes long add space for that */ + uint8 buf[DTLS_SKEXEC_LENGTH + DTLS_SKEXECPSK_LENGTH_MAX + 2]; + uint8 *p; + uint8 *ephemeral_pub_x; + uint8 *ephemeral_pub_y; + dtls_handshake_parameters_t *config = peer->handshake_params; + + /* ServerKeyExchange + * Please see Session 2, RFC 5489. + + struct { + select (KeyExchangeAlgorithm) { + //other cases for rsa, diffie_hellman, etc. + case ec_diffie_hellman_psk: // NEW + opaque psk_identity_hint<0..2^16-1>; + ServerECDHParams params; + }; + } ServerKeyExchange; */ + p = buf; + + assert(psk_hint_len <= DTLS_PSK_MAX_CLIENT_IDENTITY_LEN); + if (psk_hint_len > DTLS_PSK_MAX_CLIENT_IDENTITY_LEN) { + // should never happen + dtls_warn("psk identity hint is too long\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + + // psk_identity_hint + dtls_int_to_uint16(p, psk_hint_len); + p += sizeof(uint16); + + memcpy(p, psk_hint, psk_hint_len); + p += psk_hint_len; + + /* ServerECDHParams. */ + /* ECCurveType curve_type: named_curve */ + dtls_int_to_uint8(p, TLS_EC_CURVE_TYPE_NAMED_CURVE); + p += sizeof(uint8); + + /* NamedCurve namedcurve: secp256r1 */ + dtls_int_to_uint16(p, TLS_EXT_ELLIPTIC_CURVES_SECP256R1); + p += sizeof(uint16); + + 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); + + /* store the pointer to the x component of the pub key and make space */ + ephemeral_pub_x = p; + p += DTLS_EC_KEY_SIZE; + + /* store the pointer to the y component of the pub key and make space */ + ephemeral_pub_y = p; + p += DTLS_EC_KEY_SIZE; + + dtls_ecdsa_generate_key(config->keyx.ecc.own_eph_priv, + ephemeral_pub_x, ephemeral_pub_y, + DTLS_EC_KEY_SIZE); assert(p - buf <= sizeof(buf)); return dtls_send_handshake_msg(ctx, peer, DTLS_HT_SERVER_KEY_EXCHANGE, buf, p - buf); } -#endif /* DTLS_ECC */ +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ #ifdef DTLS_PSK static int @@ -2049,7 +2419,7 @@ dtls_send_server_key_exchange_psk(dtls_context_t *ctx, dtls_peer_t *peer, } #endif /* DTLS_PSK */ -#ifdef DTLS_ECC +#if defined(DTLS_ECC) || defined(DTLS_X509) static int dtls_send_server_certificate_request(dtls_context_t *ctx, dtls_peer_t *peer) { @@ -2108,6 +2478,9 @@ static int dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) { int res; + int ecdsa; + int ecdh_anon; + int ecdhe_psk; res = dtls_send_server_hello(ctx, peer); @@ -2116,17 +2489,40 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) return res; } -#ifdef DTLS_ECC - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) { - const dtls_ecdsa_key_t *ecdsa_key; + ecdsa = is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher); + ecdh_anon = is_tls_ecdh_anon_with_aes_128_cbc_sha_256(peer->handshake_params->cipher); + ecdhe_psk = is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(peer->handshake_params->cipher); + +#if defined(DTLS_ECC) || defined(DTLS_X509) + if(ecdh_anon) { + res = dtls_send_server_key_exchange_ecdh(ctx, peer, NULL); + + if (res < 0) { + dtls_debug("dtls_server_hello(with ECDH): cannot prepare Server Key Exchange record\n"); + return res; + } + } + else if (ecdsa) { + const dtls_ecc_key_t *ecdsa_key; + +#ifdef DTLS_X509 + if (CALL(ctx, is_x509_active) == 0) + res = CALL(ctx, get_x509_key, &peer->session, &ecdsa_key); + else +#endif /* DTLS_X509 */ + res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key); - res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key); if (res < 0) { - dtls_crit("no ecdsa certificate to send in certificate\n"); + dtls_debug("no ecdsa key to send\n"); return res; } - res = dtls_send_certificate_ecdsa(ctx, peer, ecdsa_key); +#ifdef DTLS_X509 + if (CALL(ctx, is_x509_active) == 0) + res = dtls_send_certificate_x509(ctx, peer); + else +#endif /* DTLS_X509 */ + res = dtls_send_certificate_ecdsa(ctx, peer, ecdsa_key); if (res < 0) { dtls_debug("dtls_server_hello: cannot prepare Certificate record\n"); @@ -2141,17 +2537,40 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) } if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher) && - is_ecdsa_client_auth_supported(ctx)) { + (is_ecdsa_client_auth_supported(ctx) || (is_x509_client_auth_supported(ctx)))) { res = dtls_send_server_certificate_request(ctx, peer); - if (res < 0) { - dtls_debug("dtls_server_hello: cannot prepare certificate Request record\n"); + dtls_debug("dtls_server_hello(with ECDSA): cannot prepare certificate Request record\n"); return res; } } } #endif /* DTLS_ECC */ +#if defined(DTLS_PSK) && defined(DTLS_ECC) + else if(ecdhe_psk) { + unsigned char psk_hint[DTLS_PSK_MAX_CLIENT_IDENTITY_LEN]; + int psk_len; + + /* The identity hint is optional, therefore we ignore the result + * and check psk only. */ + psk_len = CALL(ctx, get_psk_info, &peer->session, DTLS_PSK_HINT, + NULL, 0, psk_hint, DTLS_PSK_MAX_CLIENT_IDENTITY_LEN); + if (psk_len < 0) { + dtls_debug("dtls_server_hello: cannot create ServerKeyExchange\n"); + return psk_len; + } + + if (psk_len > 0) { + res = dtls_send_server_key_exchange_ecdhe_psk(ctx, peer, psk_hint, (size_t)psk_len); + + if (res < 0) { + dtls_debug("dtls_server_hello(with ECDHE): cannot prepare Server Key Exchange record\n"); + return res; + } + } + } +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ #ifdef DTLS_PSK if (is_tls_psk_with_aes_128_ccm_8(peer->handshake_params->cipher)) { unsigned char psk_hint[DTLS_PSK_MAX_CLIENT_IDENTITY_LEN]; @@ -2198,7 +2617,11 @@ dtls_send_ccs(dtls_context_t *ctx, dtls_peer_t *peer) { static int dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) { +#if defined(DTLS_PSK) && defined(DTLS_ECC) + uint8 buf[DTLS_CKXEC_LENGTH + 2 + DTLS_PSK_MAX_CLIENT_IDENTITY_LEN]; +#else uint8 buf[DTLS_CKXEC_LENGTH]; +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ uint8 client_id[DTLS_PSK_MAX_CLIENT_IDENTITY_LEN]; uint8 *p; dtls_handshake_parameters_t *handshake = peer->handshake_params; @@ -2233,8 +2656,9 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) break; } #endif /* DTLS_PSK */ -#ifdef DTLS_ECC - case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: { +#if defined(DTLS_ECC) || defined(DTLS_X509) + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: + case TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256: { uint8 *ephemeral_pub_x; uint8 *ephemeral_pub_y; @@ -2250,13 +2674,67 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) ephemeral_pub_y = p; p += DTLS_EC_KEY_SIZE; - dtls_ecdsa_generate_key(peer->handshake_params->keyx.ecdsa.own_eph_priv, + dtls_ecdsa_generate_key(peer->handshake_params->keyx.ecc.own_eph_priv, ephemeral_pub_x, ephemeral_pub_y, DTLS_EC_KEY_SIZE); break; } #endif /* DTLS_ECC */ +#if defined(DTLS_PSK) && defined(DTLS_ECC) + case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256: { + int psk_len; + uint8 *ephemeral_pub_x; + uint8 *ephemeral_pub_y; + + /* Please see Session 2, RFC 5489. + struct { + select (KeyExchangeAlgorithm) { + // other cases for rsa, diffie_hellman, etc. + case ec_diffie_hellman_psk: + opaque psk_identity<0..2^16-1>; + ClientECDiffieHellmanPublic public; + } exchange_keys; + } ClientKeyExchange; + */ + + psk_len = CALL(ctx, get_psk_info, &peer->session, DTLS_PSK_IDENTITY, + NULL, 0, + client_id, + sizeof(client_id)); + if (psk_len < 0) { + dtls_crit("no psk identity set in kx\n"); + return psk_len; + } + + if (psk_len + sizeof(uint16) > DTLS_CKXEC_LENGTH) { + dtls_warn("the psk identity is too long\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + + dtls_int_to_uint16(p, psk_len); + p += sizeof(uint16); + + memcpy(p, client_id, psk_len); + p += psk_len; + + dtls_int_to_uint8(p, 1 + 2 * DTLS_EC_KEY_SIZE); + p += sizeof(uint8); + + 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; + + dtls_ecdsa_generate_key(peer->handshake_params->keyx.ecc.own_eph_priv, + ephemeral_pub_x, ephemeral_pub_y, + DTLS_EC_KEY_SIZE); + break; + } +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ default: dtls_crit("cipher not supported\n"); return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); @@ -2268,10 +2746,10 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) buf, p - buf); } -#ifdef DTLS_ECC +#if defined(DTLS_ECC) || defined(DTLS_X509) static int dtls_send_certificate_verify_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, - const dtls_ecdsa_key_t *key) + const dtls_ecc_key_t *key) { /* The ASN.1 Integer representation of an 32 byte unsigned int could be * 33 bytes long add space for that */ @@ -2341,18 +2819,48 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, uint8 cookie[], size_t cookie_length) { uint8 buf[DTLS_CH_LENGTH_MAX]; uint8 *p = buf; - uint8_t cipher_size; - uint8_t extension_size; - int psk; - int ecdsa; + uint8_t cipher_size = 0; + uint8_t extension_size = 0; + int psk = 0; + int ecdsa = 0; + int ecdh_anon = 0; + int ecdhe_psk = 0; + int x509 = 0; dtls_handshake_parameters_t *handshake = peer->handshake_params; dtls_tick_t now; - psk = is_psk_supported(ctx); - ecdsa = is_ecdsa_supported(ctx, 1); + switch(ctx->selected_cipher) + { + case TLS_PSK_WITH_AES_128_CCM_8: + psk = is_psk_supported(ctx); + break; + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: + ecdsa = is_ecdsa_supported(ctx, 1); + x509 = is_x509_supported(ctx, 1); + break; + case TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256: + ecdh_anon = is_ecdh_anon_supported(ctx); + break; + case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256: + ecdhe_psk = is_ecdhe_psk_supported(ctx); + break; + default: + psk = is_psk_supported(ctx); + ecdsa = is_ecdsa_supported(ctx, 1); + ecdh_anon = is_ecdh_anon_supported(ctx); + ecdhe_psk = is_ecdhe_psk_supported(ctx); + x509 = is_x509_supported(ctx, 1); + break; + } - cipher_size = 2 + ((ecdsa) ? 2 : 0) + ((psk) ? 2 : 0); - extension_size = (ecdsa) ? 2 + 6 + 6 + 8 + 6: 0; + cipher_size = 2 + ((ecdsa || x509) ? 2 : 0) + (psk ? 2 : 0) + (ecdh_anon ? 2 : 0) + (ecdhe_psk ? 2 : 0); + + /* Is extension needed? */ + extension_size = (ecdsa || x509 || ecdhe_psk || ecdh_anon) ? 2 : 0; + /* Supported EC and Supported Point Formats */ + extension_size += (ecdsa || x509 || ecdhe_psk | ecdh_anon) ? ( 8 + 6) : 0; + /* Supported Client and Server Cert Types */ + extension_size += (ecdsa || x509) ? ( 6 + 6) : 0; if (cipher_size == 0) { dtls_crit("no cipher callbacks implemented\n"); @@ -2394,14 +2902,22 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, dtls_int_to_uint16(p, cipher_size - 2); p += sizeof(uint16); - if (ecdsa) { - dtls_int_to_uint16(p, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); + if (ecdh_anon) { + dtls_int_to_uint16(p, TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256); p += sizeof(uint16); } if (psk) { dtls_int_to_uint16(p, TLS_PSK_WITH_AES_128_CCM_8); p += sizeof(uint16); } + if (ecdsa || x509) { + dtls_int_to_uint16(p, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); + p += sizeof(uint16); + } + if (ecdhe_psk) { + dtls_int_to_uint16(p, TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256); + p += sizeof(uint16); + } /* compression method */ dtls_int_to_uint8(p, 1); @@ -2416,7 +2932,7 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, p += sizeof(uint16); } - if (ecdsa) { + if (ecdsa || x509) { /* client certificate type extension */ dtls_int_to_uint16(p, TLS_EXT_CLIENT_CERTIFICATE_TYPE); p += sizeof(uint16); @@ -2429,10 +2945,16 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, dtls_int_to_uint8(p, 1); p += sizeof(uint8); - dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY); +#ifdef DTLS_X509 + if (CALL(ctx, is_x509_active) == 0) + dtls_int_to_uint8(p, TLS_CERT_TYPE_X509); + else +#endif /* DTLS_X509 */ + dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY); + p += sizeof(uint8); - /* client certificate type extension */ + /* server certificate type extension */ dtls_int_to_uint16(p, TLS_EXT_SERVER_CERTIFICATE_TYPE); p += sizeof(uint16); @@ -2444,9 +2966,17 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, dtls_int_to_uint8(p, 1); p += sizeof(uint8); - dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY); +#ifdef DTLS_X509 + if (CALL(ctx, is_x509_active) == 0) + dtls_int_to_uint8(p, TLS_CERT_TYPE_X509); + else +#endif /* DTLS_X509 */ + dtls_int_to_uint8(p, TLS_CERT_TYPE_RAW_PUBLIC_KEY); + p += sizeof(uint8); + } + if (ecdsa || x509 || ecdhe_psk || ecdh_anon ) { /* elliptic_curves */ dtls_int_to_uint16(p, TLS_EXT_ELLIPTIC_CURVES); p += sizeof(uint16); @@ -2580,8 +3110,9 @@ check_server_hello_verify_request(dtls_context_t *ctx, } #ifdef DTLS_ECC + static int -check_server_certificate(dtls_context_t *ctx, +check_peer_certificate(dtls_context_t *ctx, dtls_peer_t *peer, uint8 *data, size_t data_length) { @@ -2594,14 +3125,9 @@ check_server_certificate(dtls_context_t *ctx, data += DTLS_HS_LENGTH; - if (dtls_uint24_to_int(data) != 94) { - dtls_alert("expect length of 94 bytes for server certificate message\n"); - return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); - } - data += sizeof(uint24); - - if (dtls_uint24_to_int(data) != 91) { - dtls_alert("expect length of 91 bytes for certificate\n"); + if (dtls_uint24_to_int(data) != DTLS_EC_SUBJECTPUBLICKEY_SIZE) { + dtls_alert("expect length of %d bytes for certificate\n", + DTLS_EC_SUBJECTPUBLICKEY_SIZE); return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); } data += sizeof(uint24); @@ -2612,18 +3138,18 @@ check_server_certificate(dtls_context_t *ctx, } data += sizeof(cert_asn1_header); - memcpy(config->keyx.ecdsa.other_pub_x, data, - sizeof(config->keyx.ecdsa.other_pub_x)); - data += sizeof(config->keyx.ecdsa.other_pub_x); + memcpy(config->keyx.ecc.other_pub_x, data, + sizeof(config->keyx.ecc.other_pub_x)); + data += sizeof(config->keyx.ecc.other_pub_x); - memcpy(config->keyx.ecdsa.other_pub_y, data, - sizeof(config->keyx.ecdsa.other_pub_y)); - data += sizeof(config->keyx.ecdsa.other_pub_y); + memcpy(config->keyx.ecc.other_pub_y, data, + sizeof(config->keyx.ecc.other_pub_y)); + data += sizeof(config->keyx.ecc.other_pub_y); err = CALL(ctx, verify_ecdsa_key, &peer->session, - config->keyx.ecdsa.other_pub_x, - config->keyx.ecdsa.other_pub_y, - sizeof(config->keyx.ecdsa.other_pub_x)); + config->keyx.ecc.other_pub_x, + config->keyx.ecc.other_pub_y, + sizeof(config->keyx.ecc.other_pub_x)); if (err < 0) { dtls_warn("The certificate was not accepted\n"); return err; @@ -2631,7 +3157,41 @@ check_server_certificate(dtls_context_t *ctx, return 0; } +#endif /* DTLS_ECC */ + +#ifdef DTLS_X509 +static int +check_peer_certificate_x509(dtls_context_t *ctx, + dtls_peer_t *peer, + uint8 *data, size_t data_length) +{ + int ret; + dtls_handshake_parameters_t *config = peer->handshake_params; + int cert_length; + + dtls_info("\n check_peer_certificate_x509\n"); + update_hs_hash(peer, data, data_length); + + assert(is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(config->cipher)); + + data += DTLS_HS_LENGTH; + + cert_length = dtls_uint24_to_int(data); + data += sizeof(uint24); + + ret = CALL(ctx, verify_x509_cert, &peer->session, data, cert_length, + config->keyx.ecc.other_pub_x, sizeof(config->keyx.ecc.other_pub_x), + config->keyx.ecc.other_pub_y, sizeof(config->keyx.ecc.other_pub_y)); + if (ret < 0) { + dtls_warn("The certificate was not accepted\n"); + return ret; + } + + return 0; +} +#endif /* DTLS_X509 */ +#if defined(DTLS_X509) || defined(DTLS_ECC) static int check_server_key_exchange_ecdsa(dtls_context_t *ctx, dtls_peer_t *peer, @@ -2683,13 +3243,13 @@ check_server_key_exchange_ecdsa(dtls_context_t *ctx, data += sizeof(uint8); data_length -= sizeof(uint8); - memcpy(config->keyx.ecdsa.other_eph_pub_x, data, sizeof(config->keyx.ecdsa.other_eph_pub_y)); - data += sizeof(config->keyx.ecdsa.other_eph_pub_y); - data_length -= sizeof(config->keyx.ecdsa.other_eph_pub_y); + memcpy(config->keyx.ecc.other_eph_pub_x, data, sizeof(config->keyx.ecc.other_eph_pub_y)); + data += sizeof(config->keyx.ecc.other_eph_pub_y); + data_length -= sizeof(config->keyx.ecc.other_eph_pub_y); - memcpy(config->keyx.ecdsa.other_eph_pub_y, data, sizeof(config->keyx.ecdsa.other_eph_pub_y)); - data += sizeof(config->keyx.ecdsa.other_eph_pub_y); - data_length -= sizeof(config->keyx.ecdsa.other_eph_pub_y); + memcpy(config->keyx.ecc.other_eph_pub_y, data, sizeof(config->keyx.ecc.other_eph_pub_y)); + data += sizeof(config->keyx.ecc.other_eph_pub_y); + data_length -= sizeof(config->keyx.ecc.other_eph_pub_y); ret = dtls_check_ecdsa_signature_elem(data, data_length, &result_r, &result_s); if (ret < 0) { @@ -2698,21 +3258,168 @@ check_server_key_exchange_ecdsa(dtls_context_t *ctx, data += ret; data_length -= ret; - ret = dtls_ecdsa_verify_sig(config->keyx.ecdsa.other_pub_x, config->keyx.ecdsa.other_pub_y, - sizeof(config->keyx.ecdsa.other_pub_x), - config->tmp.random.client, DTLS_RANDOM_LENGTH, - config->tmp.random.server, DTLS_RANDOM_LENGTH, - key_params, - 1 + 2 + 1 + 1 + (2 * DTLS_EC_KEY_SIZE), - result_r, result_s); + ret = dtls_ecdsa_verify_sig(config->keyx.ecc.other_pub_x, config->keyx.ecc.other_pub_y, + sizeof(config->keyx.ecc.other_pub_x), + config->tmp.random.client, DTLS_RANDOM_LENGTH, + config->tmp.random.server, DTLS_RANDOM_LENGTH, + key_params, + 1 + 2 + 1 + 1 + (2 * DTLS_EC_KEY_SIZE), + result_r, result_s); - if (ret < 0) { + if (ret <= 0) { dtls_alert("wrong signature\n"); return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); } return 0; } + +static int +check_server_key_exchange_ecdh(dtls_context_t *ctx, + dtls_peer_t *peer, + uint8 *data, size_t data_length) +{ + dtls_handshake_parameters_t *config = peer->handshake_params; + + update_hs_hash(peer, data, data_length); + + assert(is_tls_ecdh_anon_with_aes_128_cbc_sha_256(config->cipher)); + + data += DTLS_HS_LENGTH; + + if (data_length < DTLS_HS_LENGTH + DTLS_SKEXEC_ECDH_ANON_LENGTH) { + dtls_alert("the packet length does not match the expected\n"); + return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); + } + + if (dtls_uint8_to_int(data) != TLS_EC_CURVE_TYPE_NAMED_CURVE) { + dtls_alert("Only named curves supported\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + data += sizeof(uint8); + data_length -= sizeof(uint8); + + if (dtls_uint16_to_int(data) != TLS_EXT_ELLIPTIC_CURVES_SECP256R1) { + dtls_alert("secp256r1 supported\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + data += sizeof(uint16); + data_length -= sizeof(uint16); + + if (dtls_uint8_to_int(data) != 1 + 2 * DTLS_EC_KEY_SIZE) { + dtls_alert("expected 65 bytes long public point\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + data += sizeof(uint8); + data_length -= sizeof(uint8); + + if (dtls_uint8_to_int(data) != 4) { + dtls_alert("expected uncompressed public point\n"); + return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); + } + data += sizeof(uint8); + data_length -= sizeof(uint8); + + memcpy(config->keyx.ecc.other_eph_pub_x, data, sizeof(config->keyx.ecc.other_eph_pub_x)); + data += sizeof(config->keyx.ecc.other_eph_pub_x); + data_length -= sizeof(config->keyx.ecc.other_eph_pub_x); + + memcpy(config->keyx.ecc.other_eph_pub_y, data, sizeof(config->keyx.ecc.other_eph_pub_y)); + data += sizeof(config->keyx.ecc.other_eph_pub_y); + data_length -= sizeof(config->keyx.ecc.other_eph_pub_y); + + return 0; +} #endif /* DTLS_ECC */ +#if defined(DTLS_PSK) && defined(DTLS_ECC) +check_server_key_exchange_ecdhe_psk(dtls_context_t *ctx, + dtls_peer_t *peer, + uint8 *data, size_t data_length) +{ + dtls_handshake_parameters_t *config = peer->handshake_params; + uint16_t psk_len = 0; + + /* ServerKeyExchange + * Please see Session 2, RFC 5489. + + struct { + select (KeyExchangeAlgorithm) { + //other cases for rsa, diffie_hellman, etc. + case ec_diffie_hellman_psk: // NEW + opaque psk_identity_hint<0..2^16-1>; + ServerECDHParams params; + }; + } ServerKeyExchange; */ + + update_hs_hash(peer, data, data_length); + + assert(is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(config->cipher)); + + data += DTLS_HS_LENGTH; + + psk_len = dtls_uint16_to_int(data); + data += sizeof(uint16); + + if (psk_len != data_length - DTLS_HS_LENGTH - DTLS_SKEXEC_ECDH_ANON_LENGTH - sizeof(uint16)) { + dtls_warn("the length of the server identity hint is worng\n"); + return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); + } + + if (psk_len > DTLS_PSK_MAX_CLIENT_IDENTITY_LEN) { + dtls_warn("please use a smaller server identity hint\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + + // store the psk_identity_hint in config->keyx.psk for later use + config->keyx.psk.id_length = psk_len; + memcpy(config->keyx.psk.identity, data, psk_len); + + data += psk_len; + data_length -= psk_len; + + if (data_length < DTLS_HS_LENGTH + DTLS_SKEXEC_ECDH_ANON_LENGTH) { + dtls_alert("the packet length does not match the expected\n"); + return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); + } + + if (dtls_uint8_to_int(data) != TLS_EC_CURVE_TYPE_NAMED_CURVE) { + dtls_alert("Only named curves supported\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + data += sizeof(uint8); + data_length -= sizeof(uint8); + + if (dtls_uint16_to_int(data) != TLS_EXT_ELLIPTIC_CURVES_SECP256R1) { + dtls_alert("secp256r1 supported\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + data += sizeof(uint16); + data_length -= sizeof(uint16); + + if (dtls_uint8_to_int(data) != 1 + 2 * DTLS_EC_KEY_SIZE) { + dtls_alert("expected 65 bytes long public point\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + data += sizeof(uint8); + data_length -= sizeof(uint8); + + if (dtls_uint8_to_int(data) != 4) { + dtls_alert("expected uncompressed public point\n"); + return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); + } + data += sizeof(uint8); + data_length -= sizeof(uint8); + + memcpy(config->keyx.ecc.other_eph_pub_x, data, sizeof(config->keyx.ecc.other_eph_pub_x)); + data += sizeof(config->keyx.ecc.other_eph_pub_x); + data_length -= sizeof(config->keyx.ecc.other_eph_pub_x); + + memcpy(config->keyx.ecc.other_eph_pub_y, data, sizeof(config->keyx.ecc.other_eph_pub_y)); + data += sizeof(config->keyx.ecc.other_eph_pub_y); + data_length -= sizeof(config->keyx.ecc.other_eph_pub_y); + + return 0; +} +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ #ifdef DTLS_PSK static int @@ -2833,13 +3540,17 @@ check_certificate_request(dtls_context_t *ctx, } static int -check_server_hellodone(dtls_context_t *ctx, +check_server_hellodone(dtls_context_t *ctx, dtls_peer_t *peer, uint8 *data, size_t data_length) { - int res; + int res = 0; #ifdef DTLS_ECC - const dtls_ecdsa_key_t *ecdsa_key; + const dtls_ecc_key_t *ecdsa_key; +#ifdef DTLS_X509 + unsigned char *cert; + size_t cert_size; +#endif /* DTLS_X509 */ #endif /* DTLS_ECC */ dtls_handshake_parameters_t *handshake = peer->handshake_params; @@ -2848,16 +3559,25 @@ check_server_hellodone(dtls_context_t *ctx, update_hs_hash(peer, data, data_length); -#ifdef DTLS_ECC - if (handshake->do_client_auth) { - - res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key); +#if defined(DTLS_ECC) || defined(DTLS_X509) + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) && handshake->do_client_auth) { +#ifdef DTLS_X509 + if (CALL(ctx, is_x509_active) == 0) + res = CALL(ctx, get_x509_key, &peer->session, &ecdsa_key); + else +#endif /* DTLS_X509 */ + res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key); if (res < 0) { - dtls_crit("no ecdsa certificate to send in certificate\n"); + dtls_crit("no ecdsa key to use\n"); return res; } - res = dtls_send_certificate_ecdsa(ctx, peer, ecdsa_key); +#ifdef DTLS_X509 + if (CALL(ctx, is_x509_active) == 0) + res = dtls_send_certificate_x509(ctx, peer); + else +#endif /* DTLS_X509 */ + res = dtls_send_certificate_ecdsa(ctx, peer, ecdsa_key); if (res < 0) { dtls_debug("dtls_server_hello: cannot prepare Certificate record\n"); @@ -2875,8 +3595,7 @@ check_server_hellodone(dtls_context_t *ctx, } #ifdef DTLS_ECC - if (handshake->do_client_auth) { - + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) && handshake->do_client_auth) { res = dtls_send_certificate_verify_ecdh(ctx, peer, ecdsa_key); if (res < 0) { @@ -2924,6 +3643,26 @@ 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 if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(security->cipher) || + is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(security->cipher)) { + + unsigned char nonce[DTLS_CBC_IV_LENGTH]; + + if (clen < (DTLS_CBC_IV_LENGTH + DTLS_HMAC_DIGEST_SIZE)) /* need at least IV and MAC */ + return -1; + + memcpy(nonce, *cleartext , DTLS_CBC_IV_LENGTH); + clen -= DTLS_CBC_IV_LENGTH; + *cleartext += DTLS_CBC_IV_LENGTH ; + + clen = dtls_decrypt(*cleartext, clen, *cleartext, nonce, + dtls_kb_remote_write_key(security, peer->role), + dtls_kb_key_size(security, peer->role), + dtls_kb_remote_mac_secret(security, peer->role), + dtls_kb_mac_secret_size(security->cipher), + NULL, 0, + security->cipher); + } else { /* TLS_PSK_WITH_AES_128_CCM_8 or TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 */ /** * length of additional_data for the AEAD cipher which consists of @@ -2938,10 +3677,10 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, memset(nonce, 0, DTLS_CCM_BLOCKSIZE); memcpy(nonce, dtls_kb_remote_iv(security, peer->role), - dtls_kb_iv_size(security, peer->role)); + dtls_kb_iv_size(security->cipher)); /* read epoch and seq_num from message */ - memcpy(nonce + dtls_kb_iv_size(security, peer->role), *cleartext, 8); + memcpy(nonce + dtls_kb_iv_size(security->cipher), *cleartext, 8); *cleartext += 8; clen -= 8; @@ -2962,17 +3701,22 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, clen = dtls_decrypt(*cleartext, clen, *cleartext, nonce, dtls_kb_remote_write_key(security, peer->role), dtls_kb_key_size(security, peer->role), - A_DATA, A_DATA_LEN); - if (clen < 0) - dtls_warn("decryption failed\n"); - else { + dtls_kb_remote_mac_secret(security, peer->role), + dtls_kb_mac_secret_size(security->cipher), + A_DATA, A_DATA_LEN, + security->cipher); + } + + if (clen < 0) + dtls_warn("decryption failed\n"); + else { #ifndef NDEBUG - printf("decrypt_verify(): found %i bytes cleartext\n", clen); + dtls_debug("decrypt_verify(): found %i bytes cleartext\n", clen); #endif - dtls_security_params_free_other(peer); - dtls_debug_dump("cleartext", *cleartext, clen); - } + dtls_security_params_free_other(peer); + dtls_debug_dump("cleartext", *cleartext, clen); } + return clen; } @@ -3072,23 +3816,31 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session, return err; } if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) - peer->state = DTLS_STATE_WAIT_SERVERCERTIFICATE; + peer->state = DTLS_STATE_WAIT_SERVERCERTIFICATE; //ecdsa + else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(peer->handshake_params->cipher) || + is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(peer->handshake_params->cipher)) + peer->state = DTLS_STATE_WAIT_SERVERKEYEXCHANGE; //ecdh else - peer->state = DTLS_STATE_WAIT_SERVERHELLODONE; + peer->state = DTLS_STATE_WAIT_SERVERHELLODONE; //psk /* update_hs_hash(peer, data, data_length); */ break; -#ifdef DTLS_ECC +#if defined(DTLS_ECC) || defined(DTLS_X509) case DTLS_HT_CERTIFICATE: if ((role == DTLS_CLIENT && state != DTLS_STATE_WAIT_SERVERCERTIFICATE) || (role == DTLS_SERVER && state != DTLS_STATE_WAIT_CLIENTCERTIFICATE)) { return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); } - err = check_server_certificate(ctx, peer, data, data_length); +#ifdef DTLS_X509 + if (CALL(ctx, is_x509_active) == 0) + err = check_peer_certificate_x509(ctx, peer, data, data_length); + else +#endif /* DTLS_X509 */ + err = check_peer_certificate(ctx, peer, data, data_length); if (err < 0) { - dtls_warn("error in check_server_certificate err: %i\n", err); + dtls_warn("error in check_peer_certificate err: %i\n", err); return err; } if (role == DTLS_CLIENT) { @@ -3103,14 +3855,31 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session, case DTLS_HT_SERVER_KEY_EXCHANGE: -#ifdef DTLS_ECC +#if defined(DTLS_ECC) || defined(DTLS_X509) if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) { if (state != DTLS_STATE_WAIT_SERVERKEYEXCHANGE) { return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); } err = check_server_key_exchange_ecdsa(ctx, peer, data, data_length); } + + if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(peer->handshake_params->cipher)) { + if (state != DTLS_STATE_WAIT_SERVERKEYEXCHANGE) { + return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); + } + err = check_server_key_exchange_ecdh(ctx, peer, data, data_length); + } #endif /* DTLS_ECC */ + +#if defined(DTLS_PSK) && defined(DTLS_ECC) + if (is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(peer->handshake_params->cipher)) { + if (state != DTLS_STATE_WAIT_SERVERKEYEXCHANGE) { + return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); + } + err = check_server_key_exchange_ecdhe_psk(ctx, peer, data, data_length); + } +#endif defined(DTLS_PSK) && defined(DTLS_ECC) + #ifdef DTLS_PSK if (is_tls_psk_with_aes_128_ccm_8(peer->handshake_params->cipher)) { if (state != DTLS_STATE_WAIT_SERVERHELLODONE) { @@ -3218,13 +3987,13 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session, update_hs_hash(peer, data, data_length); if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher) && - is_ecdsa_client_auth_supported(ctx)) - peer->state = DTLS_STATE_WAIT_CERTIFICATEVERIFY; + (is_ecdsa_client_auth_supported(ctx) || (is_x509_client_auth_supported(ctx)))) + peer->state = DTLS_STATE_WAIT_CERTIFICATEVERIFY; //ecdsa else - peer->state = DTLS_STATE_WAIT_CHANGECIPHERSPEC; + peer->state = DTLS_STATE_WAIT_CHANGECIPHERSPEC; //psk || ecdh_anon break; -#ifdef DTLS_ECC +#if defined(DTLS_ECC) || defined(DTLS_X509) case DTLS_HT_CERTIFICATE_VERIFY: if (state != DTLS_STATE_WAIT_CERTIFICATEVERIFY) { @@ -3341,10 +4110,10 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session, return err; } if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher) && - is_ecdsa_client_auth_supported(ctx)) - peer->state = DTLS_STATE_WAIT_CLIENTCERTIFICATE; + (is_ecdsa_client_auth_supported(ctx) || (is_x509_client_auth_supported(ctx)))) + peer->state = DTLS_STATE_WAIT_CLIENTCERTIFICATE; //ecdhe else - peer->state = DTLS_STATE_WAIT_CLIENTKEYEXCHANGE; + peer->state = DTLS_STATE_WAIT_CLIENTKEYEXCHANGE; //psk, ecdh_anon /* after sending the ServerHelloDone, we expect the * ClientKeyExchange (possibly containing the PSK id), @@ -3506,7 +4275,6 @@ handle_ccs(dtls_context_t *ctx, dtls_peer_t *peer, uint8 *record_header, uint8 *data, size_t data_length) { int err; - dtls_handshake_parameters_t *handshake = peer->handshake_params; /* A CCS message is handled after a KeyExchange message was * received from the client. When security parameters have been @@ -3522,6 +4290,7 @@ handle_ccs(dtls_context_t *ctx, dtls_peer_t *peer, if (data_length < 1 || data[0] != 1) return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); + dtls_handshake_parameters_t *handshake = peer->handshake_params; /* Just change the cipher when we are on the same epoch */ if (peer->role == DTLS_SERVER) { err = calculate_key_block(ctx, handshake, peer, @@ -3668,12 +4437,16 @@ dtls_handle_message(dtls_context_t *ctx, data = msg + DTLS_RH_LENGTH; data_length = rlen - DTLS_RH_LENGTH; state = DTLS_STATE_WAIT_CLIENTHELLO; - role = DTLS_SERVER; + role = DTLS_SERVER; } else { int err = dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR); dtls_info("decrypt_verify() failed\n"); if (peer->state < DTLS_STATE_CONNECTED) { dtls_alert_send_from_err(ctx, peer, &peer->session, err); + + (void)CALL(ctx, event, &peer->session, + DTLS_ALERT_LEVEL_FATAL, DTLS_ALERT_HANDSHAKE_FAILURE); + peer->state = DTLS_STATE_CLOSED; /* dtls_stop_retransmission(ctx, peer); */ dtls_destroy_peer(ctx, peer, 1); @@ -3710,11 +4483,14 @@ dtls_handle_message(dtls_context_t *ctx, if (err < 0) { dtls_warn("error while handling ChangeCipherSpec message\n"); dtls_alert_send_from_err(ctx, peer, session, err); + if (peer) { + (void)CALL(ctx, event, &peer->session, + DTLS_ALERT_LEVEL_FATAL, DTLS_ALERT_HANDSHAKE_FAILURE); - /* invalidate peer */ - dtls_destroy_peer(ctx, peer, 1); - peer = NULL; - + /* invalidate peer */ + dtls_destroy_peer(ctx, peer, 1); + peer = NULL; + } return err; } break; @@ -3766,6 +4542,13 @@ dtls_handle_message(dtls_context_t *ctx, if (err < 0) { dtls_warn("error while handling handshake packet\n"); dtls_alert_send_from_err(ctx, peer, session, err); + + if (peer) { + (void)CALL(ctx, event, &peer->session, + DTLS_ALERT_LEVEL_FATAL, DTLS_ALERT_HANDSHAKE_FAILURE); + dtls_destroy_peer(ctx, peer, 1); + } + return err; } if (peer && peer->state == DTLS_STATE_CONNECTED) { @@ -3818,6 +4601,7 @@ dtls_new_context(void *app_data) { if (fread(buf, 1, sizeof(buf), urandom) != sizeof(buf)) { dtls_emerg("cannot initialize PRNG\n"); + fclose(urandom); return NULL; } @@ -3913,7 +4697,7 @@ dtls_connect_peer(dtls_context_t *ctx, dtls_peer_t *peer) { res = dtls_send_client_hello(ctx, peer, NULL, 0); if (res < 0) dtls_warn("cannot send ClientHello\n"); - else + else peer->state = DTLS_STATE_CLIENTHELLO; return res; @@ -4030,6 +4814,44 @@ dtls_check_retransmit(dtls_context_t *context, clock_time_t *next) { *next = node->t; } +size_t +dtls_prf_with_current_keyblock(dtls_context_t *ctx, session_t *session, + const uint8_t* label, const uint32_t labellen, + const uint8_t* random1, const uint32_t random1len, + const uint8_t* random2, const uint32_t random2len, + uint8_t* buf, const uint32_t buflen) { + dtls_peer_t *peer = NULL; + dtls_security_parameters_t *security = NULL; + size_t keysize = 0; + + if(!ctx || !session || !label || !buf || labellen == 0 || buflen == 0) { + dtls_warn("dtls_prf_with_current_keyblock(): invalid parameter\n"); + return 0; + } + + peer = dtls_get_peer(ctx, session); + if (!peer) { + dtls_warn("dtls_prf_with_current_keyblock(): cannot find peer\n"); + return 0; + } + + security = dtls_security_params(peer); + if (!security) { + dtls_crit("dtls_prf_with_current_keyblock(): peer has empty security parameters\n"); + return 0; + } + + /* note that keysize should never be zero as bad things will happen */ + keysize = dtls_kb_size(security, peer->role); + assert(keysize > 0); + + return dtls_prf(security->key_block, keysize, + label, labellen, + random1, random1len, + random2, random2len, + buf, buflen); +} + #ifdef WITH_CONTIKI /*---------------------------------------------------------------------------*/ /* message retransmission */