openssl/ssl/record/methods/dtls_meth.c
Matt Caswell b05fbac1fc Fix dtls_get_max_record_overhead()
We fix dtls_get_max_record_overhead() to give a better value for the max
record overhead. We can't realistically handle the compression case so we
just ignore that.

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19516)
2022-11-07 10:59:20 +00:00

800 lines
24 KiB
C

/*
* Copyright 2018-2022 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <assert.h>
#include "../../ssl_local.h"
#include "../record_local.h"
#include "recmethod_local.h"
/* mod 128 saturating subtract of two 64-bit values in big-endian order */
static int satsub64be(const unsigned char *v1, const unsigned char *v2)
{
int64_t ret;
uint64_t l1, l2;
n2l8(v1, l1);
n2l8(v2, l2);
ret = l1 - l2;
/* We do not permit wrap-around */
if (l1 > l2 && ret < 0)
return 128;
else if (l2 > l1 && ret > 0)
return -128;
if (ret > 128)
return 128;
else if (ret < -128)
return -128;
else
return (int)ret;
}
static int dtls_record_replay_check(OSSL_RECORD_LAYER *rl, DTLS_BITMAP *bitmap)
{
int cmp;
unsigned int shift;
const unsigned char *seq = rl->sequence;
cmp = satsub64be(seq, bitmap->max_seq_num);
if (cmp > 0) {
SSL3_RECORD_set_seq_num(&rl->rrec[0], seq);
return 1; /* this record in new */
}
shift = -cmp;
if (shift >= sizeof(bitmap->map) * 8)
return 0; /* stale, outside the window */
else if (bitmap->map & ((uint64_t)1 << shift))
return 0; /* record previously received */
SSL3_RECORD_set_seq_num(&rl->rrec[0], seq);
return 1;
}
static void dtls_record_bitmap_update(OSSL_RECORD_LAYER *rl,
DTLS_BITMAP *bitmap)
{
int cmp;
unsigned int shift;
const unsigned char *seq = rl->sequence;
cmp = satsub64be(seq, bitmap->max_seq_num);
if (cmp > 0) {
shift = cmp;
if (shift < sizeof(bitmap->map) * 8)
bitmap->map <<= shift, bitmap->map |= 1UL;
else
bitmap->map = 1UL;
memcpy(bitmap->max_seq_num, seq, SEQ_NUM_SIZE);
} else {
shift = -cmp;
if (shift < sizeof(bitmap->map) * 8)
bitmap->map |= (uint64_t)1 << shift;
}
}
static DTLS_BITMAP *dtls_get_bitmap(OSSL_RECORD_LAYER *rl, SSL3_RECORD *rr,
unsigned int *is_next_epoch)
{
*is_next_epoch = 0;
/* In current epoch, accept HM, CCS, DATA, & ALERT */
if (rr->epoch == rl->epoch)
return &rl->bitmap;
/*
* Only HM and ALERT messages can be from the next epoch and only if we
* have already processed all of the unprocessed records from the last
* epoch
*/
else if (rr->epoch == (unsigned long)(rl->epoch + 1)
&& rl->unprocessed_rcds.epoch != rl->epoch
&& (rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ALERT)) {
*is_next_epoch = 1;
return &rl->next_bitmap;
}
return NULL;
}
static void dtls_set_in_init(OSSL_RECORD_LAYER *rl, int in_init)
{
rl->in_init = in_init;
}
static int dtls_process_record(OSSL_RECORD_LAYER *rl, DTLS_BITMAP *bitmap)
{
int i;
int enc_err;
SSL3_RECORD *rr;
int imac_size;
size_t mac_size = 0;
unsigned char md[EVP_MAX_MD_SIZE];
SSL_MAC_BUF macbuf = { NULL, 0 };
int ret = 0;
rr = &rl->rrec[0];
/*
* At this point, rl->packet_length == DTLS1_RT_HEADER_LENGTH + rr->length,
* and we have that many bytes in rl->packet
*/
rr->input = &(rl->packet[DTLS1_RT_HEADER_LENGTH]);
/*
* ok, we can now read from 'rl->packet' data into 'rr'. rr->input
* points at rr->length bytes, which need to be copied into rr->data by
* either the decryption or by the decompression. When the data is 'copied'
* into the rr->data buffer, rr->input will be pointed at the new buffer
*/
/*
* We now have - encrypted [ MAC [ compressed [ plain ] ] ] rr->length
* bytes of encrypted compressed stuff.
*/
/* check is not needed I believe */
if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
RLAYERfatal(rl, SSL_AD_RECORD_OVERFLOW, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
return 0;
}
/* decrypt in place in 'rr->input' */
rr->data = rr->input;
rr->orig_len = rr->length;
if (rl->md_ctx != NULL) {
const EVP_MD *tmpmd = EVP_MD_CTX_get0_md(rl->md_ctx);
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 0;
}
mac_size = (size_t)imac_size;
}
}
if (rl->use_etm && rl->md_ctx != NULL) {
unsigned char *mac;
if (rr->orig_len < mac_size) {
RLAYERfatal(rl, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_TOO_SHORT);
return 0;
}
rr->length -= mac_size;
mac = rr->data + rr->length;
i = rl->funcs->mac(rl, rr, md, 0 /* not send */);
if (i == 0 || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0) {
RLAYERfatal(rl, SSL_AD_BAD_RECORD_MAC,
SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
return 0;
}
/*
* We've handled the mac now - there is no MAC inside the encrypted
* record
*/
mac_size = 0;
}
/*
* Set a mark around the packet decryption attempt. This is DTLS, so
* bad packets are just ignored, and we don't want to leave stray
* errors in the queue from processing bogus junk that we ignored.
*/
ERR_set_mark();
enc_err = rl->funcs->cipher(rl, rr, 1, 0, &macbuf, mac_size);
/*-
* enc_err is:
* 0: if the record is publicly invalid, or an internal error, or AEAD
* decryption failed, or ETM decryption failed.
* 1: Success or MTE decryption failed (MAC will be randomised)
*/
if (enc_err == 0) {
ERR_pop_to_mark();
if (rl->alert != SSL_AD_NO_ALERT) {
/* RLAYERfatal() already called */
goto end;
}
/* For DTLS we simply ignore bad packets. */
rr->length = 0;
rl->packet_length = 0;
goto end;
}
ERR_clear_last_mark();
OSSL_TRACE_BEGIN(TLS) {
BIO_printf(trc_out, "dec %zd\n", rr->length);
BIO_dump_indent(trc_out, rr->data, rr->length, 4);
} OSSL_TRACE_END(TLS);
/* r->length is now the compressed data plus mac */
if (!rl->use_etm
&& (rl->enc_ctx != NULL)
&& (EVP_MD_CTX_get0_md(rl->md_ctx) != NULL)) {
/* rl->md_ctx != NULL => mac_size != -1 */
i = rl->funcs->mac(rl, rr, md, 0 /* not send */);
if (i == 0 || macbuf.mac == NULL
|| CRYPTO_memcmp(md, macbuf.mac, mac_size) != 0)
enc_err = 0;
if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size)
enc_err = 0;
}
if (enc_err == 0) {
/* decryption failed, silently discard message */
rr->length = 0;
rl->packet_length = 0;
goto end;
}
/* r->length is now just compressed */
if (rl->compctx != NULL) {
if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH) {
RLAYERfatal(rl, SSL_AD_RECORD_OVERFLOW,
SSL_R_COMPRESSED_LENGTH_TOO_LONG);
goto end;
}
if (!tls_do_uncompress(rl, rr)) {
RLAYERfatal(rl, SSL_AD_DECOMPRESSION_FAILURE, SSL_R_BAD_DECOMPRESSION);
goto end;
}
}
/*
* Check if the received packet overflows the current Max Fragment
* Length setting.
*/
if (rr->length > rl->max_frag_len) {
RLAYERfatal(rl, SSL_AD_RECORD_OVERFLOW, SSL_R_DATA_LENGTH_TOO_LONG);
goto end;
}
rr->off = 0;
/*-
* So at this point the following is true
* ssl->s3.rrec.type is the type of record
* ssl->s3.rrec.length == number of bytes in record
* ssl->s3.rrec.off == offset to first valid byte
* ssl->s3.rrec.data == where to take bytes from, increment
* after use :-).
*/
/* we have pulled in a full packet so zero things */
rl->packet_length = 0;
/* Mark receipt of record. */
dtls_record_bitmap_update(rl, bitmap);
ret = 1;
end:
if (macbuf.alloced)
OPENSSL_free(macbuf.mac);
return ret;
}
static int dtls_rlayer_buffer_record(OSSL_RECORD_LAYER *rl, record_pqueue *queue,
unsigned char *priority)
{
DTLS_RLAYER_RECORD_DATA *rdata;
pitem *item;
/* Limit the size of the queue to prevent DOS attacks */
if (pqueue_size(queue->q) >= 100)
return 0;
rdata = OPENSSL_malloc(sizeof(*rdata));
item = pitem_new(priority, rdata);
if (rdata == NULL || item == NULL) {
OPENSSL_free(rdata);
pitem_free(item);
RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return -1;
}
rdata->packet = rl->packet;
rdata->packet_length = rl->packet_length;
memcpy(&(rdata->rbuf), &rl->rbuf, sizeof(SSL3_BUFFER));
memcpy(&(rdata->rrec), &rl->rrec[0], sizeof(SSL3_RECORD));
item->data = rdata;
rl->packet = NULL;
rl->packet_length = 0;
memset(&rl->rbuf, 0, sizeof(SSL3_BUFFER));
memset(&rl->rrec[0], 0, sizeof(rl->rrec[0]));
if (!tls_setup_read_buffer(rl)) {
/* RLAYERfatal() already called */
OPENSSL_free(rdata->rbuf.buf);
OPENSSL_free(rdata);
pitem_free(item);
return -1;
}
if (pqueue_insert(queue->q, item) == NULL) {
/* Must be a duplicate so ignore it */
OPENSSL_free(rdata->rbuf.buf);
OPENSSL_free(rdata);
pitem_free(item);
}
return 1;
}
/* copy buffered record into OSSL_RECORD_LAYER structure */
static int dtls_copy_rlayer_record(OSSL_RECORD_LAYER *rl, pitem *item)
{
DTLS_RLAYER_RECORD_DATA *rdata;
rdata = (DTLS_RLAYER_RECORD_DATA *)item->data;
SSL3_BUFFER_release(&rl->rbuf);
rl->packet = rdata->packet;
rl->packet_length = rdata->packet_length;
memcpy(&rl->rbuf, &(rdata->rbuf), sizeof(SSL3_BUFFER));
memcpy(&rl->rrec[0], &(rdata->rrec), sizeof(SSL3_RECORD));
/* Set proper sequence number for mac calculation */
memcpy(&(rl->sequence[2]), &(rdata->packet[5]), 6);
return 1;
}
static int dtls_retrieve_rlayer_buffered_record(OSSL_RECORD_LAYER *rl,
record_pqueue *queue)
{
pitem *item;
item = pqueue_pop(queue->q);
if (item) {
dtls_copy_rlayer_record(rl, item);
OPENSSL_free(item->data);
pitem_free(item);
return 1;
}
return 0;
}
/*-
* Call this to get a new input record.
* It will return <= 0 if more data is needed, normally due to an error
* or non-blocking IO.
* When it finishes, one packet has been decoded and can be found in
* ssl->s3.rrec.type - is the type of record
* ssl->s3.rrec.data - data
* ssl->s3.rrec.length - number of bytes
*/
int dtls_get_more_records(OSSL_RECORD_LAYER *rl)
{
int ssl_major, ssl_minor;
int rret;
size_t more, n;
SSL3_RECORD *rr;
unsigned char *p = NULL;
unsigned short version;
DTLS_BITMAP *bitmap;
unsigned int is_next_epoch;
rl->num_recs = 0;
rl->curr_rec = 0;
rl->num_released = 0;
rr = rl->rrec;
if (rl->rbuf.buf == NULL) {
if (!tls_setup_read_buffer(rl)) {
/* RLAYERfatal() already called */
return OSSL_RECORD_RETURN_FATAL;
}
}
again:
/* if we're renegotiating, then there may be buffered records */
if (dtls_retrieve_rlayer_buffered_record(rl, &rl->processed_rcds)) {
rl->num_recs = 1;
return OSSL_RECORD_RETURN_SUCCESS;
}
/* get something from the wire */
/* check if we have the header */
if ((rl->rstate != SSL_ST_READ_BODY) ||
(rl->packet_length < DTLS1_RT_HEADER_LENGTH)) {
rret = rl->funcs->read_n(rl, DTLS1_RT_HEADER_LENGTH,
SSL3_BUFFER_get_len(&rl->rbuf), 0, 1, &n);
/* read timeout is handled by dtls1_read_bytes */
if (rret < OSSL_RECORD_RETURN_SUCCESS) {
/* RLAYERfatal() already called if appropriate */
return rret; /* error or non-blocking */
}
/* this packet contained a partial record, dump it */
if (rl->packet_length != DTLS1_RT_HEADER_LENGTH) {
rl->packet_length = 0;
goto again;
}
rl->rstate = SSL_ST_READ_BODY;
p = rl->packet;
if (rl->msg_callback != NULL)
rl->msg_callback(0, 0, SSL3_RT_HEADER, p, DTLS1_RT_HEADER_LENGTH,
rl->cbarg);
/* Pull apart the header into the DTLS1_RECORD */
rr->type = *(p++);
ssl_major = *(p++);
ssl_minor = *(p++);
version = (ssl_major << 8) | ssl_minor;
/* sequence number is 64 bits, with top 2 bytes = epoch */
n2s(p, rr->epoch);
memcpy(&(rl->sequence[2]), p, 6);
p += 6;
n2s(p, rr->length);
/*
* Lets check the version. We tolerate alerts that don't have the exact
* version number (e.g. because of protocol version errors)
*/
if (!rl->is_first_record && rr->type != SSL3_RT_ALERT) {
if (version != rl->version) {
/* unexpected version, silently discard */
rr->length = 0;
rl->packet_length = 0;
goto again;
}
}
if (ssl_major !=
(rl->version == DTLS_ANY_VERSION ? DTLS1_VERSION_MAJOR
: rl->version >> 8)) {
/* wrong version, silently discard record */
rr->length = 0;
rl->packet_length = 0;
goto again;
}
if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
/* record too long, silently discard it */
rr->length = 0;
rl->packet_length = 0;
goto again;
}
/*
* If received packet overflows maximum possible fragment length then
* silently discard it
*/
if (rr->length > rl->max_frag_len + SSL3_RT_MAX_ENCRYPTED_OVERHEAD) {
/* record too long, silently discard it */
rr->length = 0;
rl->packet_length = 0;
goto again;
}
/* now rl->rstate == SSL_ST_READ_BODY */
}
/* rl->rstate == SSL_ST_READ_BODY, get and decode the data */
if (rr->length > rl->packet_length - DTLS1_RT_HEADER_LENGTH) {
/* now rl->packet_length == DTLS1_RT_HEADER_LENGTH */
more = rr->length;
rret = rl->funcs->read_n(rl, more, more, 1, 1, &n);
/* this packet contained a partial record, dump it */
if (rret < OSSL_RECORD_RETURN_SUCCESS || n != more) {
if (rl->alert != SSL_AD_NO_ALERT) {
/* read_n() called RLAYERfatal() */
return OSSL_RECORD_RETURN_FATAL;
}
rr->length = 0;
rl->packet_length = 0;
goto again;
}
/*
* now n == rr->length,
* and rl->packet_length == DTLS1_RT_HEADER_LENGTH + rr->length
*/
}
/* set state for later operations */
rl->rstate = SSL_ST_READ_HEADER;
/* match epochs. NULL means the packet is dropped on the floor */
bitmap = dtls_get_bitmap(rl, rr, &is_next_epoch);
if (bitmap == NULL) {
rr->length = 0;
rl->packet_length = 0; /* dump this record */
goto again; /* get another record */
}
#ifndef OPENSSL_NO_SCTP
/* Only do replay check if no SCTP bio */
if (!BIO_dgram_is_sctp(rl->bio)) {
#endif
/* Check whether this is a repeat, or aged record. */
if (!dtls_record_replay_check(rl, bitmap)) {
rr->length = 0;
rl->packet_length = 0; /* dump this record */
goto again; /* get another record */
}
#ifndef OPENSSL_NO_SCTP
}
#endif
/* just read a 0 length packet */
if (rr->length == 0)
goto again;
/*
* If this record is from the next epoch (either HM or ALERT), and a
* handshake is currently in progress, buffer it since it cannot be
* processed at this time.
*/
if (is_next_epoch) {
if (rl->in_init) {
if (dtls_rlayer_buffer_record(rl, &(rl->unprocessed_rcds),
rr->seq_num) < 0) {
/* RLAYERfatal() already called */
return OSSL_RECORD_RETURN_FATAL;
}
}
rr->length = 0;
rl->packet_length = 0;
goto again;
}
if (!dtls_process_record(rl, bitmap)) {
if (rl->alert != SSL_AD_NO_ALERT) {
/* dtls_process_record() called RLAYERfatal */
return OSSL_RECORD_RETURN_FATAL;
}
rr->length = 0;
rl->packet_length = 0; /* dump this record */
goto again; /* get another record */
}
rl->num_recs = 1;
return OSSL_RECORD_RETURN_SUCCESS;
}
static int dtls_free(OSSL_RECORD_LAYER *rl)
{
SSL3_BUFFER *rbuf;
size_t left, written;
pitem *item;
DTLS_RLAYER_RECORD_DATA *rdata;
int ret = 1;
rbuf = &rl->rbuf;
left = rbuf->left;
if (left > 0) {
/*
* This record layer is closing but we still have data left in our
* buffer. It must be destined for the next epoch - so push it there.
*/
ret = BIO_write_ex(rl->next, rbuf->buf + rbuf->offset, left, &written);
rbuf->left = 0;
}
if (rl->unprocessed_rcds.q != NULL) {
while ((item = pqueue_pop(rl->unprocessed_rcds.q)) != NULL) {
rdata = (DTLS_RLAYER_RECORD_DATA *)item->data;
/* Push to the next record layer */
ret &= BIO_write_ex(rl->next, rdata->packet, rdata->packet_length,
&written);
OPENSSL_free(rdata->rbuf.buf);
OPENSSL_free(item->data);
pitem_free(item);
}
pqueue_free(rl->unprocessed_rcds.q);
}
if (rl->processed_rcds.q != NULL) {
while ((item = pqueue_pop(rl->processed_rcds.q)) != NULL) {
rdata = (DTLS_RLAYER_RECORD_DATA *)item->data;
OPENSSL_free(rdata->rbuf.buf);
OPENSSL_free(item->data);
pitem_free(item);
}
pqueue_free(rl->processed_rcds.q);
}
return tls_free(rl) && ret;
}
static int
dtls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
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, COMP_METHOD *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,
transport, next, local, peer, settings,
options, fns, cbarg, retrl);
if (ret != OSSL_RECORD_RETURN_SUCCESS)
return ret;
(*retrl)->unprocessed_rcds.q = pqueue_new();
(*retrl)->processed_rcds.q = pqueue_new();
if ((*retrl)->unprocessed_rcds.q == NULL
|| (*retrl)->processed_rcds.q == NULL) {
dtls_free(*retrl);
*retrl = NULL;
ERR_raise(ERR_LIB_SSL, ERR_R_SSL_LIB);
return OSSL_RECORD_RETURN_FATAL;
}
(*retrl)->unprocessed_rcds.epoch = epoch + 1;
(*retrl)->processed_rcds.epoch = epoch;
(*retrl)->isdtls = 1;
(*retrl)->epoch = epoch;
(*retrl)->in_init = 1;
switch (vers) {
case DTLS_ANY_VERSION:
(*retrl)->funcs = &dtls_any_funcs;
break;
case DTLS1_2_VERSION:
case DTLS1_VERSION:
case DTLS1_BAD_VER:
(*retrl)->funcs = &dtls_1_funcs;
break;
default:
/* Should not happen */
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
ret = OSSL_RECORD_RETURN_FATAL;
goto err;
}
ret = (*retrl)->funcs->set_crypto_state(*retrl, level, key, keylen, iv,
ivlen, mackey, mackeylen, ciph,
taglen, mactype, md, comp);
err:
if (ret != OSSL_RECORD_RETURN_SUCCESS) {
OPENSSL_free(*retrl);
*retrl = NULL;
}
return ret;
}
int dtls_prepare_record_header(OSSL_RECORD_LAYER *rl,
WPACKET *thispkt,
OSSL_RECORD_TEMPLATE *templ,
unsigned int rectype,
unsigned char **recdata)
{
size_t maxcomplen;
*recdata = NULL;
maxcomplen = templ->buflen;
if (rl->compctx != NULL)
maxcomplen += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
if (!WPACKET_put_bytes_u8(thispkt, rectype)
|| !WPACKET_put_bytes_u16(thispkt, templ->version)
|| !WPACKET_put_bytes_u16(thispkt, rl->epoch)
|| !WPACKET_memcpy(thispkt, &(rl->sequence[2]), 6)
|| !WPACKET_start_sub_packet_u16(thispkt)
|| (rl->eivlen > 0
&& !WPACKET_allocate_bytes(thispkt, rl->eivlen, NULL))
|| (maxcomplen > 0
&& !WPACKET_reserve_bytes(thispkt, maxcomplen,
recdata))) {
RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
return 0;
}
return 1;
}
int dtls_post_encryption_processing(OSSL_RECORD_LAYER *rl,
size_t mac_size,
OSSL_RECORD_TEMPLATE *thistempl,
WPACKET *thispkt,
SSL3_RECORD *thiswr)
{
if (!tls_post_encryption_processing_default(rl, mac_size, thistempl,
thispkt, thiswr)) {
/* RLAYERfatal() already called */
return 0;
}
return tls_increment_sequence_ctr(rl);
}
static size_t dtls_get_max_record_overhead(OSSL_RECORD_LAYER *rl)
{
size_t blocksize = 0;
if (rl->enc_ctx != NULL &&
(EVP_CIPHER_CTX_get_mode(rl->enc_ctx) == EVP_CIPH_CBC_MODE))
blocksize = EVP_CIPHER_CTX_get_block_size(rl->enc_ctx);
/*
* If we have a cipher in place then the tag is mandatory. If the cipher is
* CBC mode then an explicit IV is also mandatory. If we know the digest,
* then we check it is consistent with the taglen. In the case of stitched
* ciphers or AEAD ciphers we don't now the digest (or there isn't one) so
* we just trust that the taglen is correct.
*/
assert(rl->enc_ctx == NULL || ((blocksize == 0 || rl->eivlen > 0)
&& rl->taglen > 0));
assert(rl->md == NULL || (int)rl->taglen == EVP_MD_size(rl->md));
/*
* Record overhead consists of the record header, the explicit IV, any
* expansion due to cbc padding, and the mac/tag len. There could be
* further expansion due to compression - but we don't know what this will
* be without knowing the length of the data. However when this function is
* called we don't know what the length will be yet - so this is a catch-22.
* We *could* use SSL_3_RT_MAX_COMPRESSED_OVERHEAD which is an upper limit
* for the maximum record size. But this value is larger than our fallback
* MTU size - so isn't very helpful. We just ignore potential expansion
* due to compression.
*/
return DTLS1_RT_HEADER_LENGTH + rl->eivlen + blocksize + rl->taglen;
}
const OSSL_RECORD_METHOD ossl_dtls_record_method = {
dtls_new_record_layer,
dtls_free,
tls_reset,
tls_unprocessed_read_pending,
tls_processed_read_pending,
tls_app_data_pending,
tls_get_max_records,
tls_write_records,
tls_retry_write_records,
tls_read_record,
tls_release_record,
tls_get_alert_code,
tls_set1_bio,
tls_set_protocol_version,
NULL,
tls_set_first_handshake,
tls_set_max_pipelines,
dtls_set_in_init,
tls_get_state,
tls_set_options,
tls_get_compression,
tls_set_max_frag_len,
dtls_get_max_record_overhead,
tls_increment_sequence_ctr,
tls_alloc_buffers,
tls_free_buffers
};