Add support for the msg_callback

Having support for the msg_callback will improve debug capabilities.

For record headers we "manufacture" dummy ones so that as far as the
callback is concerned we are doing "normal" TLS.

Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19748)
This commit is contained in:
Matt Caswell 2022-11-18 11:39:33 +00:00
parent 2723d705b5
commit 1d57dbac19

View File

@ -40,6 +40,10 @@ struct quic_tls_st {
struct ossl_record_layer_st {
QUIC_TLS *qtls;
/* Protection level */
int level;
/* Only used for retry flags */
BIO *dummybio;
@ -62,6 +66,10 @@ struct ossl_record_layer_st {
/* Set if recbuf is populated with data */
unsigned int recread : 1;
/* Callbacks */
OSSL_FUNC_rlayer_msg_callback_fn *msg_callback;
void *cbarg;
};
static int
@ -90,9 +98,25 @@ quic_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers,
}
rl->qtls = (QUIC_TLS *)rlarg;
rl->level = level;
rl->dummybio = transport;
rl->cbarg = cbarg;
*retrl = rl;
if (fns != NULL) {
for (; fns->function_id != 0; fns++) {
switch (fns->function_id) {
break;
case OSSL_FUNC_RLAYER_MSG_CALLBACK:
rl->msg_callback = OSSL_FUNC_rlayer_msg_callback(fns);
break;
default:
/* Just ignore anything we don't understand */
break;
}
}
}
switch (level) {
case OSSL_RECORD_PROTECTION_LEVEL_NONE:
return 1;
@ -209,6 +233,36 @@ static int quic_write_records(OSSL_RECORD_LAYER *rl,
BIO_clear_retry_flags(rl->dummybio);
if (rl->msg_callback != NULL) {
unsigned char dummyrec[SSL3_RT_HEADER_LENGTH];
/*
* For the purposes of the callback we "pretend" to be normal TLS,
* and manufacture a dummy record header
*/
dummyrec[0] = (rl->level == OSSL_RECORD_PROTECTION_LEVEL_NONE)
? template->type
: SSL3_RT_APPLICATION_DATA;
dummyrec[1] = (unsigned char)((template->version >> 8) & 0xff);
dummyrec[2] = (unsigned char)(template->version & 0xff);
/*
* We assume that buflen is always <= UINT16_MAX. Since this is
* generated by libssl itself we actually expect it to never
* exceed SSL3_RT_MAX_PLAIN_LENGTH - so it should be a safe
* assumption
*/
dummyrec[3] = (unsigned char)((template->buflen >> 8) & 0xff);
dummyrec[4] = (unsigned char)(template->buflen & 0xff);
rl->msg_callback(1, TLS1_3_VERSION, SSL3_RT_HEADER, dummyrec,
SSL3_RT_HEADER_LENGTH, rl->cbarg);
if (rl->level != OSSL_RECORD_PROTECTION_LEVEL_NONE) {
rl->msg_callback(1, TLS1_3_VERSION, SSL3_RT_INNER_CONTENT_TYPE,
&template->type, 1, rl->cbarg);
}
}
switch (template->type) {
case SSL3_RT_ALERT:
if (template->buflen != 2) {
@ -315,6 +369,31 @@ static int quic_read_record(OSSL_RECORD_LAYER *rl, void **rechandle,
rl->recread = 1;
/* epoch/seq_num are not relevant for TLS */
if (rl->msg_callback != NULL) {
unsigned char dummyrec[SSL3_RT_HEADER_LENGTH];
/*
* For the purposes of the callback we "pretend" to be normal TLS,
* and manufacture a dummy record header
*/
dummyrec[0] = (rl->level == OSSL_RECORD_PROTECTION_LEVEL_NONE)
? SSL3_RT_HANDSHAKE
: SSL3_RT_APPLICATION_DATA;
dummyrec[1] = (unsigned char)((TLS1_2_VERSION >> 8) & 0xff);
dummyrec[2] = (unsigned char)(TLS1_2_VERSION & 0xff);
/*
* *datalen will always fit into 2 bytes because our original buffer
* size is less than that.
*/
dummyrec[3] = (unsigned char)((*datalen >> 8) & 0xff);
dummyrec[4] = (unsigned char)(*datalen & 0xff);
rl->msg_callback(0, TLS1_3_VERSION, SSL3_RT_HEADER, dummyrec,
SSL3_RT_HEADER_LENGTH, rl->cbarg);
rl->msg_callback(0, TLS1_3_VERSION, SSL3_RT_INNER_CONTENT_TYPE, type, 1,
rl->cbarg);
}
return OSSL_RECORD_RETURN_SUCCESS;
}