summaryrefslogtreecommitdiffstats
path: root/ssl/record
diff options
context:
space:
mode:
authorRajeev Ranjan <ranjan.rajeev@siemens.com>2023-12-01 12:47:07 +0100
committerTomas Mraz <tomas@openssl.org>2024-05-14 15:39:15 +0200
commitb6a5e801679663c13875cf6e18f475f8700d72a9 (patch)
tree437ddfdbc1fbcf49974cc2daa89bfeadd68876ae /ssl/record
parent61f32392dd67d47018ce46f427339e7191426e45 (diff)
Add support for integrity-only cipher suites for TLS v1.3
- add test vectors for tls1_3 integrity-only ciphers - recmethod_local.h: add new member for MAC - tls13_meth.c: add MAC only to tls 1.3 - tls13_enc.c: extend function to add MAC only - ssl_local.h: add ssl_cipher_get_evp_md_mac() - s3_lib.c: add the new ciphers and add #ifndef OPENSSL_NO_INTEGRITY_ONLY_CIPHERS - ssl_ciph.c : add ssl_cipher_get_evp_md_mac() and use it - tls13secretstest.c: add dummy test function - Configure: add integrity-only-ciphers option - document the new ciphers Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/22903)
Diffstat (limited to 'ssl/record')
-rw-r--r--ssl/record/methods/recmethod_local.h7
-rw-r--r--ssl/record/methods/tls13_meth.c127
-rw-r--r--ssl/record/methods/tls_common.c4
3 files changed, 104 insertions, 34 deletions
diff --git a/ssl/record/methods/recmethod_local.h b/ssl/record/methods/recmethod_local.h
index fe9dce1535..5a3d010503 100644
--- a/ssl/record/methods/recmethod_local.h
+++ b/ssl/record/methods/recmethod_local.h
@@ -295,6 +295,9 @@ struct ossl_record_layer_st
/* cryptographic state */
EVP_CIPHER_CTX *enc_ctx;
+ /* TLSv1.3 MAC ctx, only used with integrity-only cipher */
+ EVP_MAC_CTX *mac_ctx;
+
/* Explicit IV length */
size_t eivlen;
@@ -333,8 +336,8 @@ struct ossl_record_layer_st
int tlstree;
/* TLSv1.3 fields */
- /* static IV */
- unsigned char iv[EVP_MAX_IV_LENGTH];
+ unsigned char *iv; /* static IV */
+ unsigned char *nonce; /* part of static IV followed by sequence number */
int allow_plain_alerts;
/* TLS "any" fields */
diff --git a/ssl/record/methods/tls13_meth.c b/ssl/record/methods/tls13_meth.c
index d782c327ec..afae14ad22 100644
--- a/ssl/record/methods/tls13_meth.c
+++ b/ssl/record/methods/tls13_meth.c
@@ -24,15 +24,42 @@ static int tls13_set_crypto_state(OSSL_RECORD_LAYER *rl, int level,
COMP_METHOD *comp)
{
EVP_CIPHER_CTX *ciph_ctx;
+ EVP_MAC_CTX *mac_ctx;
+ EVP_MAC *mac;
+ OSSL_PARAM params[2], *p = params;
int mode;
int enc = (rl->direction == OSSL_RECORD_DIRECTION_WRITE) ? 1 : 0;
- if (ivlen > sizeof(rl->iv)) {
- ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
+ rl->iv = OPENSSL_malloc(ivlen);
+ if (rl->iv == NULL)
return OSSL_RECORD_RETURN_FATAL;
- }
+
+ rl->nonce = OPENSSL_malloc(ivlen);
+ if (rl->nonce == NULL)
+ return OSSL_RECORD_RETURN_FATAL;
+
memcpy(rl->iv, iv, ivlen);
+ /* Integrity only */
+ if (EVP_CIPHER_is_a(ciph, "NULL") && mactype == NID_hmac && md != NULL) {
+ mac = EVP_MAC_fetch(rl->libctx, "HMAC", rl->propq);
+ if (mac == NULL
+ || (mac_ctx = rl->mac_ctx = EVP_MAC_CTX_new(mac)) == NULL) {
+ EVP_MAC_free(mac);
+ ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
+ return OSSL_RECORD_RETURN_FATAL;
+ }
+ EVP_MAC_free(mac);
+ *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
+ (char *)EVP_MD_name(md), 0);
+ *p = OSSL_PARAM_construct_end();
+ if (!EVP_MAC_init(mac_ctx, key, keylen, params)) {
+ ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
+ return OSSL_RECORD_RETURN_FATAL;
+ }
+ goto end;
+ }
+
ciph_ctx = rl->enc_ctx = EVP_CIPHER_CTX_new();
if (ciph_ctx == NULL) {
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
@@ -51,7 +78,7 @@ 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;
}
-
+ end:
return OSSL_RECORD_RETURN_SUCCESS;
}
@@ -59,15 +86,18 @@ static int tls13_cipher(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *recs,
size_t n_recs, int sending, SSL_MAC_BUF *mac,
size_t macsize)
{
- EVP_CIPHER_CTX *ctx;
- unsigned char iv[EVP_MAX_IV_LENGTH], recheader[SSL3_RT_HEADER_LENGTH];
- size_t ivlen, offset, loop, hdrlen;
+ EVP_CIPHER_CTX *enc_ctx;
+ unsigned char recheader[SSL3_RT_HEADER_LENGTH];
+ unsigned char tag[EVP_MAX_MD_SIZE];
+ size_t nonce_len, offset, loop, hdrlen, taglen;
unsigned char *staticiv;
+ unsigned char *nonce;
unsigned char *seq = rl->sequence;
int lenu, lenf;
TLS_RL_RECORD *rec = &recs[0];
WPACKET wpkt;
const EVP_CIPHER *cipher;
+ EVP_MAC_CTX *mac_ctx = NULL;
int mode;
if (n_recs != 1) {
@@ -76,15 +106,14 @@ static int tls13_cipher(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *recs,
return 0;
}
- ctx = rl->enc_ctx;
+ enc_ctx = rl->enc_ctx; /* enc_ctx is ignored when rl->mac_ctx != NULL */
staticiv = rl->iv;
+ nonce = rl->nonce;
- cipher = EVP_CIPHER_CTX_get0_cipher(ctx);
- if (cipher == NULL) {
+ if (enc_ctx == NULL && rl->mac_ctx == NULL) {
RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return 0;
}
- mode = EVP_CIPHER_get_mode(cipher);
/*
* If we're sending an alert and ctx != NULL then we must be forcing
@@ -92,13 +121,17 @@ static int tls13_cipher(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *recs,
* plaintext alerts at certain points in the handshake. If we've got this
* far then we have already validated that a plaintext alert is ok here.
*/
- if (ctx == NULL || rec->type == SSL3_RT_ALERT) {
+ if (rec->type == SSL3_RT_ALERT) {
memmove(rec->data, rec->input, rec->length);
rec->input = rec->data;
return 1;
}
- ivlen = EVP_CIPHER_CTX_get_iv_length(ctx);
+ /* For integrity-only ciphers, nonce_len is same as MAC size */
+ if (rl->mac_ctx != NULL)
+ nonce_len = EVP_MAC_CTX_get_mac_size(rl->mac_ctx);
+ else
+ nonce_len = EVP_CIPHER_CTX_get_iv_length(enc_ctx);
if (!sending) {
/*
@@ -110,30 +143,22 @@ static int tls13_cipher(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *recs,
rec->length -= rl->taglen;
}
- /* Set up IV */
- if (ivlen < SEQ_NUM_SIZE) {
+ /* Set up nonce: part of static IV followed by sequence number */
+ if (nonce_len < SEQ_NUM_SIZE) {
/* Should not happen */
RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return 0;
}
- offset = ivlen - SEQ_NUM_SIZE;
- memcpy(iv, staticiv, offset);
+ offset = nonce_len - SEQ_NUM_SIZE;
+ memcpy(nonce, staticiv, offset);
for (loop = 0; loop < SEQ_NUM_SIZE; loop++)
- iv[offset + loop] = staticiv[offset + loop] ^ seq[loop];
+ nonce[offset + loop] = staticiv[offset + loop] ^ seq[loop];
if (!tls_increment_sequence_ctr(rl)) {
/* RLAYERfatal already called */
return 0;
}
- if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv, sending) <= 0
- || (!sending && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
- rl->taglen,
- rec->data + rec->length) <= 0)) {
- RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
/* Set up the AAD */
if (!WPACKET_init_static_len(&wpkt, recheader, sizeof(recheader), 0)
|| !WPACKET_put_bytes_u8(&wpkt, rec->type)
@@ -147,24 +172,64 @@ static int tls13_cipher(OSSL_RECORD_LAYER *rl, TLS_RL_RECORD *recs,
return 0;
}
+ if (rl->mac_ctx != NULL) {
+ int ret = 0;
+
+ if ((mac_ctx = EVP_MAC_CTX_dup(rl->mac_ctx)) == NULL
+ || !EVP_MAC_update(mac_ctx, nonce, nonce_len)
+ || !EVP_MAC_update(mac_ctx, recheader, sizeof(recheader))
+ || !EVP_MAC_update(mac_ctx, rec->input, rec->length)
+ || !EVP_MAC_final(mac_ctx, tag, &taglen, rl->taglen)) {
+ RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ goto end_mac;
+ }
+
+ if (sending) {
+ memcpy(rec->data + rec->length, tag, rl->taglen);
+ rec->length += rl->taglen;
+ } else if (CRYPTO_memcmp(tag, rec->data + rec->length,
+ rl->taglen) != 0) {
+ goto end_mac;
+ }
+ ret = 1;
+ end_mac:
+ EVP_MAC_CTX_free(mac_ctx);
+ return ret;
+ }
+
+ cipher = EVP_CIPHER_CTX_get0_cipher(enc_ctx);
+ if (cipher == NULL) {
+ RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ mode = EVP_CIPHER_get_mode(cipher);
+
+ if (EVP_CipherInit_ex(enc_ctx, NULL, NULL, NULL, nonce, sending) <= 0
+ || (!sending && EVP_CIPHER_CTX_ctrl(enc_ctx, EVP_CTRL_AEAD_SET_TAG,
+ rl->taglen,
+ rec->data + rec->length) <= 0)) {
+ RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
/*
* For CCM we must explicitly set the total plaintext length before we add
* any AAD.
*/
if ((mode == EVP_CIPH_CCM_MODE
- && EVP_CipherUpdate(ctx, NULL, &lenu, NULL,
+ && EVP_CipherUpdate(enc_ctx, NULL, &lenu, NULL,
(unsigned int)rec->length) <= 0)
- || EVP_CipherUpdate(ctx, NULL, &lenu, recheader,
+ || EVP_CipherUpdate(enc_ctx, NULL, &lenu, recheader,
sizeof(recheader)) <= 0
- || EVP_CipherUpdate(ctx, rec->data, &lenu, rec->input,
+ || EVP_CipherUpdate(enc_ctx, rec->data, &lenu, rec->input,
(unsigned int)rec->length) <= 0
- || EVP_CipherFinal_ex(ctx, rec->data + lenu, &lenf) <= 0
+ || EVP_CipherFinal_ex(enc_ctx, rec->data + lenu, &lenf) <= 0
|| (size_t)(lenu + lenf) != rec->length) {
return 0;
}
if (sending) {
/* Add the tag */
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, rl->taglen,
+ if (EVP_CIPHER_CTX_ctrl(enc_ctx, EVP_CTRL_AEAD_GET_TAG, rl->taglen,
rec->data + rec->length) <= 0) {
RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return 0;
diff --git a/ssl/record/methods/tls_common.c b/ssl/record/methods/tls_common.c
index d9e017d254..bf6dc0d1f5 100644
--- a/ssl/record/methods/tls_common.c
+++ b/ssl/record/methods/tls_common.c
@@ -1434,11 +1434,13 @@ static void tls_int_free(OSSL_RECORD_LAYER *rl)
tls_release_write_buffer(rl);
EVP_CIPHER_CTX_free(rl->enc_ctx);
+ EVP_MAC_CTX_free(rl->mac_ctx);
EVP_MD_CTX_free(rl->md_ctx);
#ifndef OPENSSL_NO_COMP
COMP_CTX_free(rl->compctx);
#endif
-
+ OPENSSL_free(rl->iv);
+ OPENSSL_free(rl->nonce);
if (rl->version == SSL3_VERSION)
OPENSSL_cleanse(rl->mac_secret, sizeof(rl->mac_secret));