#include "../record_local.h"
#include "recmethod_local.h"
-# define SSL_AD_NO_ALERT -1
-
static void tls_int_free(OSSL_RECORD_LAYER *rl);
void ossl_rlayer_fatal(OSSL_RECORD_LAYER *rl, int al, int reason,
}
#ifndef OPENSSL_NO_COMP
-static int rlayer_allow_compression(OSSL_RECORD_LAYER *rl)
+static int tls_allow_compression(OSSL_RECORD_LAYER *rl)
{
if (rl->options & SSL_OP_NO_COMPRESSION)
return 0;
- return rl->security(rl->cbarg, SSL_SECOP_COMPRESSION, 0, 0, NULL);
+ return rl->security == NULL
+ || rl->security(rl->cbarg, SSL_SECOP_COMPRESSION, 0, 0, NULL);
}
#endif
-int rlayer_setup_read_buffer(OSSL_RECORD_LAYER *rl)
+int tls_setup_read_buffer(OSSL_RECORD_LAYER *rl)
{
unsigned char *p;
size_t len, align = 0, headerlen;
else
headerlen = SSL3_RT_HEADER_LENGTH;
-#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0
align = (-SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1);
#endif
len = SSL3_RT_MAX_PLAIN_LENGTH
+ SSL3_RT_MAX_ENCRYPTED_OVERHEAD + headerlen + align;
#ifndef OPENSSL_NO_COMP
- if (rlayer_allow_compression(rl))
+ if (tls_allow_compression(rl))
len += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
#endif
if (b->default_len > len)
return 1;
}
-static int rlayer_release_read_buffer(OSSL_RECORD_LAYER *rl)
+static int tls_release_read_buffer(OSSL_RECORD_LAYER *rl)
{
SSL3_BUFFER *b;
b = &rl->rbuf;
- if (rl->options & SSL_OP_CLEANSE_PLAINTEXT)
+ if ((rl->options & SSL_OP_CLEANSE_PLAINTEXT) != 0)
OPENSSL_cleanse(b->buf, b->len);
OPENSSL_free(b->buf);
b->buf = NULL;
BIO *bio = rl->prev != NULL ? rl->prev : rl->bio;
/*
- * Now we have len+left bytes at the front of s->s3.rbuf.buf and
- * need to read in more until we have len+n (up to len+max if
+ * Now we have len+left bytes at the front of rl->rbuf.buf and
+ * need to read in more until we have len + n (up to len + max if
* possible)
*/
if (ret <= OSSL_RECORD_RETURN_RETRY) {
rb->left = left;
- if (rl->mode & SSL_MODE_RELEASE_BUFFERS && !rl->isdtls)
+ if ((rl->mode & SSL_MODE_RELEASE_BUFFERS) != 0 && !rl->isdtls)
if (len + left == 0)
- rlayer_release_read_buffer(rl);
+ tls_release_read_buffer(rl);
return ret;
}
left += bioread;
if (max_early_data == 0) {
RLAYERfatal(rl, send ? SSL_AD_INTERNAL_ERROR : SSL_AD_UNEXPECTED_MESSAGE,
- SSL_R_TOO_MUCH_EARLY_DATA);
+ SSL_R_TOO_MUCH_EARLY_DATA);
return 0;
}
if (rl->early_data_count + length > max_early_data) {
RLAYERfatal(rl, send ? SSL_AD_INTERNAL_ERROR : SSL_AD_UNEXPECTED_MESSAGE,
- SSL_R_TOO_MUCH_EARLY_DATA);
+ SSL_R_TOO_MUCH_EARLY_DATA);
return 0;
}
rl->early_data_count += length;
/*
* MAX_EMPTY_RECORDS defines the number of consecutive, empty records that
- * will be processed per call to ssl3_get_record. Without this limit an
+ * will be processed per call to tls_get_more_records. Without this limit an
* attacker could send empty records at a faster rate than we can process and
- * cause ssl3_get_record to loop forever.
+ * cause tls_get_more_records to loop forever.
*/
#define MAX_EMPTY_RECORDS 32
rr = rl->rrec;
rbuf = &rl->rbuf;
if (rbuf->buf == NULL) {
- if (!rlayer_setup_read_buffer(rl)) {
+ if (!tls_setup_read_buffer(rl)) {
/* RLAYERfatal() already called */
return OSSL_RECORD_RETURN_FATAL;
}
thisrr->length = sslv2len & 0x7fff;
if (thisrr->length > SSL3_BUFFER_get_len(rbuf)
- - SSL2_RT_HEADER_LENGTH) {
+ - SSL2_RT_HEADER_LENGTH) {
RLAYERfatal(rl, SSL_AD_RECORD_OVERFLOW,
SSL_R_PACKET_LENGTH_TOO_LONG);
return OSSL_RECORD_RETURN_FATAL;
if (!PACKET_get_1(&pkt, &type)
|| !PACKET_get_net_2(&pkt, &version)
|| !PACKET_get_net_2_len(&pkt, &thisrr->length)) {
- rl->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, rl->cbarg);
+ if (rl->msg_callback != NULL)
+ rl->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, rl->cbarg);
RLAYERfatal(rl, SSL_AD_DECODE_ERROR, ERR_R_INTERNAL_ERROR);
return OSSL_RECORD_RETURN_FATAL;
}
return OSSL_RECORD_RETURN_FATAL;
}
- rl->msg_callback(0, version, SSL3_RT_HEADER, p, 5, rl->cbarg);
+ if (rl->msg_callback != NULL)
+ rl->msg_callback(0, version, SSL3_RT_HEADER, p, 5, rl->cbarg);
if (thisrr->length >
SSL3_BUFFER_get_len(rbuf) - SSL3_RT_HEADER_LENGTH) {
*/
if (thisrr->rec_version == SSL2_VERSION) {
more = thisrr->length + SSL2_RT_HEADER_LENGTH
- - SSL3_RT_HEADER_LENGTH;
+ - SSL3_RT_HEADER_LENGTH;
} else {
more = thisrr->length;
}
thisrr->data = thisrr->input;
thisrr->orig_len = thisrr->length;
- /* Mark this record as not read by upper layers yet */
- thisrr->read = 0;
-
num_recs++;
/* we have pulled in a full packet so zero things */
SSL_R_UNEXPECTED_CCS_MESSAGE);
return OSSL_RECORD_RETURN_FATAL;
}
- thisrr->read = 1;
rl->num_recs = 0;
rl->curr_rec = 0;
rl->num_released = 0;
if (tmpmd != NULL) {
imac_size = EVP_MD_get_size(tmpmd);
if (!ossl_assert(imac_size >= 0 && imac_size <= EVP_MAX_MD_SIZE)) {
- RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
- return OSSL_RECORD_RETURN_FATAL;
+ RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
+ return OSSL_RECORD_RETURN_FATAL;
}
mac_size = (size_t)imac_size;
}
* 1: Success or MTE decryption failed (MAC will be randomised)
*/
if (enc_err == 0) {
- if (rl->alert != 0) {
+ if (rl->alert != SSL_AD_NO_ALERT) {
/* RLAYERfatal() already got called */
goto end;
}
- if (num_recs == 1 && rl->skip_early_data(rl->cbarg)) {
+ if (num_recs == 1
+ && rl->skip_early_data != NULL
+ && rl->skip_early_data(rl->cbarg)) {
/*
* Valid early_data that we cannot decrypt will fail here. We treat
* it like an empty record.
}
thisrr->length = 0;
- thisrr->read = 1;
rl->num_recs = 0;
rl->curr_rec = 0;
rl->num_released = 0;
for (j = 0; j < num_recs; j++) {
SSL_MAC_BUF *thismb = &macbufs[j];
+
thisrr = &rr[j];
i = rl->funcs->mac(rl, thisrr, md, 0 /* not send */);
}
if (enc_err == 0) {
- if (rl->alert != 0) {
+ if (rl->alert != SSL_AD_NO_ALERT) {
/* We already called RLAYERfatal() */
goto end;
}
/* just read a 0 length packet */
if (thisrr->length == 0) {
if (++(rl->empty_record_count) > MAX_EMPTY_RECORDS) {
- RLAYERfatal(rl, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_RECORD_TOO_SMALL);
+ RLAYERfatal(rl, SSL_AD_UNEXPECTED_MESSAGE,
+ SSL_R_RECORD_TOO_SMALL);
goto end;
}
} else {
#ifndef OPENSSL_NO_COMP
/*
- * If OPENSSL_NO_COMP is defined then SSL3_RT_MAX_ENCRYPTED_LENGTH
- * does not include the compression overhead anyway.
- */
+ * If OPENSSL_NO_COMP is defined then SSL3_RT_MAX_ENCRYPTED_LENGTH
+ * does not include the compression overhead anyway.
+ */
if (rl->expand == NULL)
len -= SSL3_RT_MAX_COMPRESSED_OVERHEAD;
#endif
if (rec->comp == NULL)
return 0;
- i = COMP_expand_block(rl->expand, rec->comp,
- SSL3_RT_MAX_PLAIN_LENGTH, rec->data, (int)rec->length);
+ i = COMP_expand_block(rl->expand, rec->comp, SSL3_RT_MAX_PLAIN_LENGTH,
+ rec->data, (int)rec->length);
if (i < 0)
return 0;
else
return 0;
}
- rl->msg_callback(0, rl->version, SSL3_RT_INNER_CONTENT_TYPE, &rec->type,
+ if (rl->msg_callback != NULL)
+ rl->msg_callback(0, rl->version, SSL3_RT_INNER_CONTENT_TYPE, &rec->type,
1, rl->cbarg);
/*
* TLSv1.3 alert and handshake records are required to be non-zero in
* length.
*/
- if ((rec->type == SSL3_RT_HANDSHAKE
- || rec->type == SSL3_RT_ALERT)
+ if ((rec->type == SSL3_RT_HANDSHAKE || rec->type == SSL3_RT_ALERT)
&& rec->length == 0) {
RLAYERfatal(rl, SSL_AD_UNEXPECTED_MESSAGE, SSL_R_BAD_LENGTH);
return 0;
return 1;
}
-int tls_read_record(OSSL_RECORD_LAYER *rl, void **rechandle, int *rversion,
+int tls_read_record(OSSL_RECORD_LAYER *rl, void **rechandle, int *rversion,
int *type, unsigned char **data, size_t *datalen,
uint16_t *epoch, unsigned char *seq_num)
{
*data = rec->data + rec->off;
*datalen = rec->length;
if (rl->isdtls) {
- *epoch = (uint16_t)rec->epoch;
+ *epoch = rec->epoch;
memcpy(seq_num, rec->seq_num, sizeof(rec->seq_num));
}
rl->num_released++;
+ if (rl->curr_rec == rl->num_released
+ && (rl->mode & SSL_MODE_RELEASE_BUFFERS) != 0
+ && SSL3_BUFFER_get_left(&rl->rbuf) == 0)
+ tls_release_read_buffer(rl);
+
return OSSL_RECORD_RETURN_SUCCESS;
}
+int tls_set_options(OSSL_RECORD_LAYER *rl, const OSSL_PARAM *options)
+{
+ const OSSL_PARAM *p;
+
+ p = OSSL_PARAM_locate_const(options, OSSL_LIBSSL_RECORD_LAYER_PARAM_OPTIONS);
+ if (p != NULL && !OSSL_PARAM_get_uint64(p, &rl->options)) {
+ ERR_raise(ERR_LIB_SSL, SSL_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+
+ p = OSSL_PARAM_locate_const(options, OSSL_LIBSSL_RECORD_LAYER_PARAM_MODE);
+ if (p != NULL && !OSSL_PARAM_get_uint32(p, &rl->mode)) {
+ ERR_raise(ERR_LIB_SSL, SSL_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+
+ p = OSSL_PARAM_locate_const(options,
+ OSSL_LIBSSL_RECORD_LAYER_READ_BUFFER_LEN);
+ if (p != NULL && !OSSL_PARAM_get_size_t(p, &rl->rbuf.default_len)) {
+ ERR_raise(ERR_LIB_SSL, SSL_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+
+ if (rl->level == OSSL_RECORD_PROTECTION_LEVEL_APPLICATION) {
+ /*
+ * We ignore any read_ahead setting prior to the application protection
+ * level. Otherwise we may read ahead data in a lower protection level
+ * that is destined for a higher protection level. To simplify the logic
+ * we don't support that at this stage.
+ */
+ p = OSSL_PARAM_locate_const(options,
+ OSSL_LIBSSL_RECORD_LAYER_PARAM_READ_AHEAD);
+ if (p != NULL && !OSSL_PARAM_get_int(p, &rl->read_ahead)) {
+ ERR_raise(ERR_LIB_SSL, SSL_R_FAILED_TO_GET_PARAMETER);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
int
tls_int_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
int role, int direction, int level, unsigned char *key,
*retrl = NULL;
if (rl == NULL) {
- RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE);
return OSSL_RECORD_RETURN_FATAL;
}
- /*
- * TODO(RECLAYER): Need to handle the case where the params are updated
- * after the record layer has been created.
- */
- p = OSSL_PARAM_locate_const(options, OSSL_LIBSSL_RECORD_LAYER_PARAM_OPTIONS);
- if (p != NULL && !OSSL_PARAM_get_uint64(p, &rl->options)) {
- RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_FAILED_TO_GET_PARAMETER);
- goto err;
- }
-
- p = OSSL_PARAM_locate_const(options, OSSL_LIBSSL_RECORD_LAYER_PARAM_MODE);
- if (p != NULL && !OSSL_PARAM_get_uint32(p, &rl->mode)) {
- RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_FAILED_TO_GET_PARAMETER);
- goto err;
- }
-
- p = OSSL_PARAM_locate_const(options, OSSL_LIBSSL_RECORD_LAYER_READ_BUFFER_LEN);
- if (p != NULL && !OSSL_PARAM_get_size_t(p, &rl->rbuf.default_len)) {
- RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_FAILED_TO_GET_PARAMETER);
- goto err;
- }
-
/* Loop through all the settings since they must all be understood */
- for (p = settings; p->key != NULL; p++) {
- if (strcmp(p->key, OSSL_LIBSSL_RECORD_LAYER_PARAM_USE_ETM) == 0) {
- if (!OSSL_PARAM_get_int(p, &rl->use_etm)) {
- RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_FAILED_TO_GET_PARAMETER);
- goto err;
- }
- } else if (strcmp(p->key, OSSL_LIBSSL_RECORD_LAYER_PARAM_MAX_FRAG_LEN) == 0) {
- if (!OSSL_PARAM_get_uint(p, &rl->max_frag_len)) {
- RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_FAILED_TO_GET_PARAMETER);
- goto err;
- }
- } else if (strcmp(p->key, OSSL_LIBSSL_RECORD_LAYER_PARAM_MAX_EARLY_DATA) == 0) {
- if (!OSSL_PARAM_get_uint32(p, &rl->max_early_data)) {
- RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_FAILED_TO_GET_PARAMETER);
- goto err;
- }
- } else if (strcmp(p->key, OSSL_LIBSSL_RECORD_LAYER_PARAM_STREAM_MAC) == 0) {
- if (!OSSL_PARAM_get_int(p, &rl->stream_mac)) {
- RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_FAILED_TO_GET_PARAMETER);
- goto err;
- }
- } else if (strcmp(p->key, OSSL_LIBSSL_RECORD_LAYER_PARAM_TLSTREE) == 0) {
- if (!OSSL_PARAM_get_int(p, &rl->tlstree)) {
- RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_FAILED_TO_GET_PARAMETER);
+ if (settings != NULL) {
+ for (p = settings; p->key != NULL; p++) {
+ if (strcmp(p->key, OSSL_LIBSSL_RECORD_LAYER_PARAM_USE_ETM) == 0) {
+ if (!OSSL_PARAM_get_int(p, &rl->use_etm)) {
+ ERR_raise(ERR_LIB_SSL, SSL_R_FAILED_TO_GET_PARAMETER);
+ goto err;
+ }
+ } else if (strcmp(p->key,
+ OSSL_LIBSSL_RECORD_LAYER_PARAM_MAX_FRAG_LEN) == 0) {
+ if (!OSSL_PARAM_get_uint(p, &rl->max_frag_len)) {
+ ERR_raise(ERR_LIB_SSL, SSL_R_FAILED_TO_GET_PARAMETER);
+ goto err;
+ }
+ } else if (strcmp(p->key,
+ OSSL_LIBSSL_RECORD_LAYER_PARAM_MAX_EARLY_DATA) == 0) {
+ if (!OSSL_PARAM_get_uint32(p, &rl->max_early_data)) {
+ ERR_raise(ERR_LIB_SSL, SSL_R_FAILED_TO_GET_PARAMETER);
+ goto err;
+ }
+ } else if (strcmp(p->key,
+ OSSL_LIBSSL_RECORD_LAYER_PARAM_STREAM_MAC) == 0) {
+ if (!OSSL_PARAM_get_int(p, &rl->stream_mac)) {
+ ERR_raise(ERR_LIB_SSL, SSL_R_FAILED_TO_GET_PARAMETER);
+ goto err;
+ }
+ } else if (strcmp(p->key,
+ OSSL_LIBSSL_RECORD_LAYER_PARAM_TLSTREE) == 0) {
+ if (!OSSL_PARAM_get_int(p, &rl->tlstree)) {
+ ERR_raise(ERR_LIB_SSL, SSL_R_FAILED_TO_GET_PARAMETER);
+ goto err;
+ }
+ } else {
+ ERR_raise(ERR_LIB_SSL, SSL_R_UNKNOWN_MANDATORY_PARAMETER);
goto err;
}
- } else {
- RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_UNKNOWN_MANDATORY_PARAMETER);
- goto err;
- }
- }
-
-
- if (level == OSSL_RECORD_PROTECTION_LEVEL_APPLICATION) {
- /*
- * We ignore any read_ahead setting prior to the application protection
- * level. Otherwise we may read ahead data in a lower protection level
- * that is destined for a higher protection level. To simplify the logic
- * we don't support that at this stage.
- */
- /*
- * TODO(RECLAYER): Handle the case of read_ahead at the application
- * level and a key update/reneg occurs.
- */
- p = OSSL_PARAM_locate_const(options, OSSL_LIBSSL_RECORD_LAYER_PARAM_READ_AHEAD);
- if (p != NULL && !OSSL_PARAM_get_int(p, &rl->read_ahead)) {
- RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_FAILED_TO_GET_PARAMETER);
- goto err;
}
}
rl->direction = direction;
rl->level = level;
+ rl->alert = SSL_AD_NO_ALERT;
+
if (level == OSSL_RECORD_PROTECTION_LEVEL_NONE)
rl->is_first_record = 1;
rl->next = next;
rl->cbarg = cbarg;
- for (; fns->function_id != 0; fns++) {
- switch (fns->function_id) {
- case OSSL_FUNC_RLAYER_SKIP_EARLY_DATA:
- rl->skip_early_data = OSSL_FUNC_rlayer_skip_early_data(fns);
- break;
- case OSSL_FUNC_RLAYER_MSG_CALLBACK:
- rl->msg_callback = OSSL_FUNC_rlayer_msg_callback(fns);
- break;
- case OSSL_FUNC_RLAYER_SECURITY:
- rl->security = OSSL_FUNC_rlayer_security(fns);
- break;
- default:
- /* Just ignore anything we don't understand */
- break;
+ if (fns != NULL) {
+ for (; fns->function_id != 0; fns++) {
+ switch (fns->function_id) {
+ case OSSL_FUNC_RLAYER_SKIP_EARLY_DATA:
+ rl->skip_early_data = OSSL_FUNC_rlayer_skip_early_data(fns);
+ break;
+ case OSSL_FUNC_RLAYER_MSG_CALLBACK:
+ rl->msg_callback = OSSL_FUNC_rlayer_msg_callback(fns);
+ break;
+ case OSSL_FUNC_RLAYER_SECURITY:
+ rl->security = OSSL_FUNC_rlayer_security(fns);
+ break;
+ default:
+ /* Just ignore anything we don't understand */
+ break;
+ }
}
}
+ if (!tls_set_options(rl, options)) {
+ ERR_raise(ERR_LIB_SSL, SSL_R_FAILED_TO_GET_PARAMETER);
+ goto err;
+ }
+
*retrl = rl;
return OSSL_RECORD_RETURN_SUCCESS;
err:
static int
tls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
- int role, int direction, int level, unsigned int epoch,
+ int role, int direction, int level, uint16_t epoch,
unsigned char *key, size_t keylen, unsigned char *iv,
size_t ivlen, unsigned char *mackey, size_t mackeylen,
const EVP_CIPHER *ciph, size_t taglen,
int mactype,
- const EVP_MD *md, const SSL_COMP *comp, BIO *prev,
+ const EVP_MD *md, const SSL_COMP *comp, BIO *prev,
BIO *transport, BIO *next, BIO_ADDR *local, BIO_ADDR *peer,
const OSSL_PARAM *settings, const OSSL_PARAM *options,
const OSSL_DISPATCH *fns, void *cbarg,
OSSL_RECORD_LAYER **retrl)
{
int ret;
-
+
ret = tls_int_new_record_layer(libctx, propq, vers, role, direction, level,
key, keylen, iv, ivlen, mackey, mackeylen,
ciph, taglen, mactype, md, comp, prev,
}
ret = (*retrl)->funcs->set_crypto_state(*retrl, level, key, keylen, iv,
- ivlen, mackey, mackeylen, ciph,
- taglen, mactype, md, comp);
+ ivlen, mackey, mackeylen, ciph,
+ taglen, mactype, md, comp);
err:
if (ret != OSSL_RECORD_RETURN_SUCCESS) {
if (rl->version == SSL3_VERSION)
OPENSSL_cleanse(rl->mac_secret, sizeof(rl->mac_secret));
+ SSL3_RECORD_release(rl->rrec, SSL_MAX_PIPELINES);
+
OPENSSL_free(rl);
}
return ret;
}
-
int tls_reset(OSSL_RECORD_LAYER *rl)
{
memset(rl, 0, sizeof(*rl));
size_t i;
size_t num = 0;
- for (i = rl->curr_rec; i <rl->num_recs; i++) {
+ for (i = rl->curr_rec; i < rl->num_recs; i++) {
if (rl->rrec[i].type != SSL3_RT_APPLICATION_DATA)
return num;
num += rl->rrec[i].length;
return 0;
}
-int tls_write_records(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 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;
+ }
+
+ 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 (rl->msg_callback) {
+ recordstart = WPACKET_get_curr(thispkt) - len
+ - SSL3_RT_HEADER_LENGTH;
+ rl->msg_callback(1, thiswr->rec_version, SSL3_RT_HEADER, recordstart,
+ SSL3_RT_HEADER_LENGTH, rl->cbarg);
+
+ if (SSL_CONNECTION_TREAT_AS_TLS13(s) && s->enc_write_ctx != NULL) {
+ unsigned char ctype = thistempl->type;
+
+ rl->msg_callback(1, thiswr->rec_version, SSL3_RT_INNER_CONTENT_TYPE,
+ &ctype, 1, rl->cbarg);
+ }
+ }
+
+ 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(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)
{
rl->read_ahead = 1;
}
+void tls_get_state(OSSL_RECORD_LAYER *rl, const char **shortstr,
+ const char **longstr)
+{
+ const char *shrt, *lng;
+
+ switch (rl->rstate) {
+ case SSL_ST_READ_HEADER:
+ shrt = "RH";
+ lng = "read header";
+ break;
+ case SSL_ST_READ_BODY:
+ shrt = "RB";
+ lng = "read body";
+ break;
+ default:
+ shrt = lng = "unknown";
+ break;
+ }
+ if (shortstr != NULL)
+ *shortstr = shrt;
+ if (longstr != NULL)
+ *longstr = lng;
+}
+
const OSSL_RECORD_METHOD ossl_tls_record_method = {
tls_new_record_layer,
tls_free,
tls_set_plain_alerts,
tls_set_first_handshake,
tls_set_max_pipelines,
- NULL
+ NULL,
+ tls_get_state,
+ tls_set_options
};