/* 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
}
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)
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;
int version;
int role;
int direction;
+ int level;
/*
* A BIO containing any data read in the previous epoch that was destined
/* 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];
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;
};
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);
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
/* 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;
}
}
}
- 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;
}
}
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)
{
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;
rl->version = vers;
rl->role = role;
rl->direction = direction;
+ rl->level = level;
if (level == OSSL_RECORD_PROTECTION_LEVEL_NONE)
rl->is_first_record = 1;
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:
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)
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;
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)
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;
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)
{
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);
*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 (;;) {
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:
typedef struct ssl_connection_st SSL_CONNECTION;
typedef struct ssl3_buffer_st SSL3_BUFFER;
+#include <openssl/core_dispatch.h>
#include "recordmethod.h"
/*****************************************************************************
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))
\ No newline at end of file
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);
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);
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;
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);
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;
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;