+ OSSL_PARAM options[5], *opts = options;
+ OSSL_PARAM settings[6], *set = settings;
+ const OSSL_RECORD_METHOD **thismethod;
+ OSSL_RECORD_LAYER **thisrl, *newrl = NULL;
+ BIO *thisbio;
+ SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
+ const OSSL_RECORD_METHOD *meth;
+ int use_etm, stream_mac = 0, tlstree = 0;
+ unsigned int maxfrag = (direction == OSSL_RECORD_DIRECTION_WRITE)
+ ? ssl_get_max_send_fragment(s)
+ : SSL3_RT_MAX_PLAIN_LENGTH;
+ int use_early_data = 0;
+ uint32_t max_early_data;
+ COMP_METHOD *compm = (comp == NULL) ? NULL : comp->method;
+
+ meth = ssl_select_next_record_layer(s, direction, level);
+
+ 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 (meth == NULL)
+ meth = *thismethod;
+
+ if (!ossl_assert(meth != NULL)) {
+ ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ /* Parameters that *may* be supported by a record layer if passed */
+ *opts++ = OSSL_PARAM_construct_uint64(OSSL_LIBSSL_RECORD_LAYER_PARAM_OPTIONS,
+ &s->options);
+ *opts++ = OSSL_PARAM_construct_uint32(OSSL_LIBSSL_RECORD_LAYER_PARAM_MODE,
+ &s->mode);
+ 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);
+ } else {
+ *opts++ = OSSL_PARAM_construct_size_t(OSSL_LIBSSL_RECORD_LAYER_PARAM_BLOCK_PADDING,
+ &s->rlayer.block_padding);
+ }
+ *opts = OSSL_PARAM_construct_end();
+
+ /* Parameters that *must* be supported by a record layer if passed */
+ if (direction == OSSL_RECORD_DIRECTION_READ) {
+ use_etm = SSL_READ_ETM(s) ? 1 : 0;
+ if ((s->mac_flags & SSL_MAC_FLAG_READ_MAC_STREAM) != 0)
+ stream_mac = 1;
+
+ if ((s->mac_flags & SSL_MAC_FLAG_READ_MAC_TLSTREE) != 0)
+ tlstree = 1;
+ } else {
+ use_etm = SSL_WRITE_ETM(s) ? 1 : 0;
+ if ((s->mac_flags & SSL_MAC_FLAG_WRITE_MAC_STREAM) != 0)
+ stream_mac = 1;
+
+ if ((s->mac_flags & SSL_MAC_FLAG_WRITE_MAC_TLSTREE) != 0)
+ tlstree = 1;
+ }
+
+ if (use_etm)
+ *set++ = OSSL_PARAM_construct_int(OSSL_LIBSSL_RECORD_LAYER_PARAM_USE_ETM,
+ &use_etm);
+
+ if (stream_mac)
+ *set++ = OSSL_PARAM_construct_int(OSSL_LIBSSL_RECORD_LAYER_PARAM_STREAM_MAC,
+ &stream_mac);
+
+ if (tlstree)
+ *set++ = OSSL_PARAM_construct_int(OSSL_LIBSSL_RECORD_LAYER_PARAM_TLSTREE,
+ &tlstree);
+
+ /*
+ * We only need to do this for the read side. The write side should already
+ * have the correct value due to the ssl_get_max_send_fragment() call above
+ */
+ if (direction == OSSL_RECORD_DIRECTION_READ
+ && s->session != NULL
+ && USE_MAX_FRAGMENT_LENGTH_EXT(s->session))
+ maxfrag = GET_MAX_FRAGMENT_LENGTH(s->session);
+
+
+ if (maxfrag != SSL3_RT_MAX_PLAIN_LENGTH)
+ *set++ = OSSL_PARAM_construct_uint(OSSL_LIBSSL_RECORD_LAYER_PARAM_MAX_FRAG_LEN,
+ &maxfrag);
+
+ /*
+ * The record layer must check the amount of early data sent or received
+ * using the early keys. A server also needs to worry about rejected early
+ * data that might arrive when the handshake keys are in force.
+ */
+ if (s->server && direction == OSSL_RECORD_DIRECTION_READ) {
+ use_early_data = (level == OSSL_RECORD_PROTECTION_LEVEL_EARLY
+ || level == OSSL_RECORD_PROTECTION_LEVEL_HANDSHAKE);
+ } else if (!s->server && direction == OSSL_RECORD_DIRECTION_WRITE) {
+ use_early_data = (level == OSSL_RECORD_PROTECTION_LEVEL_EARLY);
+ }
+ if (use_early_data) {
+ max_early_data = ossl_get_max_early_data(s);
+
+ if (max_early_data != 0)
+ *set++ = OSSL_PARAM_construct_uint32(OSSL_LIBSSL_RECORD_LAYER_PARAM_MAX_EARLY_DATA,
+ &max_early_data);
+ }
+
+ *set = OSSL_PARAM_construct_end();
+
+ for (;;) {
+ int rlret;
+ BIO *prev = NULL;
+ BIO *next = NULL;
+ unsigned int epoch = 0;
+ OSSL_DISPATCH rlayer_dispatch_tmp[OSSL_NELEM(rlayer_dispatch)];
+ size_t i, j;
+
+ if (direction == OSSL_RECORD_DIRECTION_READ) {
+ prev = s->rlayer.rrlnext;
+ if (SSL_CONNECTION_IS_DTLS(s)
+ && level != OSSL_RECORD_PROTECTION_LEVEL_NONE)
+ epoch = dtls1_get_epoch(s, SSL3_CC_READ); /* new epoch */
+
+#ifndef OPENSSL_NO_DGRAM
+ if (SSL_CONNECTION_IS_DTLS(s))
+ next = BIO_new(BIO_s_dgram_mem());
+ else
+#endif
+ next = BIO_new(BIO_s_mem());
+
+ if (next == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ s->rlayer.rrlnext = next;
+ } else {
+ if (SSL_CONNECTION_IS_DTLS(s)
+ && level != OSSL_RECORD_PROTECTION_LEVEL_NONE)
+ epoch = dtls1_get_epoch(s, SSL3_CC_WRITE); /* new epoch */
+ }
+
+ /*
+ * Create a copy of the dispatch array, missing out wrappers for
+ * callbacks that we don't need.
+ */
+ for (i = 0, j = 0; i < OSSL_NELEM(rlayer_dispatch); i++) {
+ switch (rlayer_dispatch[i].function_id) {
+ case OSSL_FUNC_RLAYER_MSG_CALLBACK:
+ if (s->msg_callback == NULL)
+ continue;
+ break;
+ case OSSL_FUNC_RLAYER_PADDING:
+ if (s->rlayer.record_padding_cb == NULL)
+ continue;
+ break;
+ default:
+ break;
+ }
+ rlayer_dispatch_tmp[j++] = rlayer_dispatch[i];
+ }
+
+ rlret = meth->new_record_layer(sctx->libctx, sctx->propq, version,
+ s->server, direction, level, epoch,
+ secret, secretlen, key, keylen, iv,
+ ivlen, mackey, mackeylen, ciph, taglen,
+ mactype, md, compm, kdfdigest, prev,
+ thisbio, next, NULL, NULL, settings,
+ options, rlayer_dispatch_tmp, s,
+ s->rlayer.rlarg, &newrl);
+ BIO_free(prev);
+ switch (rlret) {
+ case OSSL_RECORD_RETURN_FATAL:
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_RECORD_LAYER_FAILURE);
+ return 0;
+
+ case OSSL_RECORD_RETURN_NON_FATAL_ERR:
+ if (*thismethod != meth && *thismethod != NULL) {
+ /*
+ * We tried a new record layer method, but it didn't work out,
+ * so we fallback to the original method and try again
+ */
+ meth = *thismethod;
+ continue;
+ }
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_NO_SUITABLE_RECORD_LAYER);
+ return 0;
+
+ case OSSL_RECORD_RETURN_SUCCESS:
+ break;
+
+ default:
+ /* Should not happen */
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ break;
+ }
+
+ /*
+ * Free the old record layer if we have one except in the case of DTLS when
+ * writing and there are still buffered sent messages in our queue. In that
+ * case the record layer is still referenced by those buffered messages for
+ * potential retransmit. Only when those buffered messages get freed do we
+ * free the record layer object (see dtls1_hm_fragment_free)
+ */
+ if (!SSL_CONNECTION_IS_DTLS(s)
+ || direction == OSSL_RECORD_DIRECTION_READ
+ || pqueue_peek(s->d1->sent_messages) == NULL) {
+ if (*thismethod != NULL && !(*thismethod)->free(*thisrl)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ }
+
+ *thisrl = newrl;
+ *thismethod = meth;
+
+ return ssl_post_record_layer_select(s, direction);
+}
+
+int ssl_set_record_protocol_version(SSL_CONNECTION *s, int vers)
+{
+ if (!ossl_assert(s->rlayer.rrlmethod != NULL)
+ || !ossl_assert(s->rlayer.wrlmethod != NULL))
+ return 0;
+ s->rlayer.rrlmethod->set_protocol_version(s->rlayer.rrl, s->version);
+ s->rlayer.wrlmethod->set_protocol_version(s->rlayer.wrl, s->version);
+
+ return 1;