From f4ea903aadcf8c0bf0bf085e8a9919b6443179d0 Mon Sep 17 00:00:00 2001 From: Frederik Wedel-Heinen Date: Wed, 7 Feb 2024 13:30:00 +0100 Subject: [PATCH] DTLS 1.3 record number encryption --- include/internal/recordmethod.h | 2 + ssl/d1_lib.c | 7 ++- ssl/quic/quic_tls.c | 6 ++- ssl/record/methods/dtls_meth.c | 60 ++++++++++++++++++++++--- ssl/record/methods/ktls_meth.c | 12 +++-- ssl/record/methods/recmethod_local.h | 8 ++++ ssl/record/methods/ssl3_meth.c | 2 + ssl/record/methods/tls13_meth.c | 20 +++++++++ ssl/record/methods/tls1_meth.c | 2 + ssl/record/methods/tls_common.c | 25 ++++++++--- ssl/record/methods/tlsany_meth.c | 2 + ssl/record/rec_layer_s3.c | 18 +++++--- ssl/record/record.h | 2 + ssl/s3_enc.c | 12 ++--- ssl/ssl_ciph.c | 41 ++++++++++++++++- ssl/ssl_local.h | 10 ++++- ssl/ssl_txt.c | 2 +- ssl/statem/statem_clnt.c | 11 ++--- ssl/t1_enc.c | 12 ++--- ssl/tls13_enc.c | 66 ++++++++++++++++++++-------- test/tls13encryptiontest.c | 6 ++- test/tls13secretstest.c | 5 ++- 22 files changed, 261 insertions(+), 70 deletions(-) diff --git a/include/internal/recordmethod.h b/include/internal/recordmethod.h index 53bd4ca6d2b11c..852e32f3946f69 100644 --- a/include/internal/recordmethod.h +++ b/include/internal/recordmethod.h @@ -126,12 +126,14 @@ struct ossl_record_method_st { uint16_t epoch, unsigned char *secret, size_t secretlen, + unsigned char *snkey, unsigned char *key, size_t keylen, unsigned char *iv, size_t ivlen, unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *snciph, const EVP_CIPHER *ciph, size_t taglen, int mactype, diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index a5b71559e5e3f5..3455a2b96de00b 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -844,12 +844,11 @@ int DTLSv1_listen(SSL *ssl, BIO_ADDR *client) * Reset the record layer - but this time we can use the record we just * buffered in s->rlayer.rrlnext */ - if (!ssl_set_new_record_layer(s, - DTLS_ANY_VERSION, + if (!ssl_set_new_record_layer(s, DTLS_ANY_VERSION, OSSL_RECORD_DIRECTION_READ, OSSL_RECORD_PROTECTION_LEVEL_NONE, NULL, 0, - NULL, 0, NULL, 0, NULL, 0, NULL, 0, - NID_undef, NULL, NULL, NULL)) { + NULL, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, + 0, NID_undef, NULL, NULL, NULL)) { /* SSLfatal already called */ ret = -1; goto end; diff --git a/ssl/quic/quic_tls.c b/ssl/quic/quic_tls.c index bd560c9a91a309..630a9676096406 100644 --- a/ssl/quic/quic_tls.c +++ b/ssl/quic/quic_tls.c @@ -91,8 +91,10 @@ static int quic_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, int role, int direction, int level, uint16_t epoch, unsigned char *secret, size_t secretlen, - unsigned char *key, size_t keylen, unsigned char *iv, - size_t ivlen, unsigned char *mackey, size_t mackeylen, + unsigned char *snkey, unsigned char *key, size_t keylen, + unsigned char *iv, size_t ivlen, + unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *snciph, const EVP_CIPHER *ciph, size_t taglen, int mactype, const EVP_MD *md, COMP_METHOD *comp, diff --git a/ssl/record/methods/dtls_meth.c b/ssl/record/methods/dtls_meth.c index 8c009bda4896ef..4b1d037d7eceb0 100644 --- a/ssl/record/methods/dtls_meth.c +++ b/ssl/record/methods/dtls_meth.c @@ -365,6 +365,44 @@ static int dtls_retrieve_rlayer_buffered_record(OSSL_RECORD_LAYER *rl, return 0; } +/* rfc9147 section 4.2.3 */ +int dtls_crypt_sequence_number(unsigned char *seq, size_t seq_len, + EVP_CIPHER_CTX *ctx, unsigned char *rec_data) +{ + static const size_t mask_size = 16; + unsigned char mask[mask_size]; + int outlen, inlen; + unsigned char *iv, *in; + const char *name = EVP_CIPHER_get0_name(EVP_CIPHER_CTX_get0_cipher(ctx)); + + memset(mask, 0, mask_size); + + if (strncmp(name, "AES", 3) == 0) { + iv = NULL; + in = rec_data; + inlen = 16; + } else if (strncmp(name, "Cha", 3) == 0) { + iv = rec_data; + in = rec_data + 4; + inlen = 12; + } else { + return 0; + } + + if (!ossl_assert(inlen >= 0) + || (size_t)inlen > mask_size + || seq_len > mask_size + || EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv, 1) <= 0 + || EVP_CipherUpdate(ctx, mask, &outlen, in, inlen) <= 0) { + return 0; + } + + for (size_t i = 0; i < seq_len; i++) + seq[i] ^= mask[i]; + + return 1; +} + /*- * Call this to get a new input record. * It will return <= 0 if more data is needed, normally due to an error @@ -445,6 +483,15 @@ int dtls_get_more_records(OSSL_RECORD_LAYER *rl) rl->msg_callback(0, rr->rec_version, SSL3_RT_HEADER, rl->packet, DTLS1_RT_HEADER_LENGTH, rl->cbarg); + if (rl->sn_enc_ctx != NULL + && !dtls_crypt_sequence_number(&(rl->sequence[2]), 6, + rl->sn_enc_ctx, rl->packet + 13)) { + /* unexpected version, silently discard */ + rr->length = 0; + rl->packet_length = 0; + goto again; + } + /* * Lets check the version. We tolerate alerts that don't have the exact * version number (e.g. because of protocol version errors) @@ -628,8 +675,10 @@ static int dtls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, int role, int direction, int level, uint16_t epoch, unsigned char *secret, size_t secretlen, - unsigned char *key, size_t keylen, unsigned char *iv, - size_t ivlen, unsigned char *mackey, size_t mackeylen, + unsigned char *snkey, unsigned char *key, size_t keylen, + unsigned char *iv, size_t ivlen, + unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *snciph, const EVP_CIPHER *ciph, size_t taglen, int mactype, const EVP_MD *md, COMP_METHOD *comp, @@ -683,9 +732,10 @@ dtls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, goto err; } - ret = (*retrl)->funcs->set_crypto_state(*retrl, level, key, keylen, iv, - ivlen, mackey, mackeylen, ciph, - taglen, mactype, md, comp); + ret = (*retrl)->funcs->set_crypto_state(*retrl, level, snkey, key, keylen, + iv, ivlen, mackey, mackeylen, + snciph, ciph, taglen, mactype, md, + comp); err: if (ret != OSSL_RECORD_RETURN_SUCCESS) { diff --git a/ssl/record/methods/ktls_meth.c b/ssl/record/methods/ktls_meth.c index 33c7140e151f0b..75c60a0cc223df 100644 --- a/ssl/record/methods/ktls_meth.c +++ b/ssl/record/methods/ktls_meth.c @@ -287,9 +287,11 @@ int ktls_configure_crypto(OSSL_LIB_CTX *libctx, int version, const EVP_CIPHER *c #endif /* OPENSSL_SYS_LINUX */ static int ktls_set_crypto_state(OSSL_RECORD_LAYER *rl, int level, + unsigned char *snkey, unsigned char *key, size_t keylen, unsigned char *iv, size_t ivlen, unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *snciph, const EVP_CIPHER *ciph, size_t taglen, int mactype, @@ -403,8 +405,10 @@ static int ktls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, int role, int direction, int level, uint16_t epoch, unsigned char *secret, size_t secretlen, - unsigned char *key, size_t keylen, unsigned char *iv, - size_t ivlen, unsigned char *mackey, size_t mackeylen, + unsigned char *snkey, unsigned char *key, size_t keylen, + unsigned char *iv, size_t ivlen, + unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *snciph, const EVP_CIPHER *ciph, size_t taglen, int mactype, const EVP_MD *md, COMP_METHOD *comp, @@ -426,8 +430,8 @@ ktls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, (*retrl)->funcs = &ossl_ktls_funcs; - ret = (*retrl)->funcs->set_crypto_state(*retrl, level, key, keylen, iv, - ivlen, mackey, mackeylen, ciph, + ret = (*retrl)->funcs->set_crypto_state(*retrl, level, snkey, key, keylen, + iv, ivlen, mackey, mackeylen, ciph, taglen, mactype, md, comp); if (ret != OSSL_RECORD_RETURN_SUCCESS) { diff --git a/ssl/record/methods/recmethod_local.h b/ssl/record/methods/recmethod_local.h index 0c6bf3ba63003f..07059ac360360d 100644 --- a/ssl/record/methods/recmethod_local.h +++ b/ssl/record/methods/recmethod_local.h @@ -99,9 +99,11 @@ struct record_functions_st * alternative record layer. */ int (*set_crypto_state)(OSSL_RECORD_LAYER *rl, int level, + unsigned char *snkey, unsigned char *key, size_t keylen, unsigned char *iv, size_t ivlen, unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *snciph, const EVP_CIPHER *ciph, size_t taglen, int mactype, @@ -298,6 +300,9 @@ struct ossl_record_layer_st /* TLSv1.3 MAC ctx, only used with integrity-only cipher */ EVP_MAC_CTX *mac_ctx; + /* cryptographic state for DTLS sequence numbers */ + EVP_CIPHER_CTX *sn_enc_ctx; + /* Explicit IV length */ size_t eivlen; @@ -418,6 +423,9 @@ int tls_free_buffers(OSSL_RECORD_LAYER *rl); int tls_default_read_n(OSSL_RECORD_LAYER *rl, size_t n, size_t max, int extend, int clearold, size_t *readbytes); int tls_get_more_records(OSSL_RECORD_LAYER *rl); + +int dtls_crypt_sequence_number(unsigned char *seq, size_t seq_len, + EVP_CIPHER_CTX *ctx, unsigned char *rec_data); int dtls_get_more_records(OSSL_RECORD_LAYER *rl); int dtls_prepare_record_header(OSSL_RECORD_LAYER *rl, diff --git a/ssl/record/methods/ssl3_meth.c b/ssl/record/methods/ssl3_meth.c index 6b5a1bed23ebe6..51686a08f46fac 100644 --- a/ssl/record/methods/ssl3_meth.c +++ b/ssl/record/methods/ssl3_meth.c @@ -15,9 +15,11 @@ #include "recmethod_local.h" static int ssl3_set_crypto_state(OSSL_RECORD_LAYER *rl, int level, + unsigned char *snkey, unsigned char *key, size_t keylen, unsigned char *iv, size_t ivlen, unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *snciph, const EVP_CIPHER *ciph, size_t taglen, int mactype, diff --git a/ssl/record/methods/tls13_meth.c b/ssl/record/methods/tls13_meth.c index b49faf542094d0..d22ddefb8994e9 100644 --- a/ssl/record/methods/tls13_meth.c +++ b/ssl/record/methods/tls13_meth.c @@ -14,9 +14,11 @@ #include "recmethod_local.h" static int tls13_set_crypto_state(OSSL_RECORD_LAYER *rl, int level, + unsigned char *snkey, unsigned char *key, size_t keylen, unsigned char *iv, size_t ivlen, unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *snciph, const EVP_CIPHER *ciph, size_t taglen, int mactype, @@ -78,6 +80,24 @@ static int tls13_set_crypto_state(OSSL_RECORD_LAYER *rl, int level, ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); return OSSL_RECORD_RETURN_FATAL; } + + if (rl->isdtls) { + EVP_CIPHER_CTX *sn_ciph_ctx; + + sn_ciph_ctx = rl->sn_enc_ctx = EVP_CIPHER_CTX_new(); + + if (sn_ciph_ctx == NULL || snciph == NULL) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + + if (EVP_CipherInit_ex(sn_ciph_ctx, snciph, NULL, + snkey, NULL, 1) <= 0) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + } + end: return OSSL_RECORD_RETURN_SUCCESS; } diff --git a/ssl/record/methods/tls1_meth.c b/ssl/record/methods/tls1_meth.c index 9275e19fbd3fb3..5c2c3db05c4561 100644 --- a/ssl/record/methods/tls1_meth.c +++ b/ssl/record/methods/tls1_meth.c @@ -17,9 +17,11 @@ #include "recmethod_local.h" static int tls1_set_crypto_state(OSSL_RECORD_LAYER *rl, int level, + unsigned char *snkey, unsigned char *key, size_t keylen, unsigned char *iv, size_t ivlen, unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *snciph, const EVP_CIPHER *ciph, size_t taglen, int mactype, diff --git a/ssl/record/methods/tls_common.c b/ssl/record/methods/tls_common.c index f363e10608b170..9a2dacd3c917fa 100644 --- a/ssl/record/methods/tls_common.c +++ b/ssl/record/methods/tls_common.c @@ -1378,8 +1378,10 @@ static int tls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, int role, int direction, int level, uint16_t epoch, unsigned char *secret, size_t secretlen, - unsigned char *key, size_t keylen, unsigned char *iv, - size_t ivlen, unsigned char *mackey, size_t mackeylen, + unsigned char *snkey, unsigned char *key, size_t keylen, + unsigned char *iv, size_t ivlen, + unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *snciph, const EVP_CIPHER *ciph, size_t taglen, int mactype, const EVP_MD *md, COMP_METHOD *comp, @@ -1421,9 +1423,10 @@ tls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, goto err; } - ret = (*retrl)->funcs->set_crypto_state(*retrl, level, key, keylen, iv, - ivlen, mackey, mackeylen, ciph, - taglen, mactype, md, comp); + ret = (*retrl)->funcs->set_crypto_state(*retrl, level, snkey, key, keylen, + iv, ivlen, mackey, mackeylen, + snciph, ciph, taglen, mactype, md, + comp); err: if (ret != OSSL_RECORD_RETURN_SUCCESS) { @@ -1711,6 +1714,18 @@ int tls_post_encryption_processing_default(OSSL_RECORD_LAYER *rl, return 0; } + if (rl->sn_enc_ctx != NULL) { + unsigned char *recordstart; + + recordstart = WPACKET_get_curr(thispkt) - len - headerlen; + + if (!dtls_crypt_sequence_number(recordstart + 5, 6, rl->sn_enc_ctx, + recordstart + 13)) { + RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); + return 0; + } + } + if (rl->msg_callback != NULL) { unsigned char *recordstart; const int version1_3 = rl->isdtls ? DTLS1_3_VERSION : TLS1_3_VERSION; diff --git a/ssl/record/methods/tlsany_meth.c b/ssl/record/methods/tlsany_meth.c index 0cf04d7fa7b252..7ec618adaa6b8d 100644 --- a/ssl/record/methods/tlsany_meth.c +++ b/ssl/record/methods/tlsany_meth.c @@ -15,9 +15,11 @@ #define MIN_SSL2_RECORD_LEN 9 static int tls_any_set_crypto_state(OSSL_RECORD_LAYER *rl, int level, + unsigned char *snkey, unsigned char *key, size_t keylen, unsigned char *iv, size_t ivlen, unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *snciph, const EVP_CIPHER *ciph, size_t taglen, int mactype, diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index e61861d9fd16ed..2eca429417d174 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -79,16 +79,16 @@ int RECORD_LAYER_reset(RECORD_LAYER *rl) ? DTLS_ANY_VERSION : TLS_ANY_VERSION, OSSL_RECORD_DIRECTION_READ, OSSL_RECORD_PROTECTION_LEVEL_NONE, NULL, 0, - NULL, 0, NULL, 0, NULL, 0, NULL, 0, - NID_undef, NULL, NULL, NULL); + NULL, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, + 0, NID_undef, NULL, NULL, NULL); ret &= ssl_set_new_record_layer(rl->s, SSL_CONNECTION_IS_DTLS(rl->s) ? DTLS_ANY_VERSION : TLS_ANY_VERSION, OSSL_RECORD_DIRECTION_WRITE, OSSL_RECORD_PROTECTION_LEVEL_NONE, NULL, 0, - NULL, 0, NULL, 0, NULL, 0, NULL, 0, - NID_undef, NULL, NULL, NULL); + NULL, NULL, 0, NULL, 0, NULL, 0, NULL, NULL, + 0, NID_undef, NULL, NULL, NULL); /* SSLfatal already called in the event of failure */ return ret; @@ -1233,9 +1233,11 @@ static int ssl_post_record_layer_select(SSL_CONNECTION *s, int direction) int ssl_set_new_record_layer(SSL_CONNECTION *s, int version, int direction, int level, unsigned char *secret, size_t secretlen, + unsigned char *snkey, unsigned char *key, size_t keylen, unsigned char *iv, size_t ivlen, unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *snciph, const EVP_CIPHER *ciph, size_t taglen, int mactype, const EVP_MD *md, const SSL_COMP *comp, const EVP_MD *kdfdigest) @@ -1409,9 +1411,11 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version, rlret = meth->new_record_layer(sctx->libctx, sctx->propq, version, s->server, direction, level, epoch, - secret, secretlen, key, keylen, iv, - ivlen, mackey, mackeylen, ciph, taglen, - mactype, md, compm, kdfdigest, prev, + secret, secretlen, snkey, key, keylen, + iv, + ivlen, mackey, mackeylen, snciph, ciph, + taglen, mactype, md, compm, kdfdigest, + prev, thisbio, next, NULL, NULL, settings, options, rlayer_dispatch_tmp, s, s->rlayer.rlarg, &newrl); diff --git a/ssl/record/record.h b/ssl/record/record.h index 9a076a1fb8865e..b9a596dc13df80 100644 --- a/ssl/record/record.h +++ b/ssl/record/record.h @@ -173,9 +173,11 @@ int ossl_tls_handle_rlayer_return(SSL_CONNECTION *s, int writing, int ret, int ssl_set_new_record_layer(SSL_CONNECTION *s, int version, int direction, int level, unsigned char *secret, size_t secretlen, + unsigned char *snkey, unsigned char *key, size_t keylen, unsigned char *iv, size_t ivlen, unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *snciph, const EVP_CIPHER *ciph, size_t taglen, int mactype, const EVP_MD *md, const SSL_COMP *comp, const EVP_MD *kdfdigest); diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c index 878556b069b266..dbb633bd87fb82 100644 --- a/ssl/s3_enc.c +++ b/ssl/s3_enc.c @@ -144,11 +144,11 @@ int ssl3_change_cipher_state(SSL_CONNECTION *s, int which) goto err; } - if (!ssl_set_new_record_layer(s, SSL3_VERSION, - direction, + if (!ssl_set_new_record_layer(s, SSL3_VERSION, direction, OSSL_RECORD_PROTECTION_LEVEL_APPLICATION, - NULL, 0, key, key_len, iv, iv_len, mac_secret, - md_len, ciph, 0, NID_undef, md, comp, NULL)) { + NULL, 0, NULL, key, key_len, iv, iv_len, + mac_secret, md_len, NULL, ciph, 0, NID_undef, + md, comp, NULL)) { /* SSLfatal already called */ goto err; } @@ -170,8 +170,8 @@ int ssl3_setup_key_block(SSL_CONNECTION *s) if (s->s3.tmp.key_block_length != 0) return 1; - if (!ssl_cipher_get_evp(SSL_CONNECTION_GET_CTX(s), s->session, &c, &hash, - NULL, NULL, &comp, 0)) { + if (!ssl_cipher_get_evp(SSL_CONNECTION_GET_CTX(s), s->session, NULL, &c, + &hash, NULL, NULL, &comp, 0)) { /* Error is already recorded */ SSLfatal_alert(s, SSL_AD_INTERNAL_ERROR); return 0; diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c index 5b154ea3f745a0..f0135b2da8002e 100644 --- a/ssl/ssl_ciph.c +++ b/ssl/ssl_ciph.c @@ -493,8 +493,43 @@ int ssl_cipher_get_evp_md_mac(SSL_CTX *ctx, const SSL_CIPHER *sslc, return 1; } +int ssl_cipher_get_evp_cipher_ecb(SSL_CTX *ctx, const SSL_CIPHER *sslc, + const EVP_CIPHER **enc) +{ + int i = ssl_cipher_info_lookup(ssl_cipher_table_cipher, sslc->algorithm_enc); + + if (i == -1) { + *enc = NULL; + } else { + if (i == SSL_ENC_NULL_IDX) { + /* + * We assume we don't care about this coming from an ENGINE so + * just do a normal EVP_CIPHER_fetch instead of + * ssl_evp_cipher_fetch() + */ + *enc = EVP_CIPHER_fetch(ctx->libctx, "NULL", ctx->propq); + if (*enc == NULL) + return 0; + } else { + char *ecb_name; + + if ((sslc->algorithm_enc & SSL_AES128_ANY) != 0) { + ecb_name = "AES-128-ECB"; + } else if ((sslc->algorithm_enc & SSL_AES256_ANY) != 0) { + ecb_name = "AES-256-ECB"; + } else if (ossl_assert((sslc->algorithm_enc & SSL_CHACHA20) != 0)) { + ecb_name = "ChaCha20"; + } + + *enc = EVP_CIPHER_fetch(ctx->libctx, ecb_name, ctx->propq); + } + } + return 1; +} + int ssl_cipher_get_evp(SSL_CTX *ctx, const SSL_SESSION *s, - const EVP_CIPHER **enc, const EVP_MD **md, + const EVP_CIPHER **snenc, const EVP_CIPHER **enc, + const EVP_MD **md, int *mac_pkey_type, size_t *mac_secret_size, SSL_COMP **comp, int use_etm) { @@ -524,7 +559,9 @@ int ssl_cipher_get_evp(SSL_CTX *ctx, const SSL_SESSION *s, if ((enc == NULL) || (md == NULL)) return 0; - if (!ssl_cipher_get_evp_cipher(ctx, c, enc)) + if (!ssl_cipher_get_evp_cipher(ctx, c, enc) + || (snenc != NULL + && !ssl_cipher_get_evp_cipher_ecb(ctx, c, snenc))) return 0; if (!ssl_cipher_get_evp_md_mac(ctx, c, md, mac_pkey_type, diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index c1970448c15cb8..9fc696de30ca49 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -193,6 +193,10 @@ # define SSL_AESGCM (SSL_AES128GCM | SSL_AES256GCM) # define SSL_AESCCM (SSL_AES128CCM | SSL_AES256CCM | SSL_AES128CCM8 | SSL_AES256CCM8) # define SSL_AES (SSL_AES128|SSL_AES256|SSL_AESGCM|SSL_AESCCM) +# define SSL_AES128_ANY (SSL_AES128 | SSL_AES128CCM | SSL_AES128CCM8 \ + | SSL_AES128GCM) +# define SSL_AES256_ANY (SSL_AES256 | SSL_AES256CCM | SSL_AES256CCM8 \ + | SSL_AES256GCM) # define SSL_CAMELLIA (SSL_CAMELLIA128|SSL_CAMELLIA256) # define SSL_CHACHA20 (SSL_CHACHA20POLY1305) # define SSL_ARIAGCM (SSL_ARIA128GCM | SSL_ARIA256GCM) @@ -1375,6 +1379,7 @@ struct ssl_connection_st { size_t key_block_length; unsigned char *key_block; const EVP_CIPHER *new_sym_enc; + const EVP_CIPHER *new_sym_enc_sn; const EVP_MD *new_hash; int new_mac_pkey_type; size_t new_mac_secret_size; @@ -2560,8 +2565,11 @@ __owur int ssl_cipher_get_evp_cipher(SSL_CTX *ctx, const SSL_CIPHER *sslc, __owur int ssl_cipher_get_evp_md_mac(SSL_CTX *ctx, const SSL_CIPHER *sslc, const EVP_MD **md, int *mac_pkey_type, size_t *mac_secret_size); +__owur int ssl_cipher_get_evp_cipher_ecb(SSL_CTX *ctx, const SSL_CIPHER *sslc, + const EVP_CIPHER **enc); __owur int ssl_cipher_get_evp(SSL_CTX *ctxc, const SSL_SESSION *s, - const EVP_CIPHER **enc, const EVP_MD **md, + const EVP_CIPHER **snenc, const EVP_CIPHER **enc, + const EVP_MD **md, int *mac_pkey_type, size_t *mac_secret_size, SSL_COMP **comp, int use_etm); __owur int ssl_cipher_get_overhead(const SSL_CIPHER *c, size_t *mac_overhead, diff --git a/ssl/ssl_txt.c b/ssl/ssl_txt.c index 58067027b1e33c..aec203d434ba39 100644 --- a/ssl/ssl_txt.c +++ b/ssl/ssl_txt.c @@ -119,7 +119,7 @@ int SSL_SESSION_print(BIO *bp, const SSL_SESSION *x) if (x->compress_meth != 0) { SSL_COMP *comp = NULL; - if (!ssl_cipher_get_evp(NULL, x, NULL, NULL, NULL, NULL, &comp, 0)) + if (!ssl_cipher_get_evp(NULL, x, NULL, NULL, NULL, NULL, NULL, &comp, 0)) goto err; if (comp == NULL) { if (BIO_printf(bp, "\n Compression: %d", x->compress_meth) <= 0) diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index 7abebde19db9db..3f2161ce6d191c 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -727,9 +727,9 @@ WORK_STATE ossl_statem_client_pre_work(SSL_CONNECTION *s, WORK_STATE wst) TLS_ANY_VERSION, OSSL_RECORD_DIRECTION_WRITE, OSSL_RECORD_PROTECTION_LEVEL_NONE, - NULL, 0, NULL, 0, NULL, 0, NULL, 0, - NULL, 0, NID_undef, NULL, NULL, - NULL)) { + NULL, 0, NULL, NULL, 0, NULL, 0, + NULL, 0, NULL, NULL, 0, NID_undef, + NULL, NULL, NULL)) { /* SSLfatal already called */ return WORK_ERROR; } @@ -1848,8 +1848,9 @@ static MSG_PROCESS_RETURN tls_process_as_hello_retry_request(SSL_CONNECTION *s, && !ssl_set_new_record_layer(s, versionany, OSSL_RECORD_DIRECTION_WRITE, OSSL_RECORD_PROTECTION_LEVEL_NONE, - NULL, 0, NULL, 0, NULL, 0, NULL, 0, - NULL, 0, NID_undef, NULL, NULL, NULL)) { + NULL, 0, NULL, NULL, 0, NULL, 0, NULL, + 0, NULL, NULL, 0, NID_undef, NULL, + NULL, NULL)) { /* SSLfatal already called */ goto err; } diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index 2e9e24a8cf94a3..46689cf77c06d7 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -232,10 +232,10 @@ int tls1_change_cipher_state(SSL_CONNECTION *s, int which) dtls1_increment_epoch(s, which); if (!ssl_set_new_record_layer(s, s->version, direction, - OSSL_RECORD_PROTECTION_LEVEL_APPLICATION, - NULL, 0, key, cl, iv, (size_t)k, mac_secret, - mac_secret_size, c, taglen, mac_type, - m, comp, NULL)) { + OSSL_RECORD_PROTECTION_LEVEL_APPLICATION, + NULL, 0, NULL, key, cl, iv, (size_t)k, + mac_secret, mac_secret_size, NULL, c, taglen, + mac_type, m, comp, NULL)) { /* SSLfatal already called */ goto err; } @@ -266,8 +266,8 @@ int tls1_setup_key_block(SSL_CONNECTION *s) if (s->s3.tmp.key_block_length != 0) return 1; - if (!ssl_cipher_get_evp(SSL_CONNECTION_GET_CTX(s), s->session, &c, &hash, - &mac_type, &mac_secret_size, &comp, + if (!ssl_cipher_get_evp(SSL_CONNECTION_GET_CTX(s), s->session, NULL, &c, + &hash, &mac_type, &mac_secret_size, &comp, s->ext.use_etm)) { /* Error is already recorded */ SSLfatal_alert(s, SSL_AD_INTERNAL_ERROR); diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index 861192a9477bf5..647ce04d510da3 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -178,6 +178,21 @@ int tls13_derive_finishedkey(SSL_CONNECTION *s, const EVP_MD *md, sizeof(finishedlabel) - 1, NULL, 0, fin, finlen, 1); } +/* + * Given a |secret| generate a |snkey| of length |snkeylen| bytes. Returns 1 on + * success 0 on failure. (rfc9147 section 4.2.3) + */ +static int dtls13_derive_snkey(SSL_CONNECTION *s, const EVP_MD *md, + const unsigned char *secret, + unsigned char *snkey, size_t keylen) +{ + /* ASCII: "sn", in hex for EBCDIC compatibility */ + static const unsigned char sn_str[] = "\x73\x6E"; + + return tls13_hkdf_expand(s, md, secret, sn_str, sizeof(sn_str) - 1, + NULL, 0, snkey, keylen, 1); +} + /* * Given the previous secret |prevsecret| and a new input secret |insecret| of * length |insecretlen|, generate a new secret and store it in the location @@ -352,13 +367,14 @@ size_t tls13_final_finish_mac(SSL_CONNECTION *s, const char *str, size_t slen, int tls13_setup_key_block(SSL_CONNECTION *s) { const EVP_CIPHER *c; + const EVP_CIPHER *snc; const EVP_MD *hash; int mac_type = NID_undef; size_t mac_secret_size = 0; s->session->cipher = s->s3.tmp.new_cipher; - if (!ssl_cipher_get_evp(SSL_CONNECTION_GET_CTX(s), s->session, &c, &hash, - &mac_type, &mac_secret_size, NULL, 0)) { + if (!ssl_cipher_get_evp(SSL_CONNECTION_GET_CTX(s), s->session, &snc, &c, + &hash, NULL, NULL, NULL, 0)) { /* Error is already recorded */ SSLfatal_alert(s, SSL_AD_INTERNAL_ERROR); return 0; @@ -366,6 +382,8 @@ int tls13_setup_key_block(SSL_CONNECTION *s) ssl_evp_cipher_free(s->s3.tmp.new_sym_enc); s->s3.tmp.new_sym_enc = c; + ssl_evp_cipher_free(s->s3.tmp.new_sym_enc_sn); + s->s3.tmp.new_sym_enc_sn = snc; ssl_evp_md_free(s->s3.tmp.new_hash); s->s3.tmp.new_hash = hash; s->s3.tmp.new_mac_pkey_type = mac_type; @@ -382,6 +400,7 @@ static int derive_secret_key_and_iv(SSL_CONNECTION *s, const EVP_MD *md, const unsigned char *hash, const unsigned char *label, size_t labellen, unsigned char *secret, + unsigned char *snkey, unsigned char *key, size_t *keylen, unsigned char **iv, size_t *ivlen, size_t *taglen) @@ -467,7 +486,9 @@ static int derive_secret_key_and_iv(SSL_CONNECTION *s, const EVP_MD *md, } if (!tls13_derive_key(s, md, secret, key, *keylen) - || !tls13_derive_iv(s, md, secret, *iv, *ivlen)) { + || !tls13_derive_iv(s, md, secret, *iv, *ivlen) + || (SSL_CONNECTION_IS_DTLS(s) + && !dtls13_derive_snkey(s, md, secret, snkey, *keylen))) { /* SSLfatal() already called */ return 0; } @@ -496,6 +517,7 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) unsigned char iv_intern[EVP_MAX_IV_LENGTH]; unsigned char *iv = iv_intern; unsigned char key[EVP_MAX_KEY_LENGTH]; + unsigned char snkey[EVP_MAX_KEY_LENGTH]; // has same len as key unsigned char secret[EVP_MAX_MD_SIZE]; unsigned char hashval[EVP_MAX_MD_SIZE]; unsigned char *hash = hashval; @@ -507,7 +529,7 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) size_t labellen, hashlen = 0; int ret = 0; const EVP_MD *md = NULL, *mac_md = NULL; - const EVP_CIPHER *cipher = NULL; + const EVP_CIPHER *cipher = NULL, *sncipher = NULL; int mac_pkey_type = NID_undef; SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s); size_t keylen, ivlen = EVP_MAX_IV_LENGTH, taglen; @@ -560,7 +582,10 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) * This ups the ref count on cipher so we better make sure we free * it again */ - if (!ssl_cipher_get_evp_cipher(sctx, sslcipher, &cipher)) { + if (!ssl_cipher_get_evp_cipher(sctx, sslcipher, &cipher) + || (SSL_CONNECTION_IS_DTLS(s) + && !ssl_cipher_get_evp_cipher_ecb(sctx, sslcipher, + &sncipher))) { /* Error is already recorded */ SSLfatal_alert(s, SSL_AD_INTERNAL_ERROR); goto err; @@ -670,6 +695,7 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) cipher = s->s3.tmp.new_sym_enc; mac_md = s->s3.tmp.new_hash; mac_pkey_type = s->s3.tmp.new_mac_pkey_type; + sncipher = s->s3.tmp.new_sym_enc_sn; if (!ssl3_digest_cached_records(s, 1) || !ssl_handshake_hash(s, hashval, sizeof(hashval), &hashlen)) { /* SSLfatal() already called */; @@ -707,8 +733,8 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) goto err; if (!derive_secret_key_and_iv(s, md, cipher, mac_pkey_type, mac_md, - insecret, hash, label, labellen, secret, key, - &keylen, &iv, &ivlen, &taglen)) { + insecret, hash, label, labellen, secret, + snkey, key, &keylen, &iv, &ivlen, &taglen)) { /* SSLfatal() already called */ goto err; } @@ -766,10 +792,9 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) dtls1_clear_sent_buffer(s); } - if (!ssl_set_new_record_layer(s, s->version, - direction, - level, secret, hashlen, key, keylen, iv, - ivlen, NULL, 0, cipher, taglen, + if (!ssl_set_new_record_layer(s, s->version, direction, level, secret, + hashlen, snkey, key, keylen, iv, ivlen, + NULL, 0, sncipher, cipher, taglen, mac_pkey_type, mac_md, NULL, md)) { /* SSLfatal already called */ goto err; @@ -784,6 +809,7 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) ssl_evp_cipher_free(cipher); } OPENSSL_cleanse(key, sizeof(key)); + OPENSSL_cleanse(snkey, sizeof(snkey)); OPENSSL_cleanse(secret, sizeof(secret)); if (iv != iv_intern) OPENSSL_free(iv); @@ -797,6 +823,7 @@ int tls13_update_key(SSL_CONNECTION *s, int sending) const EVP_MD *md = ssl_handshake_md(s); size_t hashlen; unsigned char key[EVP_MAX_KEY_LENGTH]; + unsigned char snkey[EVP_MAX_KEY_LENGTH]; unsigned char *insecret; unsigned char secret[EVP_MAX_MD_SIZE]; char *log_label; @@ -823,20 +850,20 @@ int tls13_update_key(SSL_CONNECTION *s, int sending) s->s3.tmp.new_mac_pkey_type, s->s3.tmp.new_hash, insecret, NULL, application_traffic, - sizeof(application_traffic) - 1, secret, key, - &keylen, &iv, &ivlen, &taglen)) { + sizeof(application_traffic) - 1, secret, snkey, + key, &keylen, &iv, &ivlen, &taglen)) { /* SSLfatal() already called */ goto err; } memcpy(insecret, secret, hashlen); - if (!ssl_set_new_record_layer(s, s->version, - direction, - OSSL_RECORD_PROTECTION_LEVEL_APPLICATION, - insecret, hashlen, key, keylen, iv, ivlen, NULL, 0, - s->s3.tmp.new_sym_enc, taglen, NID_undef, NULL, - NULL, md)) { + if (!ssl_set_new_record_layer(s, s->version, direction, + OSSL_RECORD_PROTECTION_LEVEL_APPLICATION, + insecret, hashlen, snkey, key, keylen, + iv, ivlen, NULL, 0, + s->s3.tmp.new_sym_enc_sn, s->s3.tmp.new_sym_enc, + taglen, NID_undef, NULL, NULL, md)) { /* SSLfatal already called */ goto err; } @@ -850,6 +877,7 @@ int tls13_update_key(SSL_CONNECTION *s, int sending) ret = 1; err: OPENSSL_cleanse(key, sizeof(key)); + OPENSSL_cleanse(snkey, sizeof(snkey)); OPENSSL_cleanse(secret, sizeof(secret)); if (iv != iv_intern) OPENSSL_free(iv); diff --git a/test/tls13encryptiontest.c b/test/tls13encryptiontest.c index f1e6490f9f900b..06e144530550e6 100644 --- a/test/tls13encryptiontest.c +++ b/test/tls13encryptiontest.c @@ -336,7 +336,8 @@ static int test_tls13_encryption(void) NULL, NULL, TLS1_3_VERSION, OSSL_RECORD_ROLE_SERVER, OSSL_RECORD_DIRECTION_WRITE, OSSL_RECORD_PROTECTION_LEVEL_APPLICATION, 0, NULL, 0, - key, 16, iv, ivlen, NULL, 0, EVP_aes_128_gcm(), + NULL, key, 16, iv, ivlen, NULL, 0, NULL, + EVP_aes_128_gcm(), EVP_GCM_TLS_TAG_LEN, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &wrl))) @@ -359,7 +360,8 @@ static int test_tls13_encryption(void) NULL, NULL, TLS1_3_VERSION, OSSL_RECORD_ROLE_SERVER, OSSL_RECORD_DIRECTION_READ, OSSL_RECORD_PROTECTION_LEVEL_APPLICATION, 0, NULL, 0, - key, 16, iv, ivlen, NULL, 0, EVP_aes_128_gcm(), + NULL, key, 16, iv, ivlen, NULL, 0, NULL, + EVP_aes_128_gcm(), EVP_GCM_TLS_TAG_LEN, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &rrl))) diff --git a/test/tls13secretstest.c b/test/tls13secretstest.c index 68ed06dd11ae9c..70dc7127d56509 100644 --- a/test/tls13secretstest.c +++ b/test/tls13secretstest.c @@ -171,7 +171,8 @@ int ssl_cipher_get_evp_md_mac(SSL_CTX *ctx, const SSL_CIPHER *sslc, } int ssl_cipher_get_evp(SSL_CTX *ctx, const SSL_SESSION *s, - const EVP_CIPHER **enc, const EVP_MD **md, + const EVP_CIPHER **snenc, const EVP_CIPHER **enc, + const EVP_MD **md, int *mac_pkey_type, size_t *mac_secret_size, SSL_COMP **comp, int use_etm) @@ -226,9 +227,11 @@ void ssl_evp_md_free(const EVP_MD *md) int ssl_set_new_record_layer(SSL_CONNECTION *s, int version, int direction, int level, unsigned char *secret, size_t secretlen, + unsigned char *snkey, unsigned char *key, size_t keylen, unsigned char *iv, size_t ivlen, unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *snciph, const EVP_CIPHER *ciph, size_t taglen, int mactype, const EVP_MD *md, const SSL_COMP *comp, const EVP_MD *kdfdigest)