Move early data counting out of the SSL object and into the record layer
Reviewed-by: Hugo Landau <hlandau@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/18132)
This commit is contained in:
parent
0755722c28
commit
9dd90232d5
9 changed files with 128 additions and 26 deletions
|
|
@ -558,11 +558,12 @@ extern "C" {
|
|||
|
||||
/* Libssl record layer */
|
||||
|
||||
#define OSSL_LIBSSL_RECORD_LAYER_PARAM_OPTIONS "options"
|
||||
#define OSSL_LIBSSL_RECORD_LAYER_PARAM_MODE "mode"
|
||||
#define OSSL_LIBSSL_RECORD_LAYER_PARAM_READ_AHEAD "read_ahead"
|
||||
#define OSSL_LIBSSL_RECORD_LAYER_PARAM_USE_ETM "use_etm"
|
||||
#define OSSL_LIBSSL_RECORD_LAYER_PARAM_MAX_FRAG_LEN "max_frag_len"
|
||||
#define OSSL_LIBSSL_RECORD_LAYER_PARAM_OPTIONS "options"
|
||||
#define OSSL_LIBSSL_RECORD_LAYER_PARAM_MODE "mode"
|
||||
#define OSSL_LIBSSL_RECORD_LAYER_PARAM_READ_AHEAD "read_ahead"
|
||||
#define OSSL_LIBSSL_RECORD_LAYER_PARAM_USE_ETM "use_etm"
|
||||
#define OSSL_LIBSSL_RECORD_LAYER_PARAM_MAX_FRAG_LEN "max_frag_len"
|
||||
#define OSSL_LIBSSL_RECORD_LAYER_PARAM_MAX_EARLY_DATA "max_early_data"
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -574,6 +574,7 @@ ktls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
|
|||
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,
|
||||
/* TODO(RECLAYER): Remove me */
|
||||
SSL_CONNECTION *s)
|
||||
|
|
@ -584,7 +585,7 @@ ktls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
|
|||
key, keylen, iv, ivlen, mackey, mackeylen,
|
||||
ciph, taglen, mactype, md, comp, prev,
|
||||
transport, next, local, peer, settings,
|
||||
options, retrl, s);
|
||||
options, fns, cbarg, retrl, s);
|
||||
|
||||
if (ret != OSSL_RECORD_RETURN_SUCCESS)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ struct ossl_record_layer_st
|
|||
int version;
|
||||
int role;
|
||||
int direction;
|
||||
int level;
|
||||
|
||||
/*
|
||||
* A BIO containing any data read in the previous epoch that was destined
|
||||
|
|
@ -142,6 +143,12 @@ struct ossl_record_layer_st
|
|||
/* The negotiated maximum fragment length */
|
||||
unsigned int max_frag_len;
|
||||
|
||||
/* The maxium amount of early data we can receive/send */
|
||||
uint32_t max_early_data;
|
||||
|
||||
/* The amount of early data that we have sent/received */
|
||||
size_t early_data_count;
|
||||
|
||||
/* Only used by SSLv3 */
|
||||
unsigned char mac_secret[EVP_MAX_MD_SIZE];
|
||||
|
||||
|
|
@ -161,7 +168,10 @@ struct ossl_record_layer_st
|
|||
|
||||
size_t taglen;
|
||||
|
||||
/* Function pointers for version specific functions */
|
||||
/* Callbacks */
|
||||
void *cbarg;
|
||||
OSSL_FUNC_rlayer_skip_early_data_fn *rlayer_skip_early_data;
|
||||
|
||||
/* Function pointers for version specific functions */
|
||||
struct record_functions_st *funcs;
|
||||
};
|
||||
|
|
@ -220,6 +230,7 @@ tls_int_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
|
|||
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,
|
||||
/* TODO(RECLAYER): Remove me */
|
||||
SSL_CONNECTION *s);
|
||||
|
|
|
|||
|
|
@ -383,6 +383,30 @@ static int tls_record_app_data_waiting(OSSL_RECORD_LAYER *rl)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int rlayer_early_data_count_ok(OSSL_RECORD_LAYER *rl, size_t length,
|
||||
size_t overhead, int send)
|
||||
{
|
||||
uint32_t max_early_data = rl->max_early_data;
|
||||
|
||||
if (max_early_data == 0) {
|
||||
RLAYERfatal(rl, send ? SSL_AD_INTERNAL_ERROR : SSL_AD_UNEXPECTED_MESSAGE,
|
||||
SSL_R_TOO_MUCH_EARLY_DATA);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we are dealing with ciphertext we need to allow for the overhead */
|
||||
max_early_data += overhead;
|
||||
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
rl->early_data_count += length;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* MAX_EMPTY_RECORDS defines the number of consecutive, empty records that
|
||||
* will be processed per call to ssl3_get_record. Without this limit an
|
||||
|
|
@ -705,7 +729,7 @@ static int tls_get_more_records(OSSL_RECORD_LAYER *rl,
|
|||
/* RLAYERfatal() already got called */
|
||||
goto end;
|
||||
}
|
||||
if (num_recs == 1 && ossl_statem_skip_early_data(s)) {
|
||||
if (num_recs == 1 && rl->rlayer_skip_early_data(rl->cbarg)) {
|
||||
/*
|
||||
* Valid early_data that we cannot decrypt will fail here. We treat
|
||||
* it like an empty record.
|
||||
|
|
@ -713,9 +737,9 @@ static int tls_get_more_records(OSSL_RECORD_LAYER *rl,
|
|||
|
||||
thisrr = &rr[0];
|
||||
|
||||
if (!ossl_early_data_count_ok(s, thisrr->length,
|
||||
EARLY_DATA_CIPHERTEXT_OVERHEAD, 0)) {
|
||||
/* SSLfatal() already called */
|
||||
if (!rlayer_early_data_count_ok(rl, thisrr->length,
|
||||
EARLY_DATA_CIPHERTEXT_OVERHEAD, 0)) {
|
||||
/* RLAYERfatal() already called */
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
|
@ -812,11 +836,11 @@ static int tls_get_more_records(OSSL_RECORD_LAYER *rl,
|
|||
}
|
||||
}
|
||||
|
||||
if (s->early_data_state == SSL_EARLY_DATA_READING) {
|
||||
if (rl->level == OSSL_RECORD_PROTECTION_LEVEL_EARLY) {
|
||||
thisrr = &rr[0];
|
||||
if (thisrr->type == SSL3_RT_APPLICATION_DATA
|
||||
&& !ossl_early_data_count_ok(s, thisrr->length, 0, 0)) {
|
||||
/* SSLfatal already called */
|
||||
&& !rlayer_early_data_count_ok(rl, thisrr->length, 0, 0)) {
|
||||
/* RLAYERfatal already called */
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
|
@ -1011,7 +1035,9 @@ tls_int_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
|
|||
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, OSSL_RECORD_LAYER **retrl,
|
||||
const OSSL_PARAM *options,
|
||||
const OSSL_DISPATCH *fns, void *cbarg,
|
||||
OSSL_RECORD_LAYER **retrl,
|
||||
/* TODO(RECLAYER): Remove me */
|
||||
SSL_CONNECTION *s)
|
||||
{
|
||||
|
|
@ -1053,6 +1079,11 @@ tls_int_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
|
|||
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 {
|
||||
RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, SSL_R_UNKNOWN_MANDATORY_PARAMETER);
|
||||
goto err;
|
||||
|
|
@ -1084,6 +1115,7 @@ tls_int_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
|
|||
rl->version = vers;
|
||||
rl->role = role;
|
||||
rl->direction = direction;
|
||||
rl->level = level;
|
||||
|
||||
if (level == OSSL_RECORD_PROTECTION_LEVEL_NONE)
|
||||
rl->is_first_record = 1;
|
||||
|
|
@ -1099,6 +1131,18 @@ tls_int_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
|
|||
goto err;
|
||||
rl->next = next;
|
||||
|
||||
rl->cbarg = cbarg;
|
||||
for (; fns->function_id != 0; fns++) {
|
||||
switch (fns->function_id) {
|
||||
case OSSL_FUNC_RLAYER_SKIP_EARLY_DATA:
|
||||
rl->rlayer_skip_early_data = OSSL_FUNC_rlayer_skip_early_data(fns);
|
||||
break;
|
||||
default:
|
||||
/* Just ignore anything we don't understand */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*retrl = rl;
|
||||
return OSSL_RECORD_RETURN_SUCCESS;
|
||||
err:
|
||||
|
|
@ -1117,6 +1161,7 @@ tls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
|
|||
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,
|
||||
/* TODO(RECLAYER): Remove me */
|
||||
SSL_CONNECTION *s)
|
||||
|
|
@ -1127,7 +1172,7 @@ tls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
|
|||
key, keylen, iv, ivlen, mackey, mackeylen,
|
||||
ciph, taglen, mactype, md, comp, prev,
|
||||
transport, next, local, peer, settings,
|
||||
options, retrl, s);
|
||||
options, fns, cbarg, retrl, s);
|
||||
|
||||
if (ret != OSSL_RECORD_RETURN_SUCCESS)
|
||||
return ret;
|
||||
|
|
@ -1192,6 +1237,7 @@ dtls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
|
|||
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,
|
||||
/* TODO(RECLAYER): Remove me */
|
||||
SSL_CONNECTION *s)
|
||||
|
|
@ -1203,7 +1249,7 @@ dtls_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
|
|||
key, keylen, iv, ivlen, mackey, mackeylen,
|
||||
ciph, taglen, mactype, md, comp, prev,
|
||||
transport, next, local, peer, settings,
|
||||
options, retrl, s);
|
||||
options, fns, cbarg, retrl, s);
|
||||
|
||||
if (ret != OSSL_RECORD_RETURN_SUCCESS)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -1749,6 +1749,11 @@ size_t RECORD_LAYER_get_rrec_length(RECORD_LAYER *rl)
|
|||
return SSL3_RECORD_get_length(&rl->rrec[0]);
|
||||
}
|
||||
|
||||
static const OSSL_DISPATCH rlayer_dispatch[] = {
|
||||
{ OSSL_FUNC_RLAYER_SKIP_EARLY_DATA, (void (*)(void))ossl_statem_skip_early_data },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const OSSL_RECORD_METHOD *ssl_select_next_record_layer(SSL_CONNECTION *s,
|
||||
int level)
|
||||
{
|
||||
|
|
@ -1797,12 +1802,14 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
|
|||
const SSL_COMP *comp)
|
||||
{
|
||||
OSSL_PARAM options[4], *opts = options;
|
||||
OSSL_PARAM settings[3], *set = settings;
|
||||
OSSL_PARAM settings[4], *set = settings;
|
||||
const OSSL_RECORD_METHOD *origmeth = s->rrlmethod;
|
||||
SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
|
||||
const OSSL_RECORD_METHOD *meth;
|
||||
int use_etm;
|
||||
unsigned int maxfrag = SSL3_RT_MAX_PLAIN_LENGTH;
|
||||
int use_early_data = 0;
|
||||
uint32_t max_early_data;
|
||||
|
||||
meth = ssl_select_next_record_layer(s, level);
|
||||
|
||||
|
|
@ -1845,6 +1852,26 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
|
|||
*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.
|
||||
*/
|
||||
/* TODO(RECLAYER): Check this when doing the "write" record layer */
|
||||
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_uint(OSSL_LIBSSL_RECORD_LAYER_PARAM_MAX_EARLY_DATA,
|
||||
&max_early_data);
|
||||
}
|
||||
|
||||
*set = OSSL_PARAM_construct_end();
|
||||
|
||||
for (;;) {
|
||||
|
|
@ -1865,7 +1892,8 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version,
|
|||
mackey, mackeylen, ciph, taglen,
|
||||
mactype, md, comp, prev, s->rbio,
|
||||
s->rrlnext, NULL, NULL, settings,
|
||||
options, &s->rrl, s);
|
||||
options, rlayer_dispatch, s,
|
||||
&s->rrl, s);
|
||||
BIO_free(prev);
|
||||
switch (rlret) {
|
||||
case OSSL_RECORD_RETURN_FATAL:
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
typedef struct ssl_connection_st SSL_CONNECTION;
|
||||
typedef struct ssl3_buffer_st SSL3_BUFFER;
|
||||
|
||||
#include <openssl/core_dispatch.h>
|
||||
#include "recordmethod.h"
|
||||
|
||||
/*****************************************************************************
|
||||
|
|
@ -290,3 +291,6 @@ int ssl_set_new_record_layer(SSL_CONNECTION *s, int version, int direction,
|
|||
const EVP_CIPHER *ciph, size_t taglen,
|
||||
int mactype, const EVP_MD *md,
|
||||
const SSL_COMP *comp);
|
||||
|
||||
# define OSSL_FUNC_RLAYER_SKIP_EARLY_DATA 1
|
||||
OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, rlayer_skip_early_data,(void *cbarg))
|
||||
|
|
@ -122,5 +122,6 @@ __owur int tls1_cbc_remove_padding_and_mac(size_t *reclen,
|
|||
OSSL_LIB_CTX *libctx);
|
||||
int dtls1_process_record(SSL_CONNECTION *s, DTLS1_BITMAP *bitmap);
|
||||
__owur int dtls1_get_record(SSL_CONNECTION *s);
|
||||
int ossl_early_data_count_ok(SSL_CONNECTION *s, size_t length,
|
||||
size_t overhead, int send);
|
||||
uint32_t ossl_get_max_early_data(SSL_CONNECTION *s);
|
||||
int ossl_early_data_count_ok(SSL_CONNECTION *s, size_t length, size_t overhead,
|
||||
int send);
|
||||
|
|
|
|||
|
|
@ -165,6 +165,8 @@ struct ossl_record_method_st {
|
|||
BIO_ADDR *peer,
|
||||
const OSSL_PARAM *settings,
|
||||
const OSSL_PARAM *options,
|
||||
const OSSL_DISPATCH *fns,
|
||||
void *cbarg,
|
||||
OSSL_RECORD_LAYER **ret,
|
||||
/* TODO(RECLAYER): Remove me */
|
||||
SSL_CONNECTION *s);
|
||||
|
|
|
|||
|
|
@ -63,8 +63,7 @@ void SSL3_RECORD_set_seq_num(SSL3_RECORD *r, const unsigned char *seq_num)
|
|||
memcpy(r->seq_num, seq_num, SEQ_NUM_SIZE);
|
||||
}
|
||||
|
||||
int ossl_early_data_count_ok(SSL_CONNECTION *s, size_t length,
|
||||
size_t overhead, int send)
|
||||
uint32_t ossl_get_max_early_data(SSL_CONNECTION *s)
|
||||
{
|
||||
uint32_t max_early_data;
|
||||
SSL_SESSION *sess = s->session;
|
||||
|
|
@ -91,6 +90,16 @@ int ossl_early_data_count_ok(SSL_CONNECTION *s, size_t length,
|
|||
max_early_data = s->recv_max_early_data < sess->ext.max_early_data
|
||||
? s->recv_max_early_data : sess->ext.max_early_data;
|
||||
|
||||
return max_early_data;
|
||||
}
|
||||
|
||||
int ossl_early_data_count_ok(SSL_CONNECTION *s, size_t length, size_t overhead,
|
||||
int send)
|
||||
{
|
||||
uint32_t max_early_data;
|
||||
|
||||
max_early_data = ossl_get_max_early_data(s);
|
||||
|
||||
if (max_early_data == 0) {
|
||||
SSLfatal(s, send ? SSL_AD_INTERNAL_ERROR : SSL_AD_UNEXPECTED_MESSAGE,
|
||||
SSL_R_TOO_MUCH_EARLY_DATA);
|
||||
|
|
@ -110,8 +119,7 @@ int ossl_early_data_count_ok(SSL_CONNECTION *s, size_t length,
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int ssl3_do_uncompress(SSL_CONNECTION *sc, SSL3_RECORD *rr)
|
||||
int ssl3_do_uncompress(SSL_CONNECTION *ssl, SSL3_RECORD *rr)
|
||||
{
|
||||
#ifndef OPENSSL_NO_COMP
|
||||
int i;
|
||||
|
|
@ -123,7 +131,7 @@ int ssl3_do_uncompress(SSL_CONNECTION *sc, SSL3_RECORD *rr)
|
|||
if (rr->comp == NULL)
|
||||
return 0;
|
||||
|
||||
i = COMP_expand_block(sc->expand, rr->comp,
|
||||
i = COMP_expand_block(ssl->expand, rr->comp,
|
||||
SSL3_RT_MAX_PLAIN_LENGTH, rr->data, (int)rr->length);
|
||||
if (i < 0)
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue