diff --git a/crypto.h b/crypto.h index 68096e10..53547589 100644 --- a/crypto.h +++ b/crypto.h @@ -140,6 +140,7 @@ typedef struct dtls_user_parameters_t { */ dtls_cipher_t cipher_suites[DTLS_MAX_CIPHER_SUITES + 1]; unsigned int force_extended_master_secret:1; /** force extended master secret extension (RFC7627) */ + unsigned int force_renegotiation_info:1; /** force renegotiation info extension (RFC5746) */ } dtls_user_parameters_t; typedef struct { @@ -159,6 +160,7 @@ typedef struct { dtls_cipher_index_t 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; + unsigned int renegotiation_info:1; union { #ifdef DTLS_ECC dtls_handshake_parameters_ecdsa_t ecdsa; diff --git a/dtls.c b/dtls.c index 83b1e489..9491676a 100644 --- a/dtls.c +++ b/dtls.c @@ -140,6 +140,9 @@ memarray_t dtlscontext_storage; * ec point format := 6 bytes => 26 * sign. and hash algos := 8 bytes * extended master secret := 4 bytes => 12 + * + * (The ClientHello uses TLS_EMPTY_RENEGOTIATION_INFO_SCSV + * instead of renegotiation info) */ #define DTLS_CH_LENGTH sizeof(dtls_client_hello_t) /* no variable length fields! */ #define DTLS_COOKIE_LENGTH_MAX 32 @@ -660,6 +663,7 @@ static const dtls_user_parameters_t default_user_parameters = { }, #endif /* DTLS_DEFAULT_CIPHER_SUITES */ .force_extended_master_secret = 1, + .force_renegotiation_info = 1, }; /** only one compression method is currently defined */ @@ -1260,6 +1264,15 @@ dtls_check_tls_extension(dtls_peer_t *peer, if (verify_ext_sig_hash_algo(data, j)) goto error; break; + case TLS_EXT_RENEGOTIATION_INFO: + /* RFC 5746, minimal version, only empty info is supported */ + if (j == 1 && *data == 0) { + config->renegotiation_info = 1; + } else { + dtls_warn("only empty renegotiation info is supported.\n"); + goto error; + } + break; default: dtls_notice("unsupported tls extension: %i\n", i); break; @@ -1288,6 +1301,11 @@ dtls_check_tls_extension(dtls_peer_t *peer, goto error; } } + if (config->user_parameters.force_renegotiation_info) { + if (!config->renegotiation_info) { + goto error; + } + } return 0; error: @@ -1366,9 +1384,13 @@ dtls_update_parameters(dtls_context_t *ctx, } ok = 0; - while ((i >= (int)sizeof(uint16)) && !ok) { - config->cipher_index = get_cipher_index(config->user_parameters.cipher_suites, dtls_uint16_to_int(data)); - ok = known_cipher(ctx, config->cipher_index, 0); + while ((i >= (int)sizeof(uint16)) && (!ok || !config->renegotiation_info)) { + if (dtls_uint16_to_int(data) == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) { + config->renegotiation_info = 1; + } else if (!ok) { + config->cipher_index = get_cipher_index(config->user_parameters.cipher_suites, dtls_uint16_to_int(data)); + ok = known_cipher(ctx, config->cipher_index, 0); + } i -= sizeof(uint16); data += sizeof(uint16); } @@ -2435,10 +2457,11 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) * server certificate type := 5 bytes * ec_point_formats := 6 bytes * extended master secret := 4 bytes + * renegotiation info := 5 bytes * * (no elliptic_curves in ServerHello.) */ - uint8 buf[DTLS_SH_LENGTH + 2 + 5 + 5 + 6 + 4]; + uint8 buf[DTLS_SH_LENGTH + 2 + 5 + 5 + 6 + 4 + 5]; uint8 *p; uint8 extension_size; dtls_handshake_parameters_t * const handshake = peer->handshake_params; @@ -2446,6 +2469,7 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) const int ecdsa = is_key_exchange_ecdhe_ecdsa(handshake->cipher_index); extension_size = (handshake->extended_master_secret ? 4 : 0) + + (handshake->renegotiation_info ? 5 : 0) + (ecdsa ? 5 + 5 + 6 : 0); /* Handshake header */ @@ -2527,6 +2551,19 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) p += sizeof(uint16); } + if (handshake->renegotiation_info) { + /* RFC5746 minimal version, empty renegotiation info, 5 bytes */ + dtls_int_to_uint16(p, TLS_EXT_RENEGOTIATION_INFO); + p += sizeof(uint16); + + /* length of this extension type */ + dtls_int_to_uint16(p, 1); + p += sizeof(uint16); + + /* empty renegotiation info */ + *p++ = 0; + } + assert((buf <= p) && ((unsigned int)(p - buf) <= sizeof(buf))); /* TODO use the same record sequence number as in the ClientHello, @@ -3098,6 +3135,11 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); } + /* RFC5746 add RENEGOTIATION_INFO_SCSV */ + dtls_int_to_uint16(p, TLS_EMPTY_RENEGOTIATION_INFO_SCSV); + p += sizeof(uint16); + cipher_suites_size += sizeof(uint16); + /* set size of known cipher suites */ dtls_int_to_uint16(p_cipher_suites_size, cipher_suites_size); diff --git a/global.h b/global.h index ffc12167..d915aed1 100644 --- a/global.h +++ b/global.h @@ -74,10 +74,11 @@ typedef unsigned char uint48[6]; /** Known cipher suites.*/ typedef enum { TLS_NULL_WITH_NULL_NULL = 0x0000, /**< NULL cipher */ + TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF, /**< see RFC 5746 */ 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 */ + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = 0xC0AE, /**< see RFC 7251 */ } dtls_cipher_t; /** Known compression suites.*/ @@ -92,6 +93,7 @@ typedef enum { #define TLS_EXT_SERVER_CERTIFICATE_TYPE 20 /* see RFC 7250 */ #define TLS_EXT_ENCRYPT_THEN_MAC 22 /* see RFC 7366 */ #define TLS_EXT_EXTENDED_MASTER_SECRET 23 /* see RFC 7627 */ +#define TLS_EXT_RENEGOTIATION_INFO 65281 /* see RFC 5746 */ #define TLS_CERT_TYPE_RAW_PUBLIC_KEY 2 /* see RFC 7250 */