Skip to content

Commit

Permalink
Move early data counting out of the SSL object and into the record layer
Browse files Browse the repository at this point in the history
Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from #18132)
  • Loading branch information
mattcaswell committed Aug 18, 2022
1 parent 0755722 commit 9dd9023
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 26 deletions.
11 changes: 6 additions & 5 deletions include/openssl/core_names.h
Expand Up @@ -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
}
Expand Down
3 changes: 2 additions & 1 deletion ssl/record/methods/ktls_meth.c
Expand Up @@ -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)
Expand All @@ -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;
Expand Down
13 changes: 12 additions & 1 deletion ssl/record/methods/recmethod_local.h
Expand Up @@ -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
Expand Down Expand Up @@ -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];

Expand All @@ -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;
};
Expand Down Expand Up @@ -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);
Expand Down
66 changes: 56 additions & 10 deletions ssl/record/methods/tls_common.c
Expand Up @@ -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
Expand Down Expand Up @@ -705,17 +729,17 @@ 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.
*/

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;
}

Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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:
Expand All @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand Down
32 changes: 30 additions & 2 deletions ssl/record/rec_layer_s3.c
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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 (;;) {
Expand All @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions ssl/record/record.h
Expand Up @@ -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"

/*****************************************************************************
Expand Down Expand Up @@ -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))
5 changes: 3 additions & 2 deletions ssl/record/record_local.h
Expand Up @@ -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);
2 changes: 2 additions & 0 deletions ssl/record/recordmethod.h
Expand Up @@ -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);
Expand Down
18 changes: 13 additions & 5 deletions ssl/record/ssl3_record.c
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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;
Expand Down

0 comments on commit 9dd9023

Please sign in to comment.