From: Frederik Wedel-Heinen Date: Wed, 7 Feb 2024 12:30:00 +0000 (+0100) Subject: DTLS 1.3 record number encryption X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=919c71e2f56df66b42ef1a387197bf54b1bdfd7f;p=thirdparty%2Fopenssl.git DTLS 1.3 record number encryption Reviewed-by: Viktor Dukhovni Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/23511) --- diff --git a/include/internal/recordmethod.h b/include/internal/recordmethod.h index 53bd4ca6d2b..d68c1c56f9a 100644 --- a/include/internal/recordmethod.h +++ b/include/internal/recordmethod.h @@ -126,12 +126,15 @@ 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, + size_t snoffs, const EVP_CIPHER *ciph, size_t taglen, int mactype, diff --git a/include/openssl/dtls1.h b/include/openssl/dtls1.h index 024584f426e..e5096d1ef53 100644 --- a/include/openssl/dtls1.h +++ b/include/openssl/dtls1.h @@ -34,10 +34,11 @@ extern "C" { /* Special value for method supporting multiple versions */ # define DTLS_ANY_VERSION 0x1FFFF -/* lengths of messages */ +/* DTLS records and messages lengths and offsets */ # define DTLS1_COOKIE_LENGTH 255 +# define DTLS1_RT_HEADER_SEQ_OFFS 5 # define DTLS1_RT_HEADER_LENGTH 13 # define DTLS1_HM_HEADER_LENGTH 12 diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index 2db9fb11050..681c50889a9 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -845,12 +845,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, 0, 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 bd560c9a91a..eaf49dc5b75 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, size_t snoffs, 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 7ed4450e1b9..a939238ddef 100644 --- a/ssl/record/methods/dtls_meth.c +++ b/ssl/record/methods/dtls_meth.c @@ -365,6 +365,42 @@ static int dtls_retrieve_rlayer_buffered_record(OSSL_RECORD_LAYER *rl, return 0; } +/* rfc9147 section 4.2.3 */ +int dtls_crypt_sequence_number(EVP_CIPHER_CTX *ctx, unsigned char *seq, + unsigned char *rec_data, size_t rec_data_offs) +{ + unsigned char mask[16]; + int outlen, inlen; + unsigned char *iv, *in; + size_t i; + size_t seq_len = 6; + + if (ossl_assert(sizeof(mask) > rec_data_offs)) + inlen = (int)(sizeof(mask) - rec_data_offs); + else + return 0; + + iv = rec_data_offs == 0 ? NULL : rec_data; + in = rec_data + rec_data_offs; + memset(mask, 0, sizeof(mask)); + + if (!ossl_assert(inlen >= 0) + || (size_t)inlen > sizeof(mask) + || EVP_CipherInit_ex2(ctx, NULL, NULL, iv, 1, NULL) <= 0 + || EVP_CipherUpdate(ctx, mask, &outlen, in, inlen) <= 0 + || outlen != inlen + || EVP_CipherFinal_ex(ctx, mask + outlen, &outlen) <= 0 + || outlen != 0) + return 0; + + for (i = 0; i < seq_len; i++) + seq[i] ^= mask[i]; + + OPENSSL_cleanse(mask, sizeof(mask)); + + return 1; +} + /*- * Call this to get a new input record. * It will return <= 0 if more data is needed, normally due to an error @@ -516,6 +552,24 @@ int dtls_get_more_records(OSSL_RECORD_LAYER *rl) /* set state for later operations */ rl->rstate = SSL_ST_READ_HEADER; + /* + * rfc9147: + * This procedure requires the ciphertext length to be at least 16 bytes. + * Receivers MUST reject shorter records as if they had failed deprotection + * TODO(DTLSv1.3): This check will need to be modified when support for variable + * length headers is added. + */ + if (rl->sn_enc_ctx != NULL + && (rl->packet_length < DTLS1_RT_HEADER_LENGTH + 16 + || !dtls_crypt_sequence_number(rl->sn_enc_ctx, &(rl->sequence[2]), + rl->packet + DTLS1_RT_HEADER_LENGTH, + rl->sn_enc_offs))) { + /* sequence number encryption failed dump record */ + rr->length = 0; + rl->packet_length = 0; + goto again; + } + /* match epochs. NULL means the packet is dropped on the floor */ bitmap = dtls_get_bitmap(rl, rr, &is_next_epoch); if (bitmap == NULL) { @@ -628,8 +682,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, size_t snoffs, const EVP_CIPHER *ciph, size_t taglen, int mactype, const EVP_MD *md, COMP_METHOD *comp, @@ -683,9 +739,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, snoffs, 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 33c7140e151..3d1225d4091 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, size_t snoffs, 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, size_t snoffs, const EVP_CIPHER *ciph, size_t taglen, int mactype, const EVP_MD *md, COMP_METHOD *comp, @@ -426,9 +430,10 @@ 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, - taglen, mactype, md, comp); + ret = (*retrl)->funcs->set_crypto_state(*retrl, level, snkey, key, keylen, + iv, ivlen, mackey, mackeylen, + snciph, snoffs, ciph, taglen, mactype, md, + comp); if (ret != OSSL_RECORD_RETURN_SUCCESS) { OPENSSL_free(*retrl); diff --git a/ssl/record/methods/recmethod_local.h b/ssl/record/methods/recmethod_local.h index 73c45436f8f..d38ee2c7cd7 100644 --- a/ssl/record/methods/recmethod_local.h +++ b/ssl/record/methods/recmethod_local.h @@ -98,9 +98,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, size_t snoffs, const EVP_CIPHER *ciph, size_t taglen, int mactype, @@ -292,6 +294,9 @@ struct ossl_record_layer_st { /* cryptographic state */ EVP_CIPHER_CTX *enc_ctx; + /* cryptographic state for DTLS sequence numbers */ + EVP_CIPHER_CTX *sn_enc_ctx; + size_t sn_enc_offs; /* TLSv1.3 MAC ctx, only used with integrity-only cipher */ EVP_MAC_CTX *mac_ctx; @@ -417,6 +422,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(EVP_CIPHER_CTX *ctx, unsigned char *seq, + unsigned char *rec_data, size_t rec_data_offs); 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 6b5a1bed23e..b424cef278e 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, size_t snoffs, 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 53acb6f7a61..dd44764059c 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, size_t snoffs, const EVP_CIPHER *ciph, size_t taglen, int mactype, @@ -78,6 +80,27 @@ 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 && snciph != NULL) { + EVP_CIPHER_CTX *sn_ciph_ctx; + + sn_ciph_ctx = rl->sn_enc_ctx = EVP_CIPHER_CTX_new(); + + if (sn_ciph_ctx == NULL) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); + return OSSL_RECORD_RETURN_FATAL; + } + + rl->sn_enc_offs = snoffs; + + if (EVP_CIPHER_CTX_set_padding(sn_ciph_ctx, 0) + || 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 9275e19fbd3..aaf13051c47 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, size_t snoffs, 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 317ec169fb6..77b09720136 100644 --- a/ssl/record/methods/tls_common.c +++ b/ssl/record/methods/tls_common.c @@ -1387,8 +1387,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, size_t snoffs, const EVP_CIPHER *ciph, size_t taglen, int mactype, const EVP_MD *md, COMP_METHOD *comp, @@ -1430,9 +1432,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, snoffs, ciph, taglen, mactype, md, + comp); err: if (ret != OSSL_RECORD_RETURN_SUCCESS) { @@ -1452,6 +1455,7 @@ static void tls_int_free(OSSL_RECORD_LAYER *rl) tls_release_write_buffer(rl); EVP_CIPHER_CTX_free(rl->enc_ctx); + EVP_CIPHER_CTX_free(rl->sn_enc_ctx); EVP_MAC_CTX_free(rl->mac_ctx); EVP_MD_CTX_free(rl->md_ctx); #ifndef OPENSSL_NO_COMP @@ -1720,6 +1724,19 @@ 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(rl->sn_enc_ctx, recordstart + DTLS1_RT_HEADER_SEQ_OFFS, + recordstart + DTLS1_RT_HEADER_LENGTH, + rl->sn_enc_offs)) { + 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 0cf04d7fa7b..6d6555a715c 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, size_t snoffs, 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 7022d08cea1..10d3b864d86 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -81,16 +81,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, 0, 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, 0, NULL, + 0, NID_undef, NULL, NULL, NULL); /* SSLfatal already called in the event of failure */ return ret; @@ -1235,9 +1235,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, size_t snoffs, const EVP_CIPHER *ciph, size_t taglen, int mactype, const EVP_MD *md, const SSL_COMP *comp, const EVP_MD *kdfdigest) @@ -1413,9 +1415,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, snoffs, 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 13f09fda8cc..9bdf4f23bdd 100644 --- a/ssl/record/record.h +++ b/ssl/record/record.h @@ -174,9 +174,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 *iv, size_t ivlen, unsigned char *mackey, size_t mackeylen, + const EVP_CIPHER *snciph, size_t snoffs, 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 cda1f7f83bc..6cad3c07778 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, 0, 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, NULL, &c, + &hash, NULL, NULL, &comp, 0)) { /* Error is already recorded */ SSLfatal_alert(s, SSL_AD_INTERNAL_ERROR); return 0; diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index beece1153ab..e4f9bcbd8ae 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -3415,6 +3415,7 @@ void ssl3_free(SSL *s) sc->s3.tmp.pkey = NULL; ssl_evp_cipher_free(sc->s3.tmp.new_sym_enc); + ssl_evp_cipher_free(sc->s3.tmp.new_sym_enc_sn); ssl_evp_md_free(sc->s3.tmp.new_hash); OPENSSL_free(sc->s3.tmp.ctype); diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c index 2e9c26a231b..ea057f8a576 100644 --- a/ssl/ssl_ciph.c +++ b/ssl/ssl_ciph.c @@ -494,8 +494,51 @@ int ssl_cipher_get_evp_md_mac(SSL_CTX *ctx, const SSL_CIPHER *sslc, return 1; } +int ssl_cipher_get_evp_cipher_sn(SSL_CTX *ctx, const SSL_CIPHER *sslc, + const EVP_CIPHER **enc, size_t *inputoffs) +{ + 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); + } else { + int ecbnid = NID_undef; + + *enc = NULL; + + if ((sslc->algorithm_enc & SSL_AES128_ANY) != 0) { + ecbnid = NID_aes_128_ecb; + *inputoffs = 0; + } else if ((sslc->algorithm_enc & SSL_AES256_ANY) != 0) { + ecbnid = NID_aes_256_ecb; + *inputoffs = 0; + } else if (ossl_assert((sslc->algorithm_enc & SSL_CHACHA20) != 0)) { + ecbnid = NID_chacha20; + *inputoffs = 4; + } + + if (ecbnid != NID_undef) + *enc = ssl_evp_cipher_fetch(ctx->libctx, ecbnid, ctx->propq); + } + + if (*enc == NULL) + return 0; + } + 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, size_t *snencoffs, + const EVP_CIPHER **enc, + const EVP_MD **md, int *mac_pkey_type, size_t *mac_secret_size, SSL_COMP **comp, int use_etm) { @@ -525,12 +568,18 @@ 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_sn(ctx, c, snenc, snencoffs))) return 0; if (!ssl_cipher_get_evp_md_mac(ctx, c, md, mac_pkey_type, mac_secret_size)) { ssl_evp_cipher_free(*enc); + + if (snenc != NULL) + ssl_evp_cipher_free(*snenc); + return 0; } diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index 4f606c3ef0e..ac4e516ac8e 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -188,6 +188,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) @@ -1379,6 +1383,8 @@ 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; + size_t new_sym_enc_sn_offs; const EVP_MD *new_hash; int new_mac_pkey_type; size_t new_mac_secret_size; @@ -2593,11 +2599,15 @@ __owur int ossl_bytes_to_cipher_list(SSL_CONNECTION *s, PACKET *cipher_suites, void ssl_update_cache(SSL_CONNECTION *s, int mode); __owur int ssl_cipher_get_evp_cipher(SSL_CTX *ctx, const SSL_CIPHER *sslc, const EVP_CIPHER **enc); +__owur int ssl_cipher_get_evp_cipher_sn(SSL_CTX *ctx, const SSL_CIPHER *sslc, + const EVP_CIPHER **enc, size_t *inputoffs); __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(SSL_CTX *ctxc, const SSL_SESSION *s, - const EVP_CIPHER **enc, const EVP_MD **md, +__owur int ssl_cipher_get_evp(SSL_CTX *ctx, const SSL_SESSION *s, + const EVP_CIPHER **snenc, size_t *snencoffs, + 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 7f7af8a53a2..e0afdb62ade 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, 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 f64df4bd546..5dd1cd6e408 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, 0, NULL, 0, NID_undef, + NULL, NULL, NULL)) { /* SSLfatal already called */ return WORK_ERROR; } @@ -1849,8 +1849,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, 0, 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 2e9e24a8cf9..cbb3b051969 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, 0, 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, 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 dacf7248889..c10472370db 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,15 @@ 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 = NULL, **p_snc = SSL_CONNECTION_IS_DTLS(s) ? &snc : NULL; + size_t snoffs; 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, p_snc, &snoffs, &c, + &hash, &mac_type, &mac_secret_size, NULL, 0)) { /* Error is already recorded */ SSLfatal_alert(s, SSL_AD_INTERNAL_ERROR); return 0; @@ -366,6 +383,9 @@ 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; + s->s3.tmp.new_sym_enc_sn_offs = snoffs; 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 +402,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 +488,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 +519,8 @@ 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]; + size_t sn_input_offs = 0; unsigned char secret[EVP_MAX_MD_SIZE]; unsigned char hashval[EVP_MAX_MD_SIZE]; unsigned char *hash = hashval; @@ -507,7 +532,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 +585,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_sn(sctx, sslcipher, &sncipher, + &sn_input_offs))) { /* Error is already recorded */ SSLfatal_alert(s, SSL_AD_INTERNAL_ERROR); goto err; @@ -668,6 +696,8 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) if ((which & SSL3_CC_EARLY) == 0) { md = ssl_handshake_md(s); cipher = s->s3.tmp.new_sym_enc; + sncipher = s->s3.tmp.new_sym_enc_sn; + sn_input_offs = s->s3.tmp.new_sym_enc_sn_offs; mac_md = s->s3.tmp.new_hash; mac_pkey_type = s->s3.tmp.new_mac_pkey_type; if (!ssl3_digest_cached_records(s, 1) @@ -707,8 +737,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; } @@ -777,10 +807,9 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) } } - 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, sn_input_offs, cipher, taglen, mac_pkey_type, mac_md, NULL, md)) { /* SSLfatal already called */ goto err; @@ -793,8 +822,10 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which) if ((EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) == 0) ssl_evp_md_free(mac_md); ssl_evp_cipher_free(cipher); + ssl_evp_cipher_free(sncipher); } OPENSSL_cleanse(key, sizeof(key)); + OPENSSL_cleanse(snkey, sizeof(snkey)); OPENSSL_cleanse(secret, sizeof(secret)); if (iv != iv_intern) OPENSSL_free(iv); @@ -808,6 +839,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; @@ -835,8 +867,8 @@ 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; } @@ -846,12 +878,13 @@ int tls13_update_key(SSL_CONNECTION *s, int sending) if (SSL_CONNECTION_IS_DTLS(s)) dtls1_increment_epoch(s, which); - 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_sn_offs, + s->s3.tmp.new_sym_enc, + taglen, NID_undef, NULL, NULL, md)) { /* SSLfatal already called */ goto err; } @@ -865,6 +898,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 f1e6490f9f9..9cc5b167b00 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, 0, + 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, 0, + 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 79a81a9f4ac..6cc8dae29ba 100644 --- a/test/tls13secretstest.c +++ b/test/tls13secretstest.c @@ -157,6 +157,11 @@ const EVP_MD *ssl_handshake_md(SSL_CONNECTION *s) return EVP_sha256(); } +int ssl_cipher_get_evp_cipher_sn(SSL_CTX *ctx, const SSL_CIPHER *sslc, + const EVP_CIPHER **enc, size_t *inputoffs) { + return 0; +} + int ssl_cipher_get_evp_cipher(SSL_CTX *ctx, const SSL_CIPHER *sslc, const EVP_CIPHER **enc) { @@ -171,7 +176,9 @@ 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, size_t *snencoffs, + 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 +233,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, size_t snoffs, const EVP_CIPHER *ciph, size_t taglen, int mactype, const EVP_MD *md, const SSL_COMP *comp, const EVP_MD *kdfdigest)