Create the write record layer method and object and use it
authorMatt Caswell <matt@openssl.org>
Fri, 19 Aug 2022 15:54:09 +0000 (16:54 +0100)
committerMatt Caswell <matt@openssl.org>
Fri, 23 Sep 2022 13:43:24 +0000 (14:43 +0100)
Make sure we set the write record layer method and create the object
where appropriate. Move the newly restructured writing code into the
record layer object.

For now we are cheating and still accessing the underlying SSL_CONNECTION
object. This will be removed in subsequent commits.

Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19198)

12 files changed:
ssl/record/methods/dtls_meth.c
ssl/record/methods/ktls_meth.c
ssl/record/methods/recmethod_local.h
ssl/record/methods/tls_common.c
ssl/record/rec_layer_s3.c
ssl/record/record.h
ssl/record/recordmethod.h
ssl/s3_enc.c
ssl/s3_msg.c
ssl/ssl_lib.c
ssl/t1_enc.c
ssl/tls13_enc.c

index ac4f5f397bc3591dc75db41ee20539505d43baa2..c462dd13b717f36a190c11180d79d18bd28f7fca 100644 (file)
@@ -700,8 +700,8 @@ const OSSL_RECORD_METHOD ossl_dtls_record_method = {
     tls_write_pending,
     tls_get_max_record_len,
     tls_get_max_records,
-    tls_write_records_tmp,
-    tls_retry_write_records_tmp,
+    tls_write_records,
+    tls_retry_write_records,
     tls_read_record,
     tls_release_record,
     tls_get_alert_code,
index 2477b04e9e9b09c93214b812f5045a645b372873..d0db365c5b8df4fc4cc7c33cfe64e6407c1d2033 100644 (file)
@@ -545,7 +545,7 @@ const OSSL_RECORD_METHOD ossl_ktls_record_method = {
     tls_get_max_record_len,
     tls_get_max_records,
     tls_write_records,
-    tls_retry_write_records_tmp,
+    tls_retry_write_records,
     tls_read_record,
     tls_release_record,
     tls_get_alert_code,
index 3dcfaa0f21bee1c48c131190cefeef4a6224a9d6..16f24b6d5e9f2fe9daee0f5bcd26708cc0a66922 100644 (file)
@@ -275,10 +275,9 @@ size_t tls_app_data_pending(OSSL_RECORD_LAYER *rl);
 int tls_write_pending(OSSL_RECORD_LAYER *rl);
 size_t tls_get_max_record_len(OSSL_RECORD_LAYER *rl);
 size_t tls_get_max_records(OSSL_RECORD_LAYER *rl);
-int tls_write_records_tmp(OSSL_RECORD_LAYER *rl, OSSL_RECORD_TEMPLATE **templates,
-                          size_t numtempl,  size_t allowance, size_t *sent);
-int tls_retry_write_records_tmp(OSSL_RECORD_LAYER *rl, size_t allowance,
-                                size_t *sent);
+int tls_write_records(OSSL_RECORD_LAYER *rl, OSSL_RECORD_TEMPLATE *templates,
+                      size_t numtempl);
+int tls_retry_write_records(OSSL_RECORD_LAYER *rl);
 int tls_get_alert_code(OSSL_RECORD_LAYER *rl);
 int tls_set1_bio(OSSL_RECORD_LAYER *rl, BIO *bio);
 int tls_read_record(OSSL_RECORD_LAYER *rl, void **rechandle, int *rversion,
index 56e04b1c4cefec1f6cee4842b77bfa611e31020d..6a5b7c6696731e690009c409d7f89d1c9e7d7e76 100644 (file)
@@ -1302,16 +1302,553 @@ size_t tls_get_max_records(OSSL_RECORD_LAYER *rl)
     return 0;
 }
 
-int tls_write_records_tmp(OSSL_RECORD_LAYER *rl, OSSL_RECORD_TEMPLATE **templates,
-                          size_t numtempl, size_t allowance, size_t *sent)
+int tls_write_records(OSSL_RECORD_LAYER *rl, OSSL_RECORD_TEMPLATE *templates,
+                      size_t numtempl)
 {
-    return 0;
+    WPACKET pkt[SSL_MAX_PIPELINES + 1];
+    SSL3_RECORD wr[SSL_MAX_PIPELINES + 1];
+    WPACKET *thispkt;
+    SSL3_RECORD *thiswr;
+    unsigned char *recordstart;
+    int i, mac_size, clear = 0;
+    int eivlen = 0;
+    size_t align = 0;
+    SSL3_BUFFER *wb;
+    SSL_SESSION *sess;
+    size_t totlen = 0, len, wpinited = 0;
+    size_t j, prefix = 0;
+    int using_ktls;
+    /* TODO(RECLAYER): REMOVE ME */
+    SSL_CONNECTION *s = rl->cbarg;
+    SSL *ssl = SSL_CONNECTION_GET_SSL(s);
+    OSSL_RECORD_TEMPLATE prefixtempl;
+    OSSL_RECORD_TEMPLATE *thistempl;
+
+    if (!ossl_assert(!RECORD_LAYER_write_pending(&s->rlayer))) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+        goto err;
+    }
+
+    /* If we have an alert to send, lets send it */
+    if (s->s3.alert_dispatch) {
+        i = ssl->method->ssl_dispatch_alert(ssl);
+        if (i <= 0) {
+            /* SSLfatal() already called if appropriate */
+            return i;
+        }
+        /* if it went, fall through and send more stuff */
+    }
+
+    sess = s->session;
+
+    if ((sess == NULL)
+            || (s->enc_write_ctx == NULL)
+            || (EVP_MD_CTX_get0_md(s->write_hash) == NULL)) {
+        clear = s->enc_write_ctx ? 0 : 1; /* must be AEAD cipher */
+        mac_size = 0;
+    } else {
+        mac_size = EVP_MD_CTX_get_size(s->write_hash);
+        if (mac_size < 0) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+
+    /*
+     * 'create_empty_fragment' is true only when we have recursively called
+     * ourselves.
+     * Do we need to do that recursion in order to add an empty record prefix?
+     */
+    prefix = s->s3.need_empty_fragments
+             && !clear
+             && !s->s3.empty_fragment_done
+             && templates[0].type == SSL3_RT_APPLICATION_DATA;
+
+    if (s->rlayer.numwpipes < numtempl + prefix) {
+        /*
+         * TODO(RECLAYER): In the prefix case the first buffer can be a lot
+         * smaller. It is wasteful to allocate a full sized buffer here
+         */
+        if (!ssl3_setup_write_buffer(s, numtempl + prefix, 0)) {
+            /* SSLfatal() already called */
+            return -1;
+        }
+    }
+
+    using_ktls = BIO_get_ktls_send(s->wbio);
+    if (!ossl_assert(!using_ktls || !prefix)) {
+        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (prefix) {
+        /*
+         * countermeasure against known-IV weakness in CBC ciphersuites (see
+         * http://www.openssl.org/~bodo/tls-cbc.txt)
+         */
+        prefixtempl.buf = NULL;
+        prefixtempl.buflen = 0;
+        prefixtempl.type = SSL3_RT_APPLICATION_DATA;
+        wpinited = 1;
+
+        /* TODO(RECLAYER): Do we actually need this? */
+        s->s3.empty_fragment_done = 1;
+
+        wb = &s->rlayer.wbuf[0];
+        /* TODO(RECLAYER): This alignment calculation no longer seems right */
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+        /*
+         * extra fragment would be couple of cipher blocks, which would be
+         * multiple of SSL3_ALIGN_PAYLOAD, so if we want to align the real
+         * payload, then we can just pretend we simply have two headers.
+         */
+        align = (size_t)SSL3_BUFFER_get_buf(wb) + 2 * SSL3_RT_HEADER_LENGTH;
+        align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD);
+#endif
+        SSL3_BUFFER_set_offset(wb, align);
+        if (!WPACKET_init_static_len(&pkt[0], SSL3_BUFFER_get_buf(wb),
+                                     SSL3_BUFFER_get_len(wb), 0)
+                || !WPACKET_allocate_bytes(&pkt[0], align, NULL)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        wpinited = 1;
+    }
+    for (j = 0; j < numtempl; j++) {
+        thispkt = &pkt[prefix + j];
+
+        wb = &s->rlayer.wbuf[prefix + j];
+        wb->type = templates[j].type;
+
+        if (using_ktls) {
+            /*
+            * ktls doesn't modify the buffer, but to avoid a warning we need
+            * to discard the const qualifier.
+            * This doesn't leak memory because the buffers have been
+            * released when switching to ktls.
+            */
+            SSL3_BUFFER_set_buf(wb, (unsigned char *)templates[j].buf);
+            SSL3_BUFFER_set_offset(wb, 0);
+            SSL3_BUFFER_set_app_buffer(wb, 1);
+        } else {
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0
+            align = (size_t)SSL3_BUFFER_get_buf(wb) + SSL3_RT_HEADER_LENGTH;
+            align = SSL3_ALIGN_PAYLOAD - 1
+                    - ((align - 1) % SSL3_ALIGN_PAYLOAD);
+#endif
+            /* TODO(RECLAYER): Is this alignment actually used somewhere? */
+            SSL3_BUFFER_set_offset(wb, align);
+            if (!WPACKET_init_static_len(thispkt, SSL3_BUFFER_get_buf(wb),
+                                        SSL3_BUFFER_get_len(wb), 0)
+                    || !WPACKET_allocate_bytes(thispkt, align, NULL)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            wpinited++;
+        }
+    }
+
+    if (!using_ktls) {
+        /* Explicit IV length, block ciphers appropriate version flag */
+        if (s->enc_write_ctx && SSL_USE_EXPLICIT_IV(s)
+            && !SSL_CONNECTION_TREAT_AS_TLS13(s)) {
+            int mode = EVP_CIPHER_CTX_get_mode(s->enc_write_ctx);
+            if (mode == EVP_CIPH_CBC_MODE) {
+                eivlen = EVP_CIPHER_CTX_get_iv_length(s->enc_write_ctx);
+                if (eivlen < 0) {
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_LIBRARY_BUG);
+                    goto err;
+                }
+                if (eivlen <= 1)
+                    eivlen = 0;
+            } else if (mode == EVP_CIPH_GCM_MODE) {
+                /* Need explicit part of IV for GCM mode */
+                eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
+            } else if (mode == EVP_CIPH_CCM_MODE) {
+                eivlen = EVP_CCM_TLS_EXPLICIT_IV_LEN;
+            }
+        }
+    }
+
+    totlen = 0;
+    /* Clear our SSL3_RECORD structures */
+    memset(wr, 0, sizeof(wr));
+    for (j = 0; j < numtempl + prefix; j++) {
+        unsigned int version = (s->version == TLS1_3_VERSION) ? TLS1_2_VERSION
+                                                              : s->version;
+        unsigned char *compressdata = NULL;
+        size_t maxcomplen;
+        unsigned int rectype;
+
+        thispkt = &pkt[j];
+        thiswr = &wr[j];
+        thistempl = (j == 0 && prefix == 1) ? &prefixtempl :
+                                              &templates[j - prefix];
+
+        /*
+         * In TLSv1.3, once encrypting, we always use application data for the
+         * record type
+         */
+        if (SSL_CONNECTION_TREAT_AS_TLS13(s)
+                && s->enc_write_ctx != NULL
+                && (s->statem.enc_write_state != ENC_WRITE_STATE_WRITE_PLAIN_ALERTS
+                    || thistempl->type != SSL3_RT_ALERT))
+            rectype = SSL3_RT_APPLICATION_DATA;
+        else
+            rectype = thistempl->type;
+
+        SSL3_RECORD_set_type(thiswr, rectype);
+
+        /*
+         * Some servers hang if initial client hello is larger than 256 bytes
+         * and record version number > TLS 1.0
+         */
+        if (SSL_get_state(ssl) == TLS_ST_CW_CLNT_HELLO
+                && !s->renegotiate
+                && TLS1_get_version(ssl) > TLS1_VERSION
+                && s->hello_retry_request == SSL_HRR_NONE)
+            version = TLS1_VERSION;
+        SSL3_RECORD_set_rec_version(thiswr, version);
+
+        maxcomplen = thistempl->buflen;
+        if (s->compress != NULL)
+            maxcomplen += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
+
+        /*
+         * When using offload kernel will write the header.
+         * Otherwise write the header now
+         */
+        if (!using_ktls
+                && (!WPACKET_put_bytes_u8(thispkt, rectype)
+                || !WPACKET_put_bytes_u16(thispkt, version)
+                || !WPACKET_start_sub_packet_u16(thispkt)
+                || (eivlen > 0
+                    && !WPACKET_allocate_bytes(thispkt, eivlen, NULL))
+                || (maxcomplen > 0
+                    && !WPACKET_reserve_bytes(thispkt, maxcomplen,
+                                              &compressdata)))) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        /* lets setup the record stuff. */
+        SSL3_RECORD_set_data(thiswr, compressdata);
+        SSL3_RECORD_set_length(thiswr, thistempl->buflen);
+        /*
+         * TODO(RECLAYER): Cast away the const. Should be safe - by why is this
+         * necessary?
+         */
+        SSL3_RECORD_set_input(thiswr, (unsigned char *)thistempl->buf);
+        totlen += thistempl->buflen;
+
+        /*
+         * we now 'read' from thiswr->input, thiswr->length bytes into
+         * thiswr->data
+         */
+
+        /* first we compress */
+        if (s->compress != NULL) {
+            if (!ssl3_do_compress(s, thiswr)
+                    || !WPACKET_allocate_bytes(thispkt, thiswr->length, NULL)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_COMPRESSION_FAILURE);
+                goto err;
+            }
+        } else {
+            if (using_ktls) {
+                SSL3_RECORD_reset_data(&wr[j]);
+            } else {
+                if (!WPACKET_memcpy(thispkt, thiswr->input, thiswr->length)) {
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+                    goto err;
+                }
+                SSL3_RECORD_reset_input(&wr[j]);
+            }
+        }
+
+        if (SSL_CONNECTION_TREAT_AS_TLS13(s)
+                && !using_ktls
+                && s->enc_write_ctx != NULL
+                && (s->statem.enc_write_state != ENC_WRITE_STATE_WRITE_PLAIN_ALERTS
+                    || thistempl->type != SSL3_RT_ALERT)) {
+            size_t rlen, max_send_fragment;
+
+            if (!WPACKET_put_bytes_u8(thispkt, thistempl->type)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            SSL3_RECORD_add_length(thiswr, 1);
+
+            /* Add TLS1.3 padding */
+            max_send_fragment = ssl_get_max_send_fragment(s);
+            rlen = SSL3_RECORD_get_length(thiswr);
+            if (rlen < max_send_fragment) {
+                size_t padding = 0;
+                size_t max_padding = max_send_fragment - rlen;
+                if (s->record_padding_cb != NULL) {
+                    padding = s->record_padding_cb(ssl, thistempl->type, rlen,
+                                                   s->record_padding_arg);
+                } else if (s->block_padding > 0) {
+                    size_t mask = s->block_padding - 1;
+                    size_t remainder;
+
+                    /* optimize for power of 2 */
+                    if ((s->block_padding & mask) == 0)
+                        remainder = rlen & mask;
+                    else
+                        remainder = rlen % s->block_padding;
+                    /* don't want to add a block of padding if we don't have to */
+                    if (remainder == 0)
+                        padding = 0;
+                    else
+                        padding = s->block_padding - remainder;
+                }
+                if (padding > 0) {
+                    /* do not allow the record to exceed max plaintext length */
+                    if (padding > max_padding)
+                        padding = max_padding;
+                    if (!WPACKET_memset(thispkt, 0, padding)) {
+                        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+                                 ERR_R_INTERNAL_ERROR);
+                        goto err;
+                    }
+                    SSL3_RECORD_add_length(thiswr, padding);
+                }
+            }
+        }
+
+        /*
+         * we should still have the output to thiswr->data and the input from
+         * wr->input. Length should be thiswr->length. thiswr->data still points
+         * in the wb->buf
+         */
+
+        if (!using_ktls && !SSL_WRITE_ETM(s) && mac_size != 0) {
+            unsigned char *mac;
+
+            if (!WPACKET_allocate_bytes(thispkt, mac_size, &mac)
+                    || !ssl->method->ssl3_enc->mac(s, thiswr, mac, 1)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+        }
+
+        /*
+         * Reserve some bytes for any growth that may occur during encryption.
+         * This will be at most one cipher block or the tag length if using
+         * AEAD. SSL_RT_MAX_CIPHER_BLOCK_SIZE covers either case.
+         */
+        if (!using_ktls) {
+            if (!WPACKET_reserve_bytes(thispkt,
+                                        SSL_RT_MAX_CIPHER_BLOCK_SIZE,
+                                        NULL)
+                /*
+                 * We also need next the amount of bytes written to this
+                 * sub-packet
+                 */
+                || !WPACKET_get_length(thispkt, &len)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            goto err;
+            }
+
+            /* Get a pointer to the start of this record excluding header */
+            recordstart = WPACKET_get_curr(thispkt) - len;
+            SSL3_RECORD_set_data(thiswr, recordstart);
+            SSL3_RECORD_reset_input(thiswr);
+            SSL3_RECORD_set_length(thiswr, len);
+        }
+    }
+
+    if (s->statem.enc_write_state == ENC_WRITE_STATE_WRITE_PLAIN_ALERTS) {
+        /*
+         * We haven't actually negotiated the version yet, but we're trying to
+         * send early data - so we need to use the tls13enc function.
+         */
+        if (tls13_enc(s, wr, numtempl, 1, NULL, mac_size) < 1) {
+            if (!ossl_statem_in_error(s)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            }
+            goto err;
+        }
+    } else {
+        if (!using_ktls) {
+            if (prefix) {
+                if (ssl->method->ssl3_enc->enc(s, wr, 1, 1, NULL, mac_size) < 1) {
+                    if (!ossl_statem_in_error(s)) {
+                        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+                    }
+                    goto err;
+                }
+            }
+            if (ssl->method->ssl3_enc->enc(s, wr + prefix, numtempl, 1, NULL,
+                                           mac_size) < 1) {
+                if (!ossl_statem_in_error(s)) {
+                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+                }
+                goto err;
+            }
+        }
+    }
+
+    for (j = 0; j < prefix + numtempl; j++) {
+        size_t origlen;
+
+        thispkt = &pkt[j];
+        thiswr = &wr[j];
+        thistempl = (prefix == 1 && j == 0) ? &prefixtempl
+                                            : &templates[j - prefix];
+
+        if (using_ktls)
+            goto mac_done;
+
+        /* Allocate bytes for the encryption overhead */
+        if (!WPACKET_get_length(thispkt, &origlen)
+                   /* Encryption should never shrink the data! */
+                || origlen > thiswr->length
+                || (thiswr->length > origlen
+                    && !WPACKET_allocate_bytes(thispkt,
+                                               thiswr->length - origlen,
+                                               NULL))) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        if (SSL_WRITE_ETM(s) && mac_size != 0) {
+            unsigned char *mac;
+
+            if (!WPACKET_allocate_bytes(thispkt, mac_size, &mac)
+                    || !ssl->method->ssl3_enc->mac(s, thiswr, mac, 1)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            SSL3_RECORD_add_length(thiswr, mac_size);
+        }
+
+        if (!WPACKET_get_length(thispkt, &len)
+                || !WPACKET_close(thispkt)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        if (s->msg_callback) {
+            recordstart = WPACKET_get_curr(thispkt) - len
+                          - SSL3_RT_HEADER_LENGTH;
+            s->msg_callback(1, thiswr->rec_version, SSL3_RT_HEADER, recordstart,
+                            SSL3_RT_HEADER_LENGTH, ssl,
+                            s->msg_callback_arg);
+
+            if (SSL_CONNECTION_TREAT_AS_TLS13(s) && s->enc_write_ctx != NULL) {
+                unsigned char ctype = thistempl->type;
+
+                s->msg_callback(1, thiswr->rec_version, SSL3_RT_INNER_CONTENT_TYPE,
+                                &ctype, 1, ssl, s->msg_callback_arg);
+            }
+        }
+
+        if (!WPACKET_finish(thispkt)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        /* header is added by the kernel when using offload */
+        SSL3_RECORD_add_length(thiswr, SSL3_RT_HEADER_LENGTH);
+
+ mac_done:
+        /*
+         * we should now have thiswr->data pointing to the encrypted data, which
+         * is thiswr->length long.
+         * Setting the type is not needed but helps for debugging
+         */
+        SSL3_RECORD_set_type(thiswr, thistempl->type);
+
+        /* now let's set up wb */
+        SSL3_BUFFER_set_left(&s->rlayer.wbuf[j], SSL3_RECORD_get_length(thiswr));
+    }
+
+    /* we now just need to write the buffers */
+    return tls_retry_write_records(rl);
+ err:
+    for (j = 0; j < wpinited; j++)
+        WPACKET_cleanup(&pkt[j]);
+    return -1;
 }
 
-int tls_retry_write_records_tmp(OSSL_RECORD_LAYER *rl, size_t allowance,
-                                size_t *sent)
+/* if SSL3_BUFFER_get_left() != 0, we need to call this
+ *
+ * Return values are as per SSL_write()
+ */
+int tls_retry_write_records(OSSL_RECORD_LAYER *rl)
 {
-    return 0;
+    int i;
+    SSL3_BUFFER *thiswb;
+    size_t currbuf = 0;
+    size_t tmpwrit = 0;
+    SSL_CONNECTION *s = rl->cbarg;
+
+    for (;;) {
+        thiswb = &s->rlayer.wbuf[currbuf];
+        /* Loop until we find a buffer we haven't written out yet */
+        if (SSL3_BUFFER_get_left(thiswb) == 0
+            && currbuf < s->rlayer.numwpipes - 1) {
+            currbuf++;
+            continue;
+        }
+        clear_sys_error();
+        if (s->wbio != NULL) {
+            s->rwstate = SSL_WRITING;
+
+            /*
+             * To prevent coalescing of control and data messages,
+             * such as in buffer_write, we flush the BIO
+             */
+            if (BIO_get_ktls_send(s->wbio)
+                    && thiswb->type != SSL3_RT_APPLICATION_DATA) {
+                i = BIO_flush(s->wbio);
+                if (i <= 0)
+                    return i;
+                BIO_set_ktls_ctrl_msg(s->wbio, thiswb->type);
+            }
+            i = BIO_write(s->wbio, (char *)
+                          &(SSL3_BUFFER_get_buf(thiswb)
+                            [SSL3_BUFFER_get_offset(thiswb)]),
+                          (unsigned int)SSL3_BUFFER_get_left(thiswb));
+            if (i >= 0)
+                tmpwrit = i;
+        } else {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BIO_NOT_SET);
+            i = -1;
+        }
+
+        /*
+         * When an empty fragment is sent on a connection using KTLS,
+         * it is sent as a write of zero bytes.  If this zero byte
+         * write succeeds, i will be 0 rather than a non-zero value.
+         * Treat i == 0 as success rather than an error for zero byte
+         * writes to permit this case.
+         */
+        if (i >= 0 && tmpwrit == SSL3_BUFFER_get_left(thiswb)) {
+            SSL3_BUFFER_set_left(thiswb, 0);
+            SSL3_BUFFER_add_offset(thiswb, tmpwrit);
+            if (currbuf + 1 < s->rlayer.numwpipes)
+                continue;
+            s->rwstate = SSL_NOTHING;
+            /*
+             * Next chunk of data should get another prepended empty fragment
+             * in ciphersuites with known-IV weakness:
+             */
+            s->s3.empty_fragment_done = 0;
+            return 1;
+        } else if (i <= 0) {
+            if (SSL_CONNECTION_IS_DTLS(s)) {
+                /*
+                 * For DTLS, just drop it. That's kind of the whole point in
+                 * using a datagram service
+                 */
+                SSL3_BUFFER_set_left(thiswb, 0);
+            }
+            return i;
+        }
+        SSL3_BUFFER_add_offset(thiswb, tmpwrit);
+        SSL3_BUFFER_sub_left(thiswb, tmpwrit);
+    }
 }
 
 int tls_get_alert_code(OSSL_RECORD_LAYER *rl)
@@ -1394,8 +1931,8 @@ const OSSL_RECORD_METHOD ossl_tls_record_method = {
     tls_write_pending,
     tls_get_max_record_len,
     tls_get_max_records,
-    tls_write_records_tmp,
-    tls_retry_write_records_tmp,
+    tls_write_records,
+    tls_retry_write_records,
     tls_read_record,
     tls_release_record,
     tls_get_alert_code,
index c2e6e91e4172d5195285fe4be453aa351e07aba2..e6439ccda959d32d4470870f8c2136ec3c80d640 100644 (file)
@@ -48,9 +48,14 @@ void RECORD_LAYER_clear(RECORD_LAYER *rl)
 
     if (rl->rrlmethod != NULL)
         rl->rrlmethod->free(rl->rrl); /* Ignore return value */
+    if (rl->wrlmethod != NULL)
+        rl->wrlmethod->free(rl->wrl); /* Ignore return value */
     BIO_free(rl->rrlnext);
     rl->rrlmethod = NULL;
+    rl->wrlmethod = NULL;
     rl->rrlnext = NULL;
+    rl->rrl = NULL;
+    rl->wrl = NULL;
 
     if (rl->d)
         DTLS_RECORD_LAYER_clear(rl);
@@ -258,7 +263,7 @@ int ssl3_write_bytes(SSL *ssl, int type, const void *buf_, size_t len,
         return i;
     } else if (i > 0) {
         /* Retry needed */
-        i = tls_retry_write_records(s);
+        i = s->rlayer.wrlmethod->retry_write_records(s->rlayer.wrl);
         if (i <= 0)
             return i;
         tot += s->rlayer.wpend_tot;
@@ -510,7 +515,7 @@ int ssl3_write_bytes(SSL *ssl, int type, const void *buf_, size_t len,
             s->rlayer.wpend_tot = n;
         }
 
-        i = tls_write_records(s, tmpls, numpipes);
+        i = s->rlayer.wrlmethod->write_records(s->rlayer.wrl, tmpls, numpipes);
         if (i <= 0) {
             /* SSLfatal() already called if appropriate */
             s->rlayer.wnum = tot;
@@ -535,552 +540,6 @@ int ssl3_write_bytes(SSL *ssl, int type, const void *buf_, size_t len,
     }
 }
 
-int tls_write_records(SSL_CONNECTION *s, OSSL_RECORD_TEMPLATE *templates,
-                      size_t numtempl)
-{
-    WPACKET pkt[SSL_MAX_PIPELINES + 1];
-    SSL3_RECORD wr[SSL_MAX_PIPELINES + 1];
-    WPACKET *thispkt;
-    SSL3_RECORD *thiswr;
-    unsigned char *recordstart;
-    int i, mac_size, clear = 0;
-    int eivlen = 0;
-    size_t align = 0;
-    SSL3_BUFFER *wb;
-    SSL_SESSION *sess;
-    size_t totlen = 0, len, wpinited = 0;
-    size_t j, prefix = 0;
-    int using_ktls;
-    SSL *ssl = SSL_CONNECTION_GET_SSL(s);
-    OSSL_RECORD_TEMPLATE prefixtempl;
-    OSSL_RECORD_TEMPLATE *thistempl;
-
-    if (!ossl_assert(!RECORD_LAYER_write_pending(&s->rlayer))) {
-        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
-        goto err;
-    }
-
-    /* If we have an alert to send, lets send it */
-    if (s->s3.alert_dispatch) {
-        i = ssl->method->ssl_dispatch_alert(ssl);
-        if (i <= 0) {
-            /* SSLfatal() already called if appropriate */
-            return i;
-        }
-        /* if it went, fall through and send more stuff */
-    }
-
-    sess = s->session;
-
-    if ((sess == NULL)
-            || (s->enc_write_ctx == NULL)
-            || (EVP_MD_CTX_get0_md(s->write_hash) == NULL)) {
-        clear = s->enc_write_ctx ? 0 : 1; /* must be AEAD cipher */
-        mac_size = 0;
-    } else {
-        mac_size = EVP_MD_CTX_get_size(s->write_hash);
-        if (mac_size < 0) {
-            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-    }
-
-    /*
-     * 'create_empty_fragment' is true only when we have recursively called
-     * ourselves.
-     * Do we need to do that recursion in order to add an empty record prefix?
-     */
-    prefix = s->s3.need_empty_fragments
-             && !clear
-             && !s->s3.empty_fragment_done
-             && templates[0].type == SSL3_RT_APPLICATION_DATA;
-
-    if (s->rlayer.numwpipes < numtempl + prefix) {
-        /*
-         * TODO(RECLAYER): In the prefix case the first buffer can be a lot
-         * smaller. It is wasteful to allocate a full sized buffer here
-         */
-        if (!ssl3_setup_write_buffer(s, numtempl + prefix, 0)) {
-            /* SSLfatal() already called */
-            return -1;
-        }
-    }
-
-    using_ktls = BIO_get_ktls_send(s->wbio);
-    if (!ossl_assert(!using_ktls || !prefix)) {
-        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-
-    if (prefix) {
-        /*
-         * countermeasure against known-IV weakness in CBC ciphersuites (see
-         * http://www.openssl.org/~bodo/tls-cbc.txt)
-         */
-        prefixtempl.buf = NULL;
-        prefixtempl.buflen = 0;
-        prefixtempl.type = SSL3_RT_APPLICATION_DATA;
-        wpinited = 1;
-
-        /* TODO(RECLAYER): Do we actually need this? */
-        s->s3.empty_fragment_done = 1;
-
-        wb = &s->rlayer.wbuf[0];
-        /* TODO(RECLAYER): This alignment calculation no longer seems right */
-#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
-        /*
-         * extra fragment would be couple of cipher blocks, which would be
-         * multiple of SSL3_ALIGN_PAYLOAD, so if we want to align the real
-         * payload, then we can just pretend we simply have two headers.
-         */
-        align = (size_t)SSL3_BUFFER_get_buf(wb) + 2 * SSL3_RT_HEADER_LENGTH;
-        align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD);
-#endif
-        SSL3_BUFFER_set_offset(wb, align);
-        if (!WPACKET_init_static_len(&pkt[0], SSL3_BUFFER_get_buf(wb),
-                                     SSL3_BUFFER_get_len(wb), 0)
-                || !WPACKET_allocate_bytes(&pkt[0], align, NULL)) {
-            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-        wpinited = 1;
-    }
-    for (j = 0; j < numtempl; j++) {
-        thispkt = &pkt[prefix + j];
-
-        wb = &s->rlayer.wbuf[prefix + j];
-        wb->type = templates[j].type;
-
-        if (using_ktls) {
-            /*
-            * ktls doesn't modify the buffer, but to avoid a warning we need
-            * to discard the const qualifier.
-            * This doesn't leak memory because the buffers have been
-            * released when switching to ktls.
-            */
-            SSL3_BUFFER_set_buf(wb, (unsigned char *)templates[j].buf);
-            SSL3_BUFFER_set_offset(wb, 0);
-            SSL3_BUFFER_set_app_buffer(wb, 1);
-        } else {
-#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0
-            align = (size_t)SSL3_BUFFER_get_buf(wb) + SSL3_RT_HEADER_LENGTH;
-            align = SSL3_ALIGN_PAYLOAD - 1
-                    - ((align - 1) % SSL3_ALIGN_PAYLOAD);
-#endif
-            /* TODO(RECLAYER): Is this alignment actually used somewhere? */
-            SSL3_BUFFER_set_offset(wb, align);
-            if (!WPACKET_init_static_len(thispkt, SSL3_BUFFER_get_buf(wb),
-                                        SSL3_BUFFER_get_len(wb), 0)
-                    || !WPACKET_allocate_bytes(thispkt, align, NULL)) {
-                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-            wpinited++;
-        }
-    }
-
-    if (!using_ktls) {
-        /* Explicit IV length, block ciphers appropriate version flag */
-        if (s->enc_write_ctx && SSL_USE_EXPLICIT_IV(s)
-            && !SSL_CONNECTION_TREAT_AS_TLS13(s)) {
-            int mode = EVP_CIPHER_CTX_get_mode(s->enc_write_ctx);
-            if (mode == EVP_CIPH_CBC_MODE) {
-                eivlen = EVP_CIPHER_CTX_get_iv_length(s->enc_write_ctx);
-                if (eivlen < 0) {
-                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_LIBRARY_BUG);
-                    goto err;
-            }
-                if (eivlen <= 1)
-                    eivlen = 0;
-            } else if (mode == EVP_CIPH_GCM_MODE) {
-                /* Need explicit part of IV for GCM mode */
-                eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
-            } else if (mode == EVP_CIPH_CCM_MODE) {
-                eivlen = EVP_CCM_TLS_EXPLICIT_IV_LEN;
-            }
-        }
-    }
-
-    totlen = 0;
-    /* Clear our SSL3_RECORD structures */
-    memset(wr, 0, sizeof(wr));
-    for (j = 0; j < numtempl + prefix; j++) {
-        unsigned int version = (s->version == TLS1_3_VERSION) ? TLS1_2_VERSION
-                                                              : s->version;
-        unsigned char *compressdata = NULL;
-        size_t maxcomplen;
-        unsigned int rectype;
-
-        thispkt = &pkt[j];
-        thiswr = &wr[j];
-        thistempl = (j == 0 && prefix == 1) ? &prefixtempl :
-                                              &templates[j - prefix];
-
-        /*
-         * In TLSv1.3, once encrypting, we always use application data for the
-         * record type
-         */
-        if (SSL_CONNECTION_TREAT_AS_TLS13(s)
-                && s->enc_write_ctx != NULL
-                && (s->statem.enc_write_state != ENC_WRITE_STATE_WRITE_PLAIN_ALERTS
-                    || thistempl->type != SSL3_RT_ALERT))
-            rectype = SSL3_RT_APPLICATION_DATA;
-        else
-            rectype = thistempl->type;
-
-        SSL3_RECORD_set_type(thiswr, rectype);
-
-        /*
-         * Some servers hang if initial client hello is larger than 256 bytes
-         * and record version number > TLS 1.0
-         */
-        if (SSL_get_state(ssl) == TLS_ST_CW_CLNT_HELLO
-                && !s->renegotiate
-                && TLS1_get_version(ssl) > TLS1_VERSION
-                && s->hello_retry_request == SSL_HRR_NONE)
-            version = TLS1_VERSION;
-        SSL3_RECORD_set_rec_version(thiswr, version);
-
-        maxcomplen = thistempl->buflen;
-        if (s->compress != NULL)
-            maxcomplen += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
-
-        /*
-         * When using offload kernel will write the header.
-         * Otherwise write the header now
-         */
-        if (!using_ktls
-                && (!WPACKET_put_bytes_u8(thispkt, rectype)
-                || !WPACKET_put_bytes_u16(thispkt, version)
-                || !WPACKET_start_sub_packet_u16(thispkt)
-                || (eivlen > 0
-                    && !WPACKET_allocate_bytes(thispkt, eivlen, NULL))
-                || (maxcomplen > 0
-                    && !WPACKET_reserve_bytes(thispkt, maxcomplen,
-                                              &compressdata)))) {
-            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-
-        /* lets setup the record stuff. */
-        SSL3_RECORD_set_data(thiswr, compressdata);
-        SSL3_RECORD_set_length(thiswr, thistempl->buflen);
-        /*
-         * TODO(RECLAYER): Cast away the const. Should be safe - by why is this
-         * necessary?
-         */
-        SSL3_RECORD_set_input(thiswr, (unsigned char *)thistempl->buf);
-        totlen += thistempl->buflen;
-
-        /*
-         * we now 'read' from thiswr->input, thiswr->length bytes into
-         * thiswr->data
-         */
-
-        /* first we compress */
-        if (s->compress != NULL) {
-            if (!ssl3_do_compress(s, thiswr)
-                    || !WPACKET_allocate_bytes(thispkt, thiswr->length, NULL)) {
-                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_COMPRESSION_FAILURE);
-                goto err;
-            }
-        } else {
-            if (using_ktls) {
-                SSL3_RECORD_reset_data(&wr[j]);
-            } else {
-                if (!WPACKET_memcpy(thispkt, thiswr->input, thiswr->length)) {
-                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-                    goto err;
-                }
-                SSL3_RECORD_reset_input(&wr[j]);
-            }
-        }
-
-        if (SSL_CONNECTION_TREAT_AS_TLS13(s)
-                && !using_ktls
-                && s->enc_write_ctx != NULL
-                && (s->statem.enc_write_state != ENC_WRITE_STATE_WRITE_PLAIN_ALERTS
-                    || thistempl->type != SSL3_RT_ALERT)) {
-            size_t rlen, max_send_fragment;
-
-            if (!WPACKET_put_bytes_u8(thispkt, thistempl->type)) {
-                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-            SSL3_RECORD_add_length(thiswr, 1);
-
-            /* Add TLS1.3 padding */
-            max_send_fragment = ssl_get_max_send_fragment(s);
-            rlen = SSL3_RECORD_get_length(thiswr);
-            if (rlen < max_send_fragment) {
-                size_t padding = 0;
-                size_t max_padding = max_send_fragment - rlen;
-                if (s->record_padding_cb != NULL) {
-                    padding = s->record_padding_cb(ssl, thistempl->type, rlen,
-                                                   s->record_padding_arg);
-                } else if (s->block_padding > 0) {
-                    size_t mask = s->block_padding - 1;
-                    size_t remainder;
-
-                    /* optimize for power of 2 */
-                    if ((s->block_padding & mask) == 0)
-                        remainder = rlen & mask;
-                    else
-                        remainder = rlen % s->block_padding;
-                    /* don't want to add a block of padding if we don't have to */
-                    if (remainder == 0)
-                        padding = 0;
-                    else
-                        padding = s->block_padding - remainder;
-                }
-                if (padding > 0) {
-                    /* do not allow the record to exceed max plaintext length */
-                    if (padding > max_padding)
-                        padding = max_padding;
-                    if (!WPACKET_memset(thispkt, 0, padding)) {
-                        SSLfatal(s, SSL_AD_INTERNAL_ERROR,
-                                 ERR_R_INTERNAL_ERROR);
-                        goto err;
-                    }
-                    SSL3_RECORD_add_length(thiswr, padding);
-                }
-            }
-        }
-
-        /*
-         * we should still have the output to thiswr->data and the input from
-         * wr->input. Length should be thiswr->length. thiswr->data still points
-         * in the wb->buf
-         */
-
-        if (!using_ktls && !SSL_WRITE_ETM(s) && mac_size != 0) {
-            unsigned char *mac;
-
-            if (!WPACKET_allocate_bytes(thispkt, mac_size, &mac)
-                    || !ssl->method->ssl3_enc->mac(s, thiswr, mac, 1)) {
-                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-        }
-
-        /*
-         * Reserve some bytes for any growth that may occur during encryption.
-         * This will be at most one cipher block or the tag length if using
-         * AEAD. SSL_RT_MAX_CIPHER_BLOCK_SIZE covers either case.
-         */
-        if (!using_ktls) {
-            if (!WPACKET_reserve_bytes(thispkt,
-                                        SSL_RT_MAX_CIPHER_BLOCK_SIZE,
-                                        NULL)
-                /*
-                 * We also need next the amount of bytes written to this
-                 * sub-packet
-                 */
-                || !WPACKET_get_length(thispkt, &len)) {
-            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-            goto err;
-            }
-
-            /* Get a pointer to the start of this record excluding header */
-            recordstart = WPACKET_get_curr(thispkt) - len;
-            SSL3_RECORD_set_data(thiswr, recordstart);
-            SSL3_RECORD_reset_input(thiswr);
-            SSL3_RECORD_set_length(thiswr, len);
-        }
-    }
-
-    if (s->statem.enc_write_state == ENC_WRITE_STATE_WRITE_PLAIN_ALERTS) {
-        /*
-         * We haven't actually negotiated the version yet, but we're trying to
-         * send early data - so we need to use the tls13enc function.
-         */
-        if (tls13_enc(s, wr, numtempl, 1, NULL, mac_size) < 1) {
-            if (!ossl_statem_in_error(s)) {
-                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-            }
-            goto err;
-        }
-    } else {
-        if (!using_ktls) {
-            if (prefix) {
-                if (ssl->method->ssl3_enc->enc(s, wr, 1, 1, NULL, mac_size) < 1) {
-                    if (!ossl_statem_in_error(s)) {
-                        SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-                    }
-                    goto err;
-                }
-            }
-            if (ssl->method->ssl3_enc->enc(s, wr + prefix, numtempl, 1, NULL,
-                                           mac_size) < 1) {
-                if (!ossl_statem_in_error(s)) {
-                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-                }
-                goto err;
-            }
-        }
-    }
-
-    for (j = 0; j < prefix + numtempl; j++) {
-        size_t origlen;
-
-        thispkt = &pkt[j];
-        thiswr = &wr[j];
-        thistempl = (prefix == 1 && j == 0) ? &prefixtempl
-                                            : &templates[j - prefix];
-
-        if (using_ktls)
-            goto mac_done;
-
-        /* Allocate bytes for the encryption overhead */
-        if (!WPACKET_get_length(thispkt, &origlen)
-                   /* Encryption should never shrink the data! */
-                || origlen > thiswr->length
-                || (thiswr->length > origlen
-                    && !WPACKET_allocate_bytes(thispkt,
-                                               thiswr->length - origlen,
-                                               NULL))) {
-            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-        if (SSL_WRITE_ETM(s) && mac_size != 0) {
-            unsigned char *mac;
-
-            if (!WPACKET_allocate_bytes(thispkt, mac_size, &mac)
-                    || !ssl->method->ssl3_enc->mac(s, thiswr, mac, 1)) {
-                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-            SSL3_RECORD_add_length(thiswr, mac_size);
-        }
-
-        if (!WPACKET_get_length(thispkt, &len)
-                || !WPACKET_close(thispkt)) {
-            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-
-        if (s->msg_callback) {
-            recordstart = WPACKET_get_curr(thispkt) - len
-                          - SSL3_RT_HEADER_LENGTH;
-            s->msg_callback(1, thiswr->rec_version, SSL3_RT_HEADER, recordstart,
-                            SSL3_RT_HEADER_LENGTH, ssl,
-                            s->msg_callback_arg);
-
-            if (SSL_CONNECTION_TREAT_AS_TLS13(s) && s->enc_write_ctx != NULL) {
-                unsigned char ctype = thistempl->type;
-
-                s->msg_callback(1, thiswr->rec_version, SSL3_RT_INNER_CONTENT_TYPE,
-                                &ctype, 1, ssl, s->msg_callback_arg);
-            }
-        }
-
-        if (!WPACKET_finish(thispkt)) {
-            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-
-        /* header is added by the kernel when using offload */
-        SSL3_RECORD_add_length(thiswr, SSL3_RT_HEADER_LENGTH);
-
- mac_done:
-        /*
-         * we should now have thiswr->data pointing to the encrypted data, which
-         * is thiswr->length long.
-         * Setting the type is not needed but helps for debugging
-         */
-        SSL3_RECORD_set_type(thiswr, thistempl->type);
-
-        /* now let's set up wb */
-        SSL3_BUFFER_set_left(&s->rlayer.wbuf[j], SSL3_RECORD_get_length(thiswr));
-    }
-
-    /* we now just need to write the buffers */
-    return tls_retry_write_records(s);
- err:
-    for (j = 0; j < wpinited; j++)
-        WPACKET_cleanup(&pkt[j]);
-    return -1;
-}
-
-/* if SSL3_BUFFER_get_left() != 0, we need to call this
- *
- * Return values are as per SSL_write()
- */
-int tls_retry_write_records(SSL_CONNECTION *s)
-{
-    int i;
-    SSL3_BUFFER *thiswb;
-    size_t currbuf = 0;
-    size_t tmpwrit = 0;
-
-    for (;;) {
-        thiswb = &s->rlayer.wbuf[currbuf];
-        /* Loop until we find a buffer we haven't written out yet */
-        if (SSL3_BUFFER_get_left(thiswb) == 0
-            && currbuf < s->rlayer.numwpipes - 1) {
-            currbuf++;
-            continue;
-        }
-        clear_sys_error();
-        if (s->wbio != NULL) {
-            s->rwstate = SSL_WRITING;
-
-            /*
-             * To prevent coalescing of control and data messages,
-             * such as in buffer_write, we flush the BIO
-             */
-            if (BIO_get_ktls_send(s->wbio)
-                    && thiswb->type != SSL3_RT_APPLICATION_DATA) {
-                i = BIO_flush(s->wbio);
-                if (i <= 0)
-                    return i;
-                BIO_set_ktls_ctrl_msg(s->wbio, thiswb->type);
-            }
-            i = BIO_write(s->wbio, (char *)
-                          &(SSL3_BUFFER_get_buf(thiswb)
-                            [SSL3_BUFFER_get_offset(thiswb)]),
-                          (unsigned int)SSL3_BUFFER_get_left(thiswb));
-            if (i >= 0)
-                tmpwrit = i;
-        } else {
-            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BIO_NOT_SET);
-            i = -1;
-        }
-
-        /*
-         * When an empty fragment is sent on a connection using KTLS,
-         * it is sent as a write of zero bytes.  If this zero byte
-         * write succeeds, i will be 0 rather than a non-zero value.
-         * Treat i == 0 as success rather than an error for zero byte
-         * writes to permit this case.
-         */
-        if (i >= 0 && tmpwrit == SSL3_BUFFER_get_left(thiswb)) {
-            SSL3_BUFFER_set_left(thiswb, 0);
-            SSL3_BUFFER_add_offset(thiswb, tmpwrit);
-            if (currbuf + 1 < s->rlayer.numwpipes)
-                continue;
-            s->rwstate = SSL_NOTHING;
-            /*
-             * Next chunk of data should get another prepended empty fragment
-             * in ciphersuites with known-IV weakness:
-             */
-            s->s3.empty_fragment_done = 0;
-            return 1;
-        } else if (i <= 0) {
-            if (SSL_CONNECTION_IS_DTLS(s)) {
-                /*
-                 * For DTLS, just drop it. That's kind of the whole point in
-                 * using a datagram service
-                 */
-                SSL3_BUFFER_set_left(thiswb, 0);
-            }
-            return i;
-        }
-        SSL3_BUFFER_add_offset(thiswb, tmpwrit);
-        SSL3_BUFFER_sub_left(thiswb, tmpwrit);
-    }
-}
-
 int ossl_tls_handle_rlayer_return(SSL_CONNECTION *s, int ret, char *file,
                                   int line)
 {
@@ -1744,21 +1203,34 @@ static const OSSL_RECORD_METHOD *ssl_select_next_record_layer(SSL_CONNECTION *s,
     return s->rlayer.rrlmethod;
 }
 
-static int ssl_post_record_layer_select(SSL_CONNECTION *s)
+static int ssl_post_record_layer_select(SSL_CONNECTION *s, int direction)
 {
+    const OSSL_RECORD_METHOD *thismethod;
+    OSSL_RECORD_LAYER *thisrl;
+
+    if (direction == OSSL_RECORD_DIRECTION_READ) {
+        thismethod = s->rlayer.rrlmethod;
+        thisrl = s->rlayer.rrl;
+    } else {
+        thismethod = s->rlayer.wrlmethod;
+        thisrl = s->rlayer.wrl;
+    }
+
 #ifndef OPENSSL_NO_KTLS
-    SSL *ssl = SSL_CONNECTION_GET_SSL(s);
+    {
+        SSL *ssl = SSL_CONNECTION_GET_SSL(s);
 
-    if (s->rlayer.rrlmethod == &ossl_ktls_record_method) {
-        /* KTLS does not support renegotiation so disallow it */
-        SSL_set_options(ssl, SSL_OP_NO_RENEGOTIATION);
+        if (s->rlayer.rrlmethod == &ossl_ktls_record_method) {
+            /* KTLS does not support renegotiation so disallow it */
+            SSL_set_options(ssl, SSL_OP_NO_RENEGOTIATION);
+        }
     }
 #endif
-    if (SSL_IS_FIRST_HANDSHAKE(s) && s->rlayer.rrlmethod->set_first_handshake != NULL)
-        s->rlayer.rrlmethod->set_first_handshake(s->rlayer.rrl, 1);
+    if (SSL_IS_FIRST_HANDSHAKE(s) && thismethod->set_first_handshake != NULL)
+        thismethod->set_first_handshake(thisrl, 1);
 
-    if (s->max_pipelines != 0 && s->rlayer.rrlmethod->set_max_pipelines != NULL)
-        s->rlayer.rrlmethod->set_max_pipelines(s->rlayer.rrl, s->max_pipelines);
+    if (s->max_pipelines != 0 && thismethod->set_max_pipelines != NULL)
+        thismethod->set_max_pipelines(thisrl, s->max_pipelines);
 
     return 1;
 }
@@ -1775,6 +1247,9 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
     OSSL_PARAM options[5], *opts = options;
     OSSL_PARAM settings[6], *set =  settings;
     const OSSL_RECORD_METHOD *origmeth = s->rlayer.rrlmethod;
+    const OSSL_RECORD_METHOD **thismethod;
+    OSSL_RECORD_LAYER **thisrl;
+    BIO *thisbio;
     SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
     const OSSL_RECORD_METHOD *meth;
     int use_etm, stream_mac = 0, tlstree = 0;
@@ -1784,16 +1259,26 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
 
     meth = ssl_select_next_record_layer(s, level);
 
-    if (s->rlayer.rrlmethod != NULL && !s->rlayer.rrlmethod->free(s->rlayer.rrl)) {
+    if (direction == OSSL_RECORD_DIRECTION_READ) {
+        thismethod = &s->rlayer.rrlmethod;
+        thisrl = &s->rlayer.rrl;
+        thisbio = s->rbio;
+    } else {
+        thismethod = &s->rlayer.wrlmethod;
+        thisrl = &s->rlayer.wrl;
+        thisbio = s->wbio;
+    }
+
+    if (*thismethod != NULL && !(*thismethod)->free(*thisrl)) {
         ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
         return 0;
     }
 
-    s->rlayer.rrl = NULL;
+    *thisrl = NULL;
     if (meth != NULL)
-        s->rlayer.rrlmethod = meth;
+        *thismethod = meth;
 
-    if (!ossl_assert(s->rlayer.rrlmethod != NULL)) {
+    if (!ossl_assert(*thismethod != NULL)) {
         ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
         return 0;
     }
@@ -1803,10 +1288,12 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
                                           &s->options);
     *opts++ = OSSL_PARAM_construct_uint32(OSSL_LIBSSL_RECORD_LAYER_PARAM_MODE,
                                           &s->mode);
-    *opts++ = OSSL_PARAM_construct_size_t(OSSL_LIBSSL_RECORD_LAYER_READ_BUFFER_LEN,
-                                          &s->rlayer.default_read_buf_len);
-    *opts++ = OSSL_PARAM_construct_int(OSSL_LIBSSL_RECORD_LAYER_PARAM_READ_AHEAD,
-                                       &s->rlayer.read_ahead);
+    if (direction == OSSL_RECORD_DIRECTION_READ) {
+        *opts++ = OSSL_PARAM_construct_size_t(OSSL_LIBSSL_RECORD_LAYER_READ_BUFFER_LEN,
+                                              &s->rlayer.default_read_buf_len);
+        *opts++ = OSSL_PARAM_construct_int(OSSL_LIBSSL_RECORD_LAYER_PARAM_READ_AHEAD,
+                                           &s->rlayer.read_ahead);
+    }
     *opts = OSSL_PARAM_construct_end();
 
     /* Parameters that *must* be supported by a record layer if passed */
@@ -1862,43 +1349,49 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
 
         if (max_early_data != 0)
             *set++ = OSSL_PARAM_construct_uint(OSSL_LIBSSL_RECORD_LAYER_PARAM_MAX_EARLY_DATA,
-                                            &max_early_data);
+                                               &max_early_data);
     }
 
     *set = OSSL_PARAM_construct_end();
 
     for (;;) {
         int rlret;
-        BIO *prev = s->rlayer.rrlnext;
+        BIO *prev = NULL;
+        BIO *next = NULL;
         unsigned int epoch = 0;;
 
-        if (SSL_CONNECTION_IS_DTLS(s)
-                && level != OSSL_RECORD_PROTECTION_LEVEL_NONE)
-            epoch =  DTLS_RECORD_LAYER_get_r_epoch(&s->rlayer) + 1; /* new epoch */
 
-        if (SSL_CONNECTION_IS_DTLS(s))
-            s->rlayer.rrlnext = BIO_new(BIO_s_dgram_mem());
-        else
-            s->rlayer.rrlnext = BIO_new(BIO_s_mem());
+        if (direction == OSSL_RECORD_DIRECTION_READ) {
+            prev = s->rlayer.rrlnext;
+            if (SSL_CONNECTION_IS_DTLS(s)
+                    && level != OSSL_RECORD_PROTECTION_LEVEL_NONE)
+                epoch =  DTLS_RECORD_LAYER_get_r_epoch(&s->rlayer) + 1; /* new epoch */
 
-        if (s->rlayer.rrlnext == NULL) {
-            BIO_free(prev);
-            SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
-            return 0;
+            if (SSL_CONNECTION_IS_DTLS(s))
+                next = BIO_new(BIO_s_dgram_mem());
+            else
+                next = BIO_new(BIO_s_mem());
+
+            if (next == NULL) {
+                BIO_free(prev);
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+            s->rlayer.rrlnext = next;
         }
 
-        rlret = s->rlayer.rrlmethod->new_record_layer(sctx->libctx,
-                                                      sctx->propq,
-                                                      version, s->server,
-                                                      direction, level, epoch,
-                                                      key, keylen, iv, ivlen,
-                                                      mackey, mackeylen, ciph,
-                                                      taglen, mactype, md, comp,
-                                                      prev, s->rbio,
-                                                      s->rlayer.rrlnext, NULL,
-                                                      NULL, settings, options,
-                                                      rlayer_dispatch, s,
-                                                      &s->rlayer.rrl);
+        rlret = (*thismethod)->new_record_layer(sctx->libctx,
+                                                sctx->propq,
+                                                version, s->server,
+                                                direction, level, epoch,
+                                                key, keylen, iv, ivlen,
+                                                mackey, mackeylen, ciph,
+                                                taglen, mactype, md, comp,
+                                                prev, thisbio,
+                                                next, NULL,
+                                                NULL, settings, options,
+                                                rlayer_dispatch, s,
+                                                thisrl);
         BIO_free(prev);
         switch (rlret) {
         case OSSL_RECORD_RETURN_FATAL:
@@ -1906,12 +1399,12 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
             return 0;
 
         case OSSL_RECORD_RETURN_NON_FATAL_ERR:
-            if (s->rlayer.rrlmethod != origmeth && origmeth != NULL) {
+            if (*thismethod != origmeth && origmeth != NULL) {
                 /*
                  * We tried a new record layer method, but it didn't work out,
                  * so we fallback to the original method and try again
                  */
-                s->rlayer.rrlmethod = origmeth;
+                *thismethod = origmeth;
                 continue;
             }
             SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_NO_SUITABLE_RECORD_LAYER);
@@ -1928,5 +1421,5 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
         break;
     }
 
-    return ssl_post_record_layer_select(s);
+    return ssl_post_record_layer_select(s, direction);
 }
index fe31ccdab567510da1d80fa4bee811a874498ada..1442b8cb67ed40b5db48a738c61b89e29559f4f1 100644 (file)
@@ -133,8 +133,12 @@ typedef struct record_layer_st {
 
     /* Method to use for the read record layer*/
     const OSSL_RECORD_METHOD *rrlmethod;
+    /* Method to use for the write record layer*/
+    const OSSL_RECORD_METHOD *wrlmethod;
     /* The read record layer object itself */
     OSSL_RECORD_LAYER *rrl;
+    /* The write record layer object itself */
+    OSSL_RECORD_LAYER *wrl;
     /* BIO to store data destined for the next read record layer epoch */
     BIO *rrlnext;
     /* Default read buffer length to be passed to the record layer */
@@ -217,7 +221,6 @@ __owur int ssl3_enc(SSL_CONNECTION *s, SSL3_RECORD *inrecs, size_t n_recs,
                     int send, SSL_MAC_BUF *mac, size_t macsize);
 __owur int n_ssl3_mac(SSL_CONNECTION *s, SSL3_RECORD *rec, unsigned char *md,
                       int send);
-__owur int tls_retry_write_records(SSL_CONNECTION *s);
 __owur int tls1_enc(SSL_CONNECTION *s, SSL3_RECORD *recs, size_t n_recs,
                     int sending, SSL_MAC_BUF *mac, size_t macsize);
 __owur int tls1_mac_old(SSL_CONNECTION *s, SSL3_RECORD *rec, unsigned char *md,
@@ -263,7 +266,4 @@ OSSL_CORE_MAKE_FUNC(void, rlayer_msg_callback, (int write_p, int version,
                                                 void *cbarg))
 # define OSSL_FUNC_RLAYER_SECURITY               3
 OSSL_CORE_MAKE_FUNC(int, rlayer_security, (void *cbarg, int op, int bits,
-                                           int nid, void *other))
-
-int tls_write_records(SSL_CONNECTION *s, OSSL_RECORD_TEMPLATE *templates,
-                      size_t numtempl);
+                                           int nid, void *other))
\ No newline at end of file
index 9e77c5f4e43809c362b0c42a99cd2083dabd493a..a6dd59fc3226ee158cec1b149ff3bb82e1215c90 100644 (file)
@@ -186,11 +186,6 @@ struct ossl_record_method_st {
      * by |templates|. Each record should be no longer than the value returned
      * by get_max_record_len(), and there should be no more records than the
      * value returned by get_max_records().
-     * |allowance| is the maximum amount of "on-the-wire" data that is allowed
-     * to be sent at the moment (including all QUIC headers, but excluding any
-     * UDP/IP headers). After a successful or retry return |*sent| will
-     * be updated with the amount of data that has been sent so far. In the case
-     * of a retry this could be 0.
      * Where possible the caller will attempt to ensure that all records are the
      * same length, except the last record. This may not always be possible so
      * the record method implementation should not rely on this being the case.
@@ -206,24 +201,19 @@ struct ossl_record_method_st {
      *  0 on retry
      * -1 on failure
      */
-    int (*write_records)(OSSL_RECORD_LAYER *rl, OSSL_RECORD_TEMPLATE **templates,
-                         size_t numtempl, size_t allowance, size_t *sent);
+    int (*write_records)(OSSL_RECORD_LAYER *rl, OSSL_RECORD_TEMPLATE *templates,
+                         size_t numtempl);
 
     /*
      * Retry a previous call to write_records. The caller should continue to
      * call this until the function returns with success or failure. After
-     * each retry more of the data may have been incrementally sent. |allowance|
-     * is the amount of "on-the-wire" data that is allowed to be sent at the
-     * moment. After a successful or retry return |*sent| will
-     * be updated with the amount of data that has been sent by this call to
-     * retry_write_records().
+     * each retry more of the data may have been incrementally sent.
      * Returns:
      *  1 on success
      *  0 on retry
      * -1 on failure
      */
-    int (*retry_write_records)(OSSL_RECORD_LAYER *rl, size_t allowance,
-                               size_t *sent);
+    int (*retry_write_records)(OSSL_RECORD_LAYER *rl);
 
     /*
      * Read a record and return the record layer version and record type in
index bfff734a4f685ca5c00d0b9c3b460395dcee9caa..a1b91a0acb780a037a571b2844888214a6798527 100644 (file)
@@ -99,6 +99,8 @@ int ssl3_change_cipher_state(SSL_CONNECTION *s, int which)
     int mdi;
     size_t n, iv_len, key_len;
     int reuse_dd = 0;
+    int direction = (which & SSL3_CC_READ) != 0 ? OSSL_RECORD_DIRECTION_READ
+                                                : OSSL_RECORD_DIRECTION_WRITE;
 
     ciph = s->s3.tmp.new_sym_enc;
     md = s->s3.tmp.new_hash;
@@ -143,16 +145,16 @@ int ssl3_change_cipher_state(SSL_CONNECTION *s, int which)
         goto err;
     }
 
-    if (which & SSL3_CC_READ) {
-        if (!ssl_set_new_record_layer(s, SSL3_VERSION,
-                                      OSSL_RECORD_DIRECTION_READ,
-                                      OSSL_RECORD_PROTECTION_LEVEL_APPLICATION,
-                                      key, key_len, iv, iv_len, mac_secret,
-                                      md_len, ciph, 0, NID_undef, md, comp)) {
-            /* SSLfatal already called */
-            goto err;
-        }
+    if (!ssl_set_new_record_layer(s, SSL3_VERSION,
+                                  direction,
+                                  OSSL_RECORD_PROTECTION_LEVEL_APPLICATION,
+                                  key, key_len, iv, iv_len, mac_secret,
+                                  md_len, ciph, 0, NID_undef, md, comp)) {
+        /* SSLfatal already called */
+        goto err;
+    }
 
+    if (which & SSL3_CC_READ) {
         s->statem.enc_write_state = ENC_WRITE_STATE_VALID;
         return 1;
     }
index 749c93e16d770766957a1b0e25c98297516641e4..06acc0b46635444e2b84c8b785ec942543c2ebf6 100644 (file)
@@ -95,7 +95,7 @@ int ssl3_dispatch_alert(SSL *s)
     if (RECORD_LAYER_write_pending(&sc->rlayer))
         return -1;
 
-    i = tls_write_records(sc, &templ, 1);
+    i = sc->rlayer.wrlmethod->write_records(sc->rlayer.wrl, &templ, 1);
     if (i <= 0) {
         sc->s3.alert_dispatch = 1;
     } else {
index a143dbf3179f40c529b9ccf2b60e230d444750a8..b976324f925048e4a7fc990391c586e99ad728cb 100644 (file)
@@ -669,6 +669,15 @@ int ossl_ssl_connection_reset(SSL *s)
         /* SSLfatal already called */
         return 0;
     }
+    if (!ssl_set_new_record_layer(sc,
+                                  SSL_CONNECTION_IS_DTLS(sc) ? DTLS_ANY_VERSION : TLS_ANY_VERSION,
+                                  OSSL_RECORD_DIRECTION_WRITE,
+                                  OSSL_RECORD_PROTECTION_LEVEL_NONE,
+                                  NULL, 0, NULL, 0, NULL,  0, NULL, 0,
+                                  NID_undef, NULL, NULL)) {
+        /* SSLfatal already called */
+        return 0;
+    }
 
     return 1;
 }
index 920c8e028b102a91cfc288e3c3a675a0c8a7aca9..7c7876b7df8de69f3477c3c67ff0977945f45a3e 100644 (file)
@@ -243,11 +243,11 @@ int tls1_change_cipher_state(SSL_CONNECTION *s, int which)
             s->mac_flags &= ~SSL_MAC_FLAG_READ_MAC_TLSTREE;
 
         if (!ssl_set_new_record_layer(s, s->version,
-                                        OSSL_RECORD_DIRECTION_READ,
-                                        OSSL_RECORD_PROTECTION_LEVEL_APPLICATION,
-                                        key, cl, iv, (size_t)k, mac_secret,
-                                        mac_secret_size, c, taglen, mac_type,
-                                        m, comp)) {
+                                      OSSL_RECORD_DIRECTION_READ,
+                                      OSSL_RECORD_PROTECTION_LEVEL_APPLICATION,
+                                      key, cl, iv, (size_t)k, mac_secret,
+                                      mac_secret_size, c, taglen, mac_type,
+                                      m, comp)) {
             /* SSLfatal already called */
             goto err;
         }
@@ -270,6 +270,17 @@ int tls1_change_cipher_state(SSL_CONNECTION *s, int which)
             s->mac_flags |= SSL_MAC_FLAG_WRITE_MAC_TLSTREE;
         else
             s->mac_flags &= ~SSL_MAC_FLAG_WRITE_MAC_TLSTREE;
+
+        if (!ssl_set_new_record_layer(s, s->version,
+                                      OSSL_RECORD_DIRECTION_WRITE,
+                                      OSSL_RECORD_PROTECTION_LEVEL_APPLICATION,
+                                      key, cl, iv, (size_t)k, mac_secret,
+                                      mac_secret_size, c, taglen, mac_type,
+                                      m, comp)) {
+            /* SSLfatal already called */
+            goto err;
+        }
+
         if (s->enc_write_ctx != NULL && !SSL_CONNECTION_IS_DTLS(s)) {
             reuse_dd = 1;
         } else if ((s->enc_write_ctx = EVP_CIPHER_CTX_new()) == NULL) {
index 539dcd2f918aa3f2736937f5160792649192b469..829dfe3c102c4dad7423c4029c8f6c3b357237ed 100644 (file)
@@ -458,6 +458,9 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which)
     const EVP_CIPHER *cipher = NULL;
     SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
     size_t keylen, ivlen, taglen;
+    int level;
+    int direction = (which & SSL3_CC_READ) != 0 ? OSSL_RECORD_DIRECTION_READ
+                                                : OSSL_RECORD_DIRECTION_WRITE;
 #if !defined(OPENSSL_NO_KTLS) && defined(OPENSSL_KTLS_TLS13)
     ktls_crypto_info_t crypto_info;
     void *rl_sequence;
@@ -702,20 +705,21 @@ int tls13_change_cipher_state(SSL_CONNECTION *s, int which)
     else
         s->statem.enc_write_state = ENC_WRITE_STATE_VALID;
 
+    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);
+
+    if (!ssl_set_new_record_layer(s, s->version,
+                                  direction,
+                                  level, key, keylen, iv, ivlen, NULL, 0,
+                                  cipher, taglen, NID_undef, NULL, NULL)) {
+        /* SSLfatal already called */
+        goto err;
+    }
+
     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);
-
-        if (!ssl_set_new_record_layer(s, s->version,
-                                    OSSL_RECORD_DIRECTION_READ,
-                                    level, key, keylen, iv, ivlen, NULL, 0,
-                                    cipher, taglen, NID_undef, NULL, NULL)) {
-            /* SSLfatal already called */
-            goto err;
-        }
         /* TODO(RECLAYER): Remove me when write rlayer done */
         goto skip_ktls;
     }
@@ -797,6 +801,8 @@ int tls13_update_key(SSL_CONNECTION *s, int sending)
     EVP_CIPHER_CTX *ciph_ctx;
     size_t keylen, ivlen, taglen;
     int ret = 0, l;
+    int direction = sending ? OSSL_RECORD_DIRECTION_WRITE
+                            : OSSL_RECORD_DIRECTION_READ;
 
     if ((l = EVP_MD_get_size(md)) <= 0) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
@@ -830,16 +836,14 @@ int tls13_update_key(SSL_CONNECTION *s, int sending)
 
     memcpy(insecret, secret, hashlen);
 
-    if (!sending) {
-        if (!ssl_set_new_record_layer(s, s->version,
-                                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)) {
-            /* SSLfatal already called */
-            goto err;
-        }
+    if (!ssl_set_new_record_layer(s, s->version,
+                            direction,
+                            OSSL_RECORD_PROTECTION_LEVEL_APPLICATION,
+                            key, keylen, iv, ivlen, NULL, 0,
+                            s->s3.tmp.new_sym_enc, taglen, NID_undef, NULL,
+                            NULL)) {
+        /* SSLfatal already called */
+        goto err;
     }
 
     s->statem.enc_write_state = ENC_WRITE_STATE_VALID;