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,
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,
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,
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)
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,
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);
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;
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;
}
}
-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)
{
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;
}
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;
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;
}
&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 */
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:
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);
break;
}
- return ssl_post_record_layer_select(s);
+ return ssl_post_record_layer_select(s, direction);
}
/* 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 */
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,
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
* 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.
* 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
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;
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;
}
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 {
/* 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;
}
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;
}
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) {
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;
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;
}
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);
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;