2022-06-02 23:29:04 +08:00
|
|
|
/*
|
|
|
|
* 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 "../../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;
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
static int dtls1_record_replay_check(OSSL_RECORD_LAYER *rl, DTLS1_BITMAP *bitmap)
|
2022-06-02 23:29:04 +08:00
|
|
|
{
|
|
|
|
int cmp;
|
|
|
|
unsigned int shift;
|
2022-06-08 21:52:44 +08:00
|
|
|
const unsigned char *seq = rl->sequence;
|
2022-06-02 23:29:04 +08:00
|
|
|
|
|
|
|
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 & (1UL << shift))
|
|
|
|
return 0; /* record previously received */
|
|
|
|
|
|
|
|
SSL3_RECORD_set_seq_num(&rl->rrec[0], seq);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
static void dtls1_record_bitmap_update(OSSL_RECORD_LAYER *rl,
|
|
|
|
DTLS1_BITMAP *bitmap)
|
2022-06-02 23:29:04 +08:00
|
|
|
{
|
|
|
|
int cmp;
|
|
|
|
unsigned int shift;
|
2022-06-08 21:52:44 +08:00
|
|
|
const unsigned char *seq = rl->sequence;
|
2022-06-02 23:29:04 +08:00
|
|
|
|
|
|
|
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 |= 1UL << shift;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
static DTLS1_BITMAP *dtls1_get_bitmap(OSSL_RECORD_LAYER *rl, SSL3_RECORD *rr,
|
2022-06-02 23:29:04 +08:00
|
|
|
unsigned int *is_next_epoch)
|
|
|
|
{
|
2022-06-08 21:52:44 +08:00
|
|
|
SSL_CONNECTION *s = (SSL_CONNECTION *)rl->cbarg;
|
|
|
|
|
2022-06-02 23:29:04 +08:00
|
|
|
*is_next_epoch = 0;
|
|
|
|
|
|
|
|
/* In current epoch, accept HM, CCS, DATA, & ALERT */
|
2022-06-08 21:52:44 +08:00
|
|
|
if (rr->epoch == rl->epoch)
|
2022-06-02 23:29:04 +08:00
|
|
|
return &s->rlayer.d->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
|
|
|
|
*/
|
2022-06-08 21:52:44 +08:00
|
|
|
else if (rr->epoch == (unsigned long)(rl->epoch + 1) &&
|
|
|
|
rl->unprocessed_rcds.epoch != rl->epoch &&
|
2022-06-02 23:29:04 +08:00
|
|
|
(rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ALERT)) {
|
|
|
|
*is_next_epoch = 1;
|
|
|
|
return &s->rlayer.d->next_bitmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
static int dtls1_process_record(OSSL_RECORD_LAYER *rl, DTLS1_BITMAP *bitmap)
|
2022-06-02 23:29:04 +08:00
|
|
|
{
|
|
|
|
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];
|
|
|
|
|
|
|
|
/*
|
2022-06-08 21:52:44 +08:00
|
|
|
* At this point, rl->packet_length == SSL3_RT_HEADER_LNGTH + rr->length,
|
|
|
|
* and we have that many bytes in rl->packet
|
2022-06-02 23:29:04 +08:00
|
|
|
*/
|
2022-06-08 21:52:44 +08:00
|
|
|
rr->input = &(rl->packet[DTLS1_RT_HEADER_LENGTH]);
|
2022-06-02 23:29:04 +08:00
|
|
|
|
|
|
|
/*
|
2022-06-08 21:52:44 +08:00
|
|
|
* ok, we can now read from 'rl->packet' data into 'rr'. rr->input
|
2022-06-02 23:29:04 +08:00
|
|
|
* 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) {
|
2022-06-08 21:52:44 +08:00
|
|
|
RLAYERfatal(rl, SSL_AD_RECORD_OVERFLOW, SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
|
2022-06-02 23:29:04 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* decrypt in place in 'rr->input' */
|
|
|
|
rr->data = rr->input;
|
|
|
|
rr->orig_len = rr->length;
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
if (rl->md_ctx != NULL) {
|
|
|
|
const EVP_MD *tmpmd = EVP_MD_CTX_get0_md(rl->md_ctx);
|
2022-06-02 23:29:04 +08:00
|
|
|
|
|
|
|
if (tmpmd != NULL) {
|
|
|
|
imac_size = EVP_MD_get_size(tmpmd);
|
|
|
|
if (!ossl_assert(imac_size >= 0 && imac_size <= EVP_MAX_MD_SIZE)) {
|
2022-06-08 21:52:44 +08:00
|
|
|
RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
|
2022-06-02 23:29:04 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
mac_size = (size_t)imac_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
if (rl->use_etm && rl->md_ctx) {
|
2022-06-02 23:29:04 +08:00
|
|
|
unsigned char *mac;
|
|
|
|
|
|
|
|
if (rr->orig_len < mac_size) {
|
2022-06-08 21:52:44 +08:00
|
|
|
RLAYERfatal(rl, SSL_AD_DECODE_ERROR, SSL_R_LENGTH_TOO_SHORT);
|
2022-06-02 23:29:04 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
rr->length -= mac_size;
|
|
|
|
mac = rr->data + rr->length;
|
2022-06-08 21:52:44 +08:00
|
|
|
i = rl->funcs->mac(rl, rr, md, 0 /* not send */);
|
2022-06-02 23:29:04 +08:00
|
|
|
if (i == 0 || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0) {
|
2022-06-08 21:52:44 +08:00
|
|
|
RLAYERfatal(rl, SSL_AD_BAD_RECORD_MAC,
|
|
|
|
SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
|
2022-06-02 23:29:04 +08:00
|
|
|
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();
|
2022-06-08 21:52:44 +08:00
|
|
|
enc_err = rl->funcs->cipher(rl, rr, 1, 0, &macbuf, mac_size);
|
2022-06-02 23:29:04 +08:00
|
|
|
|
|
|
|
/*-
|
|
|
|
* 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();
|
2022-06-08 21:52:44 +08:00
|
|
|
if (rl->alert != 0) {
|
2022-06-02 23:29:04 +08:00
|
|
|
/* SSLfatal() got called */
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
/* For DTLS we simply ignore bad packets. */
|
|
|
|
rr->length = 0;
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet_length = 0;
|
2022-06-02 23:29:04 +08:00
|
|
|
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 */
|
2022-06-08 21:52:44 +08:00
|
|
|
if (!rl->use_etm
|
|
|
|
&& (rl->enc_ctx != NULL)
|
|
|
|
&& (EVP_MD_CTX_get0_md(rl->md_ctx) != NULL)) {
|
|
|
|
/* rl->md_ctx != NULL => mac_size != -1 */
|
2022-06-02 23:29:04 +08:00
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
i = rl->funcs->mac(rl, rr, md, 0 /* not send */ );
|
2022-06-02 23:29:04 +08:00
|
|
|
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;
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet_length = 0;
|
2022-06-02 23:29:04 +08:00
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* r->length is now just compressed */
|
2022-06-08 21:52:44 +08:00
|
|
|
if (rl->expand != NULL) {
|
2022-06-02 23:29:04 +08:00
|
|
|
if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH) {
|
2022-06-08 21:52:44 +08:00
|
|
|
RLAYERfatal(rl, SSL_AD_RECORD_OVERFLOW,
|
|
|
|
SSL_R_COMPRESSED_LENGTH_TOO_LONG);
|
2022-06-02 23:29:04 +08:00
|
|
|
goto end;
|
|
|
|
}
|
2022-06-08 21:52:44 +08:00
|
|
|
if (!tls_do_uncompress(rl, rr)) {
|
|
|
|
RLAYERfatal(rl, SSL_AD_DECOMPRESSION_FAILURE, SSL_R_BAD_DECOMPRESSION);
|
2022-06-02 23:29:04 +08:00
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
/*
|
|
|
|
* Check if the received packet overflows the current Max Fragment
|
|
|
|
* Length setting.
|
|
|
|
*/
|
|
|
|
if (rl->max_frag_len > 0 && rr->length > rl->max_frag_len) {
|
|
|
|
RLAYERfatal(rl, SSL_AD_RECORD_OVERFLOW, SSL_R_DATA_LENGTH_TOO_LONG);
|
2022-06-02 23:29:04 +08:00
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
|
2022-06-02 23:29:04 +08:00
|
|
|
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 */
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet_length = 0;
|
2022-06-02 23:29:04 +08:00
|
|
|
|
|
|
|
/* Mark receipt of record. */
|
2022-06-08 21:52:44 +08:00
|
|
|
dtls1_record_bitmap_update(rl, bitmap);
|
2022-06-02 23:29:04 +08:00
|
|
|
|
|
|
|
ret = 1;
|
|
|
|
end:
|
|
|
|
if (macbuf.alloced)
|
|
|
|
OPENSSL_free(macbuf.mac);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
static int dtls_rlayer_buffer_record(OSSL_RECORD_LAYER *rl, record_pqueue *queue,
|
2022-06-02 23:29:04 +08:00
|
|
|
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);
|
2022-06-08 21:52:44 +08:00
|
|
|
RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
2022-06-02 23:29:04 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
rdata->packet = rl->packet;
|
|
|
|
rdata->packet_length = rl->packet_length;
|
|
|
|
memcpy(&(rdata->rbuf), &rl->rbuf, sizeof(SSL3_BUFFER));
|
2022-06-02 23:29:04 +08:00
|
|
|
memcpy(&(rdata->rrec), &rl->rrec[0], sizeof(SSL3_RECORD));
|
|
|
|
|
|
|
|
item->data = rdata;
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet = NULL;
|
|
|
|
rl->packet_length = 0;
|
|
|
|
memset(&rl->rbuf, 0, sizeof(SSL3_BUFFER));
|
2022-06-02 23:29:04 +08:00
|
|
|
memset(&rl->rrec[0], 0, sizeof(rl->rrec[0]));
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
|
|
|
|
if (!rlayer_setup_read_buffer(rl)) {
|
2022-06-02 23:29:04 +08:00
|
|
|
/* SSLfatal() 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 SSL 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;
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
SSL3_BUFFER_release(&rl->rbuf);
|
2022-06-02 23:29:04 +08:00
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet = rdata->packet;
|
|
|
|
rl->packet_length = rdata->packet_length;
|
|
|
|
memcpy(&rl->rbuf, &(rdata->rbuf), sizeof(SSL3_BUFFER));
|
2022-06-02 23:29:04 +08:00
|
|
|
memcpy(&rl->rrec[0], &(rdata->rrec), sizeof(SSL3_RECORD));
|
|
|
|
|
|
|
|
/* Set proper sequence number for mac calculation */
|
2022-06-08 21:52:44 +08:00
|
|
|
memcpy(&(rl->sequence[2]), &(rdata->packet[5]), 6);
|
2022-06-02 23:29:04 +08:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
static int dtls_process_rlayer_buffered_records(OSSL_RECORD_LAYER *rl)
|
2022-06-02 23:29:04 +08:00
|
|
|
{
|
|
|
|
pitem *item;
|
|
|
|
SSL3_BUFFER *rb;
|
|
|
|
SSL3_RECORD *rr;
|
|
|
|
DTLS1_BITMAP *bitmap;
|
|
|
|
unsigned int is_next_epoch;
|
|
|
|
int replayok = 1;
|
|
|
|
|
|
|
|
item = pqueue_peek(rl->unprocessed_rcds.q);
|
|
|
|
if (item) {
|
|
|
|
/* Check if epoch is current. */
|
2022-06-08 21:52:44 +08:00
|
|
|
if (rl->unprocessed_rcds.epoch != rl->epoch)
|
2022-06-02 23:29:04 +08:00
|
|
|
return 1; /* Nothing to do. */
|
|
|
|
|
|
|
|
rr = rl->rrec;
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
rb = &rl->rbuf;
|
2022-06-02 23:29:04 +08:00
|
|
|
|
|
|
|
if (SSL3_BUFFER_get_left(rb) > 0) {
|
|
|
|
/*
|
|
|
|
* We've still got data from the current packet to read. There could
|
|
|
|
* be a record from the new epoch in it - so don't overwrite it
|
|
|
|
* with the unprocessed records yet (we'll do it when we've
|
|
|
|
* finished reading the current packet).
|
|
|
|
*/
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process all the records. */
|
|
|
|
while (pqueue_peek(rl->unprocessed_rcds.q)) {
|
|
|
|
dtls_retrieve_rlayer_buffered_record(rl, &(rl->unprocessed_rcds));
|
2022-06-08 21:52:44 +08:00
|
|
|
bitmap = dtls1_get_bitmap(rl, rr, &is_next_epoch);
|
2022-06-02 23:29:04 +08:00
|
|
|
if (bitmap == NULL) {
|
|
|
|
/*
|
|
|
|
* Should not happen. This will only ever be NULL when the
|
|
|
|
* current record is from a different epoch. But that cannot
|
|
|
|
* be the case because we already checked the epoch above
|
|
|
|
*/
|
2022-06-08 21:52:44 +08:00
|
|
|
RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
2022-06-02 23:29:04 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#ifndef OPENSSL_NO_SCTP
|
|
|
|
/* Only do replay check if no SCTP bio */
|
2022-06-08 21:52:44 +08:00
|
|
|
if (!BIO_dgram_is_sctp(rl->bio))
|
2022-06-02 23:29:04 +08:00
|
|
|
#endif
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Check whether this is a repeat, or aged record. We did this
|
|
|
|
* check once already when we first received the record - but
|
|
|
|
* we might have updated the window since then due to
|
|
|
|
* records we subsequently processed.
|
|
|
|
*/
|
2022-06-08 21:52:44 +08:00
|
|
|
replayok = dtls1_record_replay_check(rl, bitmap);
|
2022-06-02 23:29:04 +08:00
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
if (!replayok || !dtls1_process_record(rl, bitmap)) {
|
|
|
|
if (rl->alert != 0) {
|
|
|
|
/* dtls1_process_record called RLAYERfatal() */
|
2022-06-02 23:29:04 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* dump this record */
|
|
|
|
rr->length = 0;
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet_length = 0;
|
2022-06-02 23:29:04 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
if (dtls_rlayer_buffer_record(rl, &(rl->processed_rcds),
|
2022-06-02 23:29:04 +08:00
|
|
|
SSL3_RECORD_get_seq_num(&rl->rrec[0])) < 0) {
|
|
|
|
/* SSLfatal() already called */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sync epoch numbers once all the unprocessed records have been
|
|
|
|
* processed
|
|
|
|
*/
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->processed_rcds.epoch = rl->epoch;
|
|
|
|
rl->unprocessed_rcds.epoch = rl->epoch + 1;
|
2022-06-02 23:29:04 +08:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
/* TODO(RECLAYER): FIXME. This is called directly from d1_lib.c. It should not be */
|
|
|
|
int dtls_buffer_listen_record(OSSL_RECORD_LAYER *rl, size_t len,
|
|
|
|
unsigned char *seq, size_t off)
|
2022-06-02 23:29:04 +08:00
|
|
|
{
|
|
|
|
SSL3_RECORD *rr;
|
|
|
|
|
|
|
|
rr = &rl->rrec[0];
|
|
|
|
memset(rr, 0, sizeof(SSL3_RECORD));
|
|
|
|
|
|
|
|
rr->length = len;
|
|
|
|
rr->type = SSL3_RT_HANDSHAKE;
|
|
|
|
memcpy(rr->seq_num, seq, sizeof(rr->seq_num));
|
|
|
|
rr->off = off;
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet = rl->rbuf.buf;
|
|
|
|
rl->packet_length = DTLS1_RT_HEADER_LENGTH + len;
|
|
|
|
rr->data = rl->packet + DTLS1_RT_HEADER_LENGTH;
|
2022-06-02 23:29:04 +08:00
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
if (dtls_rlayer_buffer_record(rl, &(rl->processed_rcds),
|
2022-06-02 23:29:04 +08:00
|
|
|
SSL3_RECORD_get_seq_num(rr)) <= 0) {
|
|
|
|
/* SSLfatal() already called */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
/* used only by dtls1_read_bytes */
|
2022-06-08 21:52:44 +08:00
|
|
|
int dtls_get_more_records(OSSL_RECORD_LAYER *rl)
|
2022-06-02 23:29:04 +08:00
|
|
|
{
|
|
|
|
int ssl_major, ssl_minor;
|
|
|
|
int rret;
|
|
|
|
size_t more, n;
|
|
|
|
SSL3_RECORD *rr;
|
|
|
|
unsigned char *p = NULL;
|
|
|
|
unsigned short version;
|
|
|
|
DTLS1_BITMAP *bitmap;
|
|
|
|
unsigned int is_next_epoch;
|
|
|
|
/* TODO(RECLAYER): Remove me */
|
|
|
|
SSL_CONNECTION *s = (SSL_CONNECTION *)rl->cbarg;
|
|
|
|
SSL *ssl = SSL_CONNECTION_GET_SSL(s);
|
|
|
|
|
|
|
|
rl->num_recs = 0;
|
|
|
|
rl->curr_rec = 0;
|
|
|
|
rl->num_released = 0;
|
|
|
|
|
|
|
|
rr = rl->rrec;
|
|
|
|
|
|
|
|
again:
|
|
|
|
/*
|
|
|
|
* The epoch may have changed. If so, process all the pending records.
|
|
|
|
* This is a non-blocking operation.
|
|
|
|
*/
|
2022-06-08 21:52:44 +08:00
|
|
|
if (!dtls_process_rlayer_buffered_records(rl)) {
|
2022-06-02 23:29:04 +08:00
|
|
|
/* SSLfatal() already called */
|
|
|
|
return OSSL_RECORD_RETURN_FATAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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 */
|
2022-06-08 21:52:44 +08:00
|
|
|
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);
|
2022-06-02 23:29:04 +08:00
|
|
|
/* read timeout is handled by dtls1_read_bytes */
|
|
|
|
if (rret < OSSL_RECORD_RETURN_SUCCESS) {
|
|
|
|
/* SSLfatal() already called if appropriate */
|
|
|
|
return rret; /* error or non-blocking */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this packet contained a partial record, dump it */
|
2022-06-08 21:52:44 +08:00
|
|
|
if (rl->packet_length != DTLS1_RT_HEADER_LENGTH) {
|
|
|
|
rl->packet_length = 0;
|
2022-06-02 23:29:04 +08:00
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->rstate = SSL_ST_READ_BODY;
|
2022-06-02 23:29:04 +08:00
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
p = rl->packet;
|
2022-06-02 23:29:04 +08:00
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->msg_callback(0, 0, SSL3_RT_HEADER, p, DTLS1_RT_HEADER_LENGTH,
|
|
|
|
rl->cbarg);
|
2022-06-02 23:29:04 +08:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
memcpy(&(rl->sequence[2]), p, 6);
|
2022-06-02 23:29:04 +08:00
|
|
|
p += 6;
|
|
|
|
|
|
|
|
n2s(p, rr->length);
|
|
|
|
rr->read = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Lets check the version. We tolerate alerts that don't have the exact
|
|
|
|
* version number (e.g. because of protocol version errors)
|
|
|
|
*/
|
2022-06-08 21:52:44 +08:00
|
|
|
if (!rl->is_first_record && rr->type != SSL3_RT_ALERT) {
|
|
|
|
if (version != rl->version) {
|
2022-06-02 23:29:04 +08:00
|
|
|
/* unexpected version, silently discard */
|
|
|
|
rr->length = 0;
|
|
|
|
rr->read = 1;
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet_length = 0;
|
2022-06-02 23:29:04 +08:00
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
|
|
|
|
if (ssl_major !=
|
|
|
|
(rl->version == DTLS_ANY_VERSION ? DTLS1_VERSION_MAJOR
|
|
|
|
: rl->version >> 8)) {
|
2022-06-02 23:29:04 +08:00
|
|
|
/* wrong version, silently discard record */
|
|
|
|
rr->length = 0;
|
|
|
|
rr->read = 1;
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet_length = 0;
|
2022-06-02 23:29:04 +08:00
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) {
|
|
|
|
/* record too long, silently discard it */
|
|
|
|
rr->length = 0;
|
|
|
|
rr->read = 1;
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet_length = 0;
|
2022-06-02 23:29:04 +08:00
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If received packet overflows maximum possible fragment length then
|
|
|
|
* silently discard it
|
|
|
|
*/
|
|
|
|
if (rl->max_frag_len > 0
|
|
|
|
&& rr->length > rl->max_frag_len + SSL3_RT_MAX_ENCRYPTED_OVERHEAD) {
|
2022-06-02 23:29:04 +08:00
|
|
|
/* record too long, silently discard it */
|
|
|
|
rr->length = 0;
|
|
|
|
rr->read = 1;
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet_length = 0;
|
2022-06-02 23:29:04 +08:00
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
/* now rl->rstate == SSL_ST_READ_BODY */
|
2022-06-02 23:29:04 +08:00
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
/* rl->rstate == SSL_ST_READ_BODY, get and decode the data */
|
2022-06-02 23:29:04 +08:00
|
|
|
|
|
|
|
if (rr->length >
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet_length - DTLS1_RT_HEADER_LENGTH) {
|
|
|
|
/* now rl->packet_length == DTLS1_RT_HEADER_LENGTH */
|
2022-06-02 23:29:04 +08:00
|
|
|
more = rr->length;
|
2022-06-08 21:52:44 +08:00
|
|
|
rret = rl->funcs->read_n(rl, more, more, 1, 1, &n);
|
2022-06-02 23:29:04 +08:00
|
|
|
/* this packet contained a partial record, dump it */
|
|
|
|
if (rret < OSSL_RECORD_RETURN_SUCCESS || n != more) {
|
2022-06-08 21:52:44 +08:00
|
|
|
if (rl->alert != 0) {
|
|
|
|
/* read_n() called RLAYERfatal() */
|
2022-06-02 23:29:04 +08:00
|
|
|
return OSSL_RECORD_RETURN_FATAL;
|
|
|
|
}
|
|
|
|
rr->length = 0;
|
|
|
|
rr->read = 1;
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet_length = 0;
|
2022-06-02 23:29:04 +08:00
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2022-06-08 21:52:44 +08:00
|
|
|
* now n == rr->length,
|
|
|
|
* and rl->packet_length == DTLS1_RT_HEADER_LENGTH + rr->length
|
2022-06-02 23:29:04 +08:00
|
|
|
*/
|
|
|
|
}
|
|
|
|
/* set state for later operations */
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->rstate = SSL_ST_READ_HEADER;
|
2022-06-02 23:29:04 +08:00
|
|
|
|
|
|
|
/* match epochs. NULL means the packet is dropped on the floor */
|
2022-06-08 21:52:44 +08:00
|
|
|
bitmap = dtls1_get_bitmap(rl, rr, &is_next_epoch);
|
2022-06-02 23:29:04 +08:00
|
|
|
if (bitmap == NULL) {
|
|
|
|
rr->length = 0;
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet_length = 0; /* dump this record */
|
2022-06-02 23:29:04 +08:00
|
|
|
goto again; /* get another record */
|
|
|
|
}
|
|
|
|
#ifndef OPENSSL_NO_SCTP
|
|
|
|
/* Only do replay check if no SCTP bio */
|
2022-06-08 21:52:44 +08:00
|
|
|
if (!BIO_dgram_is_sctp(rl->bio)) {
|
2022-06-02 23:29:04 +08:00
|
|
|
#endif
|
|
|
|
/* Check whether this is a repeat, or aged record. */
|
2022-06-08 21:52:44 +08:00
|
|
|
if (!dtls1_record_replay_check(rl, bitmap)) {
|
2022-06-02 23:29:04 +08:00
|
|
|
rr->length = 0;
|
|
|
|
rr->read = 1;
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet_length = 0; /* dump this record */
|
2022-06-02 23:29:04 +08:00
|
|
|
goto again; /* get another record */
|
|
|
|
}
|
|
|
|
#ifndef OPENSSL_NO_SCTP
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* just read a 0 length packet */
|
|
|
|
if (rr->length == 0) {
|
|
|
|
rr->read = 1;
|
|
|
|
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 ((SSL_in_init(ssl) || ossl_statem_get_in_handshake(s))) {
|
2022-06-08 21:52:44 +08:00
|
|
|
if (dtls_rlayer_buffer_record(rl,
|
2022-06-02 23:29:04 +08:00
|
|
|
&(rl->unprocessed_rcds),
|
|
|
|
rr->seq_num) < 0) {
|
|
|
|
/* SSLfatal() already called */
|
|
|
|
return OSSL_RECORD_RETURN_FATAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rr->length = 0;
|
|
|
|
rr->read = 1;
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet_length = 0;
|
2022-06-02 23:29:04 +08:00
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
if (!dtls1_process_record(rl, bitmap)) {
|
|
|
|
if (rl->alert != 0) {
|
|
|
|
/* dtls1_process_record() called RLAYERfatal */
|
2022-06-02 23:29:04 +08:00
|
|
|
return OSSL_RECORD_RETURN_FATAL;
|
|
|
|
}
|
|
|
|
rr->length = 0;
|
|
|
|
rr->read = 1;
|
2022-06-08 21:52:44 +08:00
|
|
|
rl->packet_length = 0; /* dump this record */
|
2022-06-02 23:29:04 +08:00
|
|
|
goto again; /* get another record */
|
|
|
|
}
|
|
|
|
|
|
|
|
rl->num_recs = 1;
|
|
|
|
return OSSL_RECORD_RETURN_SUCCESS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dtls_free(OSSL_RECORD_LAYER *rl)
|
|
|
|
{
|
|
|
|
pitem *item;
|
|
|
|
DTLS_RLAYER_RECORD_DATA *rdata;
|
|
|
|
|
|
|
|
if (rl->unprocessed_rcds.q == NULL) {
|
|
|
|
while ((item = pqueue_pop(rl->unprocessed_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->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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
dtls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
|
2022-06-08 21:52:44 +08:00
|
|
|
int role, int direction, int level, unsigned int epoch,
|
|
|
|
unsigned char *key, size_t keylen, unsigned char *iv,
|
|
|
|
size_t ivlen, unsigned char *mackey, size_t mackeylen,
|
2022-06-02 23:29:04 +08:00
|
|
|
const EVP_CIPHER *ciph, size_t taglen,
|
|
|
|
/* TODO(RECLAYER): This probably should not be an int */
|
|
|
|
int mactype,
|
|
|
|
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,
|
|
|
|
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;
|
|
|
|
RLAYERfatal(*retrl, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
|
|
|
|
return OSSL_RECORD_RETURN_FATAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*retrl)->isdtls = 1;
|
2022-06-08 21:52:44 +08:00
|
|
|
(*retrl)->epoch = epoch;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2022-06-02 23:29:04 +08:00
|
|
|
|
2022-06-08 21:52:44 +08:00
|
|
|
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;
|
2022-06-02 23:29:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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_write_pending,
|
|
|
|
tls_get_max_record_len,
|
|
|
|
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,
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO(RECLAYER): Remove these. These function pointers are temporary hacks
|
|
|
|
* during the record layer refactoring. They need to be removed before the
|
|
|
|
* refactor is complete.
|
|
|
|
*/
|
|
|
|
tls_default_read_n,
|
|
|
|
tls_get0_rbuf,
|
|
|
|
tls_get0_packet,
|
|
|
|
tls_set0_packet,
|
|
|
|
tls_get_packet_length,
|
|
|
|
tls_reset_packet_length
|
|
|
|
};
|