Convert TLSv1.3 code to use the new read side record layer
authorMatt Caswell <matt@openssl.org>
Fri, 29 Apr 2022 16:13:23 +0000 (17:13 +0100)
committerMatt Caswell <matt@openssl.org>
Thu, 18 Aug 2022 15:38:12 +0000 (16:38 +0100)
Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18132)

ssl/record/methods/tlsrecord.c
ssl/tls13_enc.c

index 1646ba5ba1811832f9d4062f666365eb2845fe0f..5a50ef25f0ee0a66c01f6387221e0029339a5094 100644 (file)
@@ -104,6 +104,11 @@ struct ossl_record_layer_st
     /* Only used by SSLv3 */
     unsigned char mac_secret[EVP_MAX_MD_SIZE];
 
+    /* TLSv1.3 static IV */
+    unsigned char iv[EVP_MAX_IV_LENGTH];
+
+    size_t taglen;
+
     /* Function pointers for version specific functions */
     /* Function pointers for version specific functions */
     struct record_functions_st *funcs;
@@ -169,23 +174,6 @@ static int tls_provider_set_tls_parameters(OSSL_RECORD_LAYER *rl,
     return 1;
 }
 
-static int tls_fail_set_crypto_state(OSSL_RECORD_LAYER *rl, int level,
-                                     unsigned char *key, size_t keylen,
-                                     unsigned char *iv, size_t ivlen,
-                                     unsigned char *mackey, size_t mackeylen,
-                                     const EVP_CIPHER *ciph,
-                                     size_t taglen,
-                                     /* TODO(RECLAYER): This probably should not be an int */
-                                     int mactype,
-                                     const EVP_MD *md,
-                                     const SSL_COMP *comp,
-                                     /* TODO(RECLAYER): Remove me */
-                                     SSL_CONNECTION *s)
-{
-    RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-    return 0;
-}
-
 static int tls_any_set_crypto_state(OSSL_RECORD_LAYER *rl, int level,
                                     unsigned char *key, size_t keylen,
                                     unsigned char *iv, size_t ivlen,
@@ -410,6 +398,51 @@ static int tls1_set_crypto_state(OSSL_RECORD_LAYER *rl, int level,
     return 1;
 }
 
+static int tls13_set_crypto_state(OSSL_RECORD_LAYER *rl, int level,
+                                  unsigned char *key, size_t keylen,
+                                  unsigned char *iv, size_t ivlen,
+                                  unsigned char *mackey, size_t mackeylen,
+                                  const EVP_CIPHER *ciph,
+                                  size_t taglen,
+                                  /* TODO(RECLAYER): This probably should not be an int */
+                                  int mactype,
+                                  const EVP_MD *md,
+                                  const SSL_COMP *comp,
+                                  /* TODO(RECLAYER): Remove me */
+                                  SSL_CONNECTION *s)
+{
+    EVP_CIPHER_CTX *ciph_ctx;
+    int mode;
+
+    if (ivlen > sizeof(rl->iv)) {
+        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    memcpy(rl->iv, iv, ivlen);
+
+    ciph_ctx = rl->enc_read_ctx = EVP_CIPHER_CTX_new();
+    if (ciph_ctx == NULL) {
+        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    RECORD_LAYER_reset_read_sequence(&s->rlayer);
+    rl->taglen = taglen;
+
+    mode = EVP_CIPHER_get_mode(ciph);
+
+    if (EVP_DecryptInit_ex(ciph_ctx, ciph, NULL, NULL, NULL) <= 0
+        || !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_IVLEN, ivlen, NULL)
+        || (mode == EVP_CIPH_CCM_MODE
+            && !EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_TAG,  taglen, NULL))
+        || EVP_DecryptInit_ex(ciph_ctx, NULL, NULL, key, NULL) <= 0) {
+        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
+        return 0;
+    }
+
+    return 1;
+}
+
 static int tls_any_cipher(OSSL_RECORD_LAYER *rl, SSL3_RECORD *recs, size_t n_recs,
                           int sending, SSL_MAC_BUF *macs, size_t macsize,
                           /* TODO(RECLAYER): Remove me */ SSL_CONNECTION *s)
@@ -875,6 +908,139 @@ static int tls1_cipher(OSSL_RECORD_LAYER *rl, SSL3_RECORD *recs, size_t n_recs,
     return 1;
 }
 
+static int tls13_cipher(OSSL_RECORD_LAYER *rl, SSL3_RECORD *recs, size_t n_recs,
+                        int sending, SSL_MAC_BUF *mac, size_t macsize,
+                        /* TODO(RECLAYER): Remove me */ SSL_CONNECTION *s)
+{
+    EVP_CIPHER_CTX *ctx;
+    unsigned char iv[EVP_MAX_IV_LENGTH], recheader[SSL3_RT_HEADER_LENGTH];
+    size_t ivlen, offset, loop, hdrlen;
+    unsigned char *staticiv;
+    unsigned char *seq;
+    int lenu, lenf;
+    SSL3_RECORD *rec = &recs[0];
+    WPACKET wpkt;
+    const EVP_CIPHER *cipher;
+    int mode;
+
+    if (n_recs != 1) {
+        /* Should not happen */
+        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    if (sending) {
+        ctx = s->enc_write_ctx;
+        staticiv = s->write_iv;
+        seq = RECORD_LAYER_get_write_sequence(&s->rlayer);
+    } else {
+        ctx = rl->enc_read_ctx;
+        staticiv = rl->iv;
+        seq = RECORD_LAYER_get_read_sequence(&s->rlayer);
+    }
+
+    cipher = EVP_CIPHER_CTX_get0_cipher(ctx);
+    if (cipher == 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
+     * plaintext alerts. If we're reading and ctx != NULL then we allow
+     * 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) {
+        memmove(rec->data, rec->input, rec->length);
+        rec->input = rec->data;
+        return 1;
+    }
+
+    ivlen = EVP_CIPHER_CTX_get_iv_length(ctx);
+
+    if (!sending) {
+        /*
+         * Take off tag. There must be at least one byte of content type as
+         * well as the tag
+         */
+        if (rec->length < rl->taglen + 1)
+            return 0;
+        rec->length -= rl->taglen;
+    }
+
+    /* Set up IV */
+    if (ivlen < 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);
+    for (loop = 0; loop < SEQ_NUM_SIZE; loop++)
+        iv[offset + loop] = staticiv[offset + loop] ^ seq[loop];
+
+    /* Increment the sequence counter */
+    for (loop = SEQ_NUM_SIZE; loop > 0; loop--) {
+        ++seq[loop - 1];
+        if (seq[loop - 1] != 0)
+            break;
+    }
+    if (loop == 0) {
+        /* Sequence has wrapped */
+        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)
+            || !WPACKET_put_bytes_u16(&wpkt, rec->rec_version)
+            || !WPACKET_put_bytes_u16(&wpkt, rec->length + rl->taglen)
+            || !WPACKET_get_total_written(&wpkt, &hdrlen)
+            || hdrlen != SSL3_RT_HEADER_LENGTH
+            || !WPACKET_finish(&wpkt)) {
+        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        WPACKET_cleanup(&wpkt);
+        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,
+                                     (unsigned int)rec->length) <= 0)
+            || EVP_CipherUpdate(ctx, NULL, &lenu, recheader,
+                                sizeof(recheader)) <= 0
+            || EVP_CipherUpdate(ctx, rec->data, &lenu, rec->input,
+                                (unsigned int)rec->length) <= 0
+            || EVP_CipherFinal_ex(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,
+                                rec->data + rec->length) <= 0) {
+            RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        rec->length += rl->taglen;
+    }
+
+    return 1;
+}
+
 static const unsigned char ssl3_pad_1[48] = {
     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
     0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
@@ -1102,7 +1268,6 @@ static int tls1_mac(OSSL_RECORD_LAYER *rl, SSL3_RECORD *rec, unsigned char *md,
     return ret;
 }
 
-
 struct record_functions_st tls_any_funcs = {
     tls_any_set_crypto_state,
     tls_any_cipher,
@@ -1110,8 +1275,8 @@ struct record_functions_st tls_any_funcs = {
 };
 
 struct record_functions_st tls_1_3_funcs = {
-    tls_fail_set_crypto_state,
-    NULL,
+    tls13_set_crypto_state,
+    tls13_cipher,
     NULL
 };
 
@@ -1648,7 +1813,7 @@ static int tls_get_more_records(OSSL_RECORD_LAYER *rl,
                 }
 
                 if (SSL_CONNECTION_IS_TLS13(s)
-                        && s->enc_read_ctx != NULL
+                        && rl->enc_read_ctx != NULL
                         && !using_ktls) {
                     if (thisrr->type != SSL3_RT_APPLICATION_DATA
                             && (thisrr->type != SSL3_RT_CHANGE_CIPHER_SPEC
@@ -1866,10 +2031,7 @@ static int tls_get_more_records(OSSL_RECORD_LAYER *rl,
      * TODO(RECLAYER): Only call rl functions once TLSv1.3/SSLv3 is moved to new
      * record layer code
      */
-    if (!SSL_CONNECTION_IS_TLS13(s))
-        enc_err = rl->funcs->cipher(rl, rr, num_recs, 0, macbufs, mac_size, s);
-    else
-        enc_err = ssl->method->ssl3_enc->enc(s, rr, num_recs, 0, macbufs, mac_size);
+    enc_err = rl->funcs->cipher(rl, rr, num_recs, 0, macbufs, mac_size, s);
 
     /*-
      * enc_err is:
@@ -1970,7 +2132,7 @@ static int tls_get_more_records(OSSL_RECORD_LAYER *rl,
         }
 
         if (SSL_CONNECTION_IS_TLS13(s)
-                && s->enc_read_ctx != NULL
+                && rl->enc_read_ctx != NULL
                 && thisrr->type != SSL3_RT_ALERT) {
             /*
              * The following logic are irrelevant in KTLS: the kernel provides
@@ -2288,6 +2450,7 @@ static OSSL_RECORD_LAYER *dtls_new_record_layer(OSSL_LIB_CTX *libctx,
 
 static void tls_free(OSSL_RECORD_LAYER *rl)
 {
+    /* TODO(RECLAYER): Cleanse sensitive fields */
     BIO_free(rl->bio);
     OPENSSL_free(rl);
 }
index 1bfafcb3c93cfb66b8e667c36786e0594c9674ff..9001a4455a30696ffc2a56a259786d34732421cb 100644 (file)
@@ -344,12 +344,14 @@ static int derive_secret_key_and_iv(SSL_CONNECTION *s, int sending,
                                     const unsigned char *hash,
                                     const unsigned char *label,
                                     size_t labellen, unsigned char *secret,
-                                    unsigned char *key, unsigned char *iv,
+                                    unsigned char *key, size_t *keylen,
+                                    unsigned char *iv, size_t *ivlen,
+                                    size_t *taglen,
                                     EVP_CIPHER_CTX *ciph_ctx)
 {
-    size_t ivlen, keylen, taglen;
     int hashleni = EVP_MD_get_size(md);
     size_t hashlen;
+    int mode;
 
     /* Ensure cast to size_t is safe */
     if (!ossl_assert(hashleni >= 0)) {
@@ -364,11 +366,13 @@ static int derive_secret_key_and_iv(SSL_CONNECTION *s, int sending,
         return 0;
     }
 
-    keylen = EVP_CIPHER_get_key_length(ciph);
-    if (EVP_CIPHER_get_mode(ciph) == EVP_CIPH_CCM_MODE) {
+    *keylen = EVP_CIPHER_get_key_length(ciph);
+
+    mode = EVP_CIPHER_get_mode(ciph);
+    if (mode == EVP_CIPH_CCM_MODE) {
         uint32_t algenc;
 
-        ivlen = EVP_CCM_TLS_IV_LEN;
+        *ivlen = EVP_CCM_TLS_IV_LEN;
         if (s->s3.tmp.new_cipher != NULL) {
             algenc = s->s3.tmp.new_cipher->algorithm_enc;
         } else if (s->session->cipher != NULL) {
@@ -382,27 +386,34 @@ static int derive_secret_key_and_iv(SSL_CONNECTION *s, int sending,
             return 0;
         }
         if (algenc & (SSL_AES128CCM8 | SSL_AES256CCM8))
-            taglen = EVP_CCM8_TLS_TAG_LEN;
+            *taglen = EVP_CCM8_TLS_TAG_LEN;
          else
-            taglen = EVP_CCM_TLS_TAG_LEN;
+            *taglen = EVP_CCM_TLS_TAG_LEN;
     } else {
-        ivlen = EVP_CIPHER_get_iv_length(ciph);
-        taglen = 0;
+        if (mode == EVP_CIPH_GCM_MODE) {
+            *taglen = EVP_GCM_TLS_TAG_LEN;
+        } else {
+            /* CHACHA20P-POLY1305 */
+            *taglen = EVP_CHACHAPOLY_TLS_TAG_LEN;
+        }
+        *ivlen = EVP_CIPHER_get_iv_length(ciph);
     }
 
-    if (!tls13_derive_key(s, md, secret, key, keylen)
-            || !tls13_derive_iv(s, md, secret, iv, ivlen)) {
+    if (!tls13_derive_key(s, md, secret, key, *keylen)
+            || !tls13_derive_iv(s, md, secret, iv, *ivlen)) {
         /* SSLfatal() already called */
         return 0;
     }
 
-    if (EVP_CipherInit_ex(ciph_ctx, ciph, NULL, NULL, NULL, sending) <= 0
-        || EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_IVLEN, ivlen, NULL) <= 0
-        || (taglen != 0 && EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_TAG,
-                                                taglen, NULL) <= 0)
-        || EVP_CipherInit_ex(ciph_ctx, NULL, NULL, key, NULL, -1) <= 0) {
-        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
-        return 0;
+    if (sending) {
+        if (EVP_CipherInit_ex(ciph_ctx, ciph, NULL, NULL, NULL, sending) <= 0
+            || EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_IVLEN, *ivlen, NULL) <= 0
+            || (mode == EVP_CIPH_CCM_MODE
+                && EVP_CIPHER_CTX_ctrl(ciph_ctx, EVP_CTRL_AEAD_SET_TAG, *taglen, NULL) <= 0)
+            || EVP_CipherInit_ex(ciph_ctx, NULL, NULL, key, NULL, -1) <= 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
+            return 0;
+        }
     }
 
     return 1;
@@ -411,14 +422,14 @@ static int derive_secret_key_and_iv(SSL_CONNECTION *s, int sending,
 int tls13_change_cipher_state(SSL_CONNECTION *s, int which)
 {
 #ifdef CHARSET_EBCDIC
-  static const unsigned char client_early_traffic[]       = {0x63, 0x20, 0x65, 0x20,       /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
-  static const unsigned char client_handshake_traffic[]   = {0x63, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
-  static const unsigned char client_application_traffic[] = {0x63, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
-  static const unsigned char server_handshake_traffic[]   = {0x73, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
-  static const unsigned char server_application_traffic[] = {0x73, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
-  static const unsigned char exporter_master_secret[] = {0x65, 0x78, 0x70, 0x20,                    /* master*/  0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00};
-  static const unsigned char resumption_master_secret[] = {0x72, 0x65, 0x73, 0x20,                  /* master*/  0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00};
-  static const unsigned char early_exporter_master_secret[] = {0x65, 0x20, 0x65, 0x78, 0x70, 0x20,  /* master*/  0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00};
+    static const unsigned char client_early_traffic[]       = {0x63, 0x20, 0x65, 0x20,       /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
+    static const unsigned char client_handshake_traffic[]   = {0x63, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
+    static const unsigned char client_application_traffic[] = {0x63, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
+    static const unsigned char server_handshake_traffic[]   = {0x73, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
+    static const unsigned char server_application_traffic[] = {0x73, 0x20, 0x61, 0x70, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
+    static const unsigned char exporter_master_secret[] = {0x65, 0x78, 0x70, 0x20,                    /* master*/  0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00};
+    static const unsigned char resumption_master_secret[] = {0x72, 0x65, 0x73, 0x20,                  /* master*/  0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00};
+    static const unsigned char early_exporter_master_secret[] = {0x65, 0x20, 0x65, 0x78, 0x70, 0x20,  /* master*/  0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x00};
 #else
     static const unsigned char client_early_traffic[] = "c e traffic";
     static const unsigned char client_handshake_traffic[] = "c hs traffic";
@@ -437,7 +448,7 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which)
     unsigned char *insecret;
     unsigned char *finsecret = NULL;
     const char *log_label = NULL;
-    EVP_CIPHER_CTX *ciph_ctx;
+    EVP_CIPHER_CTX *ciph_ctx = NULL;
     size_t finsecretlen = 0;
     const unsigned char *label;
     size_t labellen, hashlen = 0;
@@ -445,6 +456,7 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which)
     const EVP_MD *md = NULL;
     const EVP_CIPHER *cipher = NULL;
     SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
+    size_t keylen, ivlen, taglen;
 #if !defined(OPENSSL_NO_KTLS) && defined(OPENSSL_KTLS_TLS13)
     ktls_crypto_info_t crypto_info;
     void *rl_sequence;
@@ -452,16 +464,6 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which)
 #endif
 
     if (which & SSL3_CC_READ) {
-        if (s->enc_read_ctx != NULL) {
-            EVP_CIPHER_CTX_reset(s->enc_read_ctx);
-        } else {
-            s->enc_read_ctx = EVP_CIPHER_CTX_new();
-            if (s->enc_read_ctx == NULL) {
-                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
-                goto err;
-            }
-        }
-        ciph_ctx = s->enc_read_ctx;
         iv = s->read_iv;
 
         RECORD_LAYER_reset_read_sequence(&s->rlayer);
@@ -659,7 +661,7 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which)
 
     if (!derive_secret_key_and_iv(s, which & SSL3_CC_WRITE, md, cipher,
                                   insecret, hash, label, labellen, secret, key,
-                                  iv, ciph_ctx)) {
+                                  &keylen, iv, &ivlen, &taglen, ciph_ctx)) {
         /* SSLfatal() already called */
         goto err;
     }
@@ -700,6 +702,29 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which)
         s->statem.enc_write_state = ENC_WRITE_STATE_WRITE_PLAIN_ALERTS;
     else
         s->statem.enc_write_state = ENC_WRITE_STATE_VALID;
+
+    if ((which & SSL3_CC_READ) != 0) {
+        int level = (which & SSL3_CC_EARLY) != 0
+                    ? OSSL_RECORD_PROTECTION_LEVEL_EARLY
+                    : ((which &SSL3_CC_HANDSHAKE) != 0
+                       ? OSSL_RECORD_PROTECTION_LEVEL_HANDSHAKE
+                       : OSSL_RECORD_PROTECTION_LEVEL_APPLICATION);
+        s->rrlmethod->free(s->rrl);
+        s->rrl = s->rrlmethod->new_record_layer(sctx->libctx,
+                                                sctx->propq,
+                                                s->version, s->server,
+                                                OSSL_RECORD_DIRECTION_READ,
+                                                level, key, keylen, iv, ivlen,
+                                                NULL, 0, cipher, taglen,
+                                                NID_undef, NULL, NULL, s->rbio,
+                                                NULL, NULL, NULL, NULL, s);
+        if (s->rrl == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+
+
 #ifndef OPENSSL_NO_KTLS
 # if defined(OPENSSL_KTLS_TLS13)
     if (!(which & SSL3_CC_APPLICATION)
@@ -776,7 +801,9 @@ int tls13_update_key(SSL_CONNECTION *s, int sending)
     unsigned char *insecret, *iv;
     unsigned char secret[EVP_MAX_MD_SIZE];
     EVP_CIPHER_CTX *ciph_ctx;
+    size_t keylen, ivlen, taglen;
     int ret = 0;
+    SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
 
     if (s->server == sending)
         insecret = s->server_app_traffic_secret;
@@ -798,13 +825,32 @@ int tls13_update_key(SSL_CONNECTION *s, int sending)
                                   s->s3.tmp.new_sym_enc, insecret, NULL,
                                   application_traffic,
                                   sizeof(application_traffic) - 1, secret, key,
-                                  iv, ciph_ctx)) {
+                                  &keylen, iv, &ivlen, &taglen, ciph_ctx)) {
         /* SSLfatal() already called */
         goto err;
     }
 
     memcpy(insecret, secret, hashlen);
 
+    if (!sending) {
+        s->rrlmethod->free(s->rrl);
+        s->rrl = s->rrlmethod->new_record_layer(sctx->libctx,
+                                                sctx->propq,
+                                                s->version, s->server,
+                                                OSSL_RECORD_DIRECTION_READ,
+                                                OSSL_RECORD_PROTECTION_LEVEL_APPLICATION,
+                                                key, keylen, iv, ivlen,
+                                                NULL, 0, s->s3.tmp.new_sym_enc,
+                                                taglen, NID_undef, NULL, NULL,
+                                                s->rbio, NULL, NULL, NULL, NULL,
+                                                s);
+        if (s->rrl == NULL) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+
+
     s->statem.enc_write_state = ENC_WRITE_STATE_VALID;
     ret = 1;
  err: