Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support QUIC with the msg_callback and -trace in s_client #20914

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f2cc537
Add initial QUIC support for the msg_callback
mattcaswell May 1, 2023
cdd23bb
Support trace for QUIC datagrams
mattcaswell May 2, 2023
15bcc1e
Support trace for QUIC Packets
mattcaswell May 4, 2023
a05f30d
Support trace for QUIC Frames
mattcaswell May 4, 2023
f8c0974
Extend tracing of frames to transmitted frames
mattcaswell May 5, 2023
827c96e
Enable tracing of packets that have been sent
mattcaswell May 5, 2023
46dac8f
Enable tracing of datagrams we have sent
mattcaswell May 8, 2023
741d10a
Properly handling stream/crypto frames while tracing
mattcaswell May 8, 2023
6baf7dc
Add more trace details for the remaining frame types
mattcaswell May 8, 2023
8808f36
Update the msg_callback documentation
mattcaswell May 9, 2023
df47f74
Fix an SSL_trace bug
mattcaswell May 9, 2023
e82e8fa
Add a test for the new QUIC tracing capability
mattcaswell May 9, 2023
7b2768e
fixup! Extend tracing of frames to transmitted frames
mattcaswell May 18, 2023
1daebdf
Create setter functions for the msg_callback and msg_callback_arg
mattcaswell May 18, 2023
4afae1d
fixup! Update the msg_callback documentation
mattcaswell May 22, 2023
0a30b72
fixup! Enable tracing of packets that have been sent
mattcaswell May 22, 2023
da0cb7c
fixup! Create setter functions for the msg_callback and msg_callback_arg
mattcaswell May 22, 2023
dd7118e
Use the %llu format specifier for uint64_t
mattcaswell May 22, 2023
7c711bd
fixup! Fix an SSL_trace bug
mattcaswell May 22, 2023
0190d2a
Rename msg_callback_s to msg_callback_ssl for greater clarity
mattcaswell May 22, 2023
ad6aa7c
fixup! Support trace for QUIC Frames
mattcaswell May 22, 2023
c9f80b1
fixup! Create setter functions for the msg_callback and msg_callback_arg
mattcaswell May 22, 2023
2f3b6c5
Create internal/ssl.h
mattcaswell May 22, 2023
5fc5736
fixup! Add a test for the new QUIC tracing capability
mattcaswell May 22, 2023
ce22275
fixup! Create internal/ssl.h
mattcaswell May 22, 2023
65152c0
fixup! Add a test for the new QUIC tracing capability
mattcaswell May 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
54 changes: 48 additions & 6 deletions doc/man3/SSL_CTX_set_msg_callback.pod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
SSL_CTX_set_msg_callback,
SSL_CTX_set_msg_callback_arg,
SSL_set_msg_callback,
SSL_set_msg_callback_arg
SSL_set_msg_callback_arg,
SSL_trace
- install callback for observing protocol messages

=head1 SYNOPSIS
Expand All @@ -24,10 +25,13 @@ SSL_set_msg_callback_arg
size_t len, SSL *ssl, void *arg));
void SSL_set_msg_callback_arg(SSL *ssl, void *arg);

void SSL_trace(int write_p, int version, int content_type,
const void *buf, size_t len, SSL *ssl, void *arg);

=head1 DESCRIPTION

SSL_CTX_set_msg_callback() or SSL_set_msg_callback() can be used to
define a message callback function I<cb> for observing all SSL/TLS
define a message callback function I<cb> for observing all SSL/TLS/QUIC
protocol messages (such as handshake messages) that are received or
sent, as well as other events that occur during processing.
SSL_CTX_set_msg_callback_arg() and SSL_set_msg_callback_arg()
Expand All @@ -40,7 +44,7 @@ L<SSL_new(3)>. SSL_set_msg_callback() and
SSL_set_msg_callback_arg() modify the actual settings of an B<SSL>
object. Using a B<NULL> pointer for I<cb> disables the message callback.

When I<cb> is called by the SSL/TLS library the function arguments have the
When I<cb> is called by the SSL/TLS/QUIC library the function arguments have the
following meaning:

=over 4
Expand All @@ -53,8 +57,9 @@ when a protocol message has been sent.
=item I<version>

The protocol version according to which the protocol message is
interpreted by the library such as B<TLS1_3_VERSION>, B<TLS1_2_VERSION> etc.
This is set to 0 for the SSL3_RT_HEADER pseudo content type (see NOTES below).
interpreted by the library such as B<TLS1_3_VERSION>, B<TLS1_2_VERSION>,
B<OSSL_QUIC1_VERSION> etc. This is set to 0 for the SSL3_RT_HEADER pseudo
content type (see NOTES below).

=item I<content_type>

Expand Down Expand Up @@ -82,6 +87,13 @@ SSL_CTX_set_msg_callback_arg() or SSL_set_msg_callback_arg().

=back

The SSL_trace() function can be used as a pre-written callback in a call to
SSL_CTX_set_msg_callback() or SSL_set_msg_callback(). It requires a BIO to be
set as the callback argument via SSL_CTX_set_msg_callback_arg() or
SSL_set_msg_callback_arg(). Setting this callback will cause human readable
diagostic tracing information about an SSL/TLS/QUIC connection to be written to
the BIO.

=head1 NOTES

Protocol messages are passed to the callback function after decryption
Expand All @@ -105,7 +117,7 @@ of data. The following pseudo content types are currently defined:

=item B<SSL3_RT_HEADER>

Used when a record is sent or received. The B<buf> contains the record header
Used when a TLS record is sent or received. The B<buf> contains the record header
bytes only.

=item B<SSL3_RT_INNER_CONTENT_TYPE>
Expand All @@ -115,6 +127,32 @@ records the content type in the record header is always
SSL3_RT_APPLICATION_DATA. The real content type for the record is contained in
an "inner" content type. B<buf> contains the encoded "inner" content type byte.

=item B<SSL3_RT_QUIC_DATAGRAM>

Used when a QUIC datagram is sent or received.

=item B<SSL3_RT_QUIC_PACKET>

Used when a QUIC packet is sent or received.

=item B<SSL3_RT_QUIC_FRAME_FULL>

Used when a QUIC frame is sent or received. This is only used for non-crypto
and stream data related frames. The full QUIC frame data is supplied.

=item B<SSL3_RT_QUIC_FRAME_HEADER>

Used when a QUIC stream data or crypto frame is sent or received. Only the QUIC
frame header data is supplied.

=item B<SSL3_RT_QUIC_FRAME_PADDING>

Used when a sequence of one or more QUIC padding frames is sent or received.
A padding frame consists of a single byte and it is common to have multiple
such frames in a sequence. Rather than supplying each frame individually the
callback will supply all the padding frames in one go via this pseudo content
type.

=back

=head1 RETURN VALUES
Expand All @@ -130,6 +168,10 @@ L<ssl(7)>, L<SSL_new(3)>

The pseudo content type B<SSL3_RT_INNER_CONTENT_TYPE> was added in OpenSSL 1.1.1.

The pseudo content types B<SSL3_RT_QUIC_DATAGRAM>, B<SSL3_RT_QUIC_PACKET>,
B<SSL3_RT_QUIC_FRAME_FULL>, B<SSL3_RT_QUIC_FRAME_HEADER> and
B<SSL3_RT_QUIC_FRAME_PADDING> were added in OpenSSL 3.2.

=head1 COPYRIGHT

Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
Expand Down
7 changes: 7 additions & 0 deletions include/internal/quic_channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,13 @@ void ossl_quic_channel_reject_stream(QUIC_CHANNEL *ch, QUIC_STREAM *qs);
int ossl_quic_channel_replace_local_cid(QUIC_CHANNEL *ch,
const QUIC_CONN_ID *conn_id);

/* Setters for the msg_callback and msg_callback_arg */
void ossl_quic_channel_set_msg_callback(QUIC_CHANNEL *ch,
ossl_msg_cb msg_callback,
SSL *msg_callback_ssl);
void ossl_quic_channel_set_msg_callback_arg(QUIC_CHANNEL *ch,
void *msg_callback_arg);

# endif

#endif
6 changes: 6 additions & 0 deletions include/internal/quic_record_rx.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ OSSL_QRX *ossl_qrx_new(const OSSL_QRX_ARGS *args);
*/
void ossl_qrx_free(OSSL_QRX *qrx);

/* Setters for the msg_callback and msg_callback_arg */
void ossl_qrx_set_msg_callback(OSSL_QRX *qrx, ossl_msg_cb msg_callback,
SSL *msg_callback_ssl);
void ossl_qrx_set_msg_callback_arg(OSSL_QRX *qrx,
void *msg_callback_arg);

/*
* DCID Management
* ===============
Expand Down
5 changes: 5 additions & 0 deletions include/internal/quic_record_tx.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ void ossl_qtx_free(OSSL_QTX *qtx);
void ossl_qtx_set_mutator(OSSL_QTX *qtx, ossl_mutate_packet_cb mutatecb,
ossl_finish_mutate_cb finishmutatecb, void *mutatearg);

/* Setters for the msg_callback and the msg_callback_arg */
void ossl_qtx_set_msg_callback(OSSL_QTX *qtx, ossl_msg_cb msg_callback,
SSL *msg_callback_ssl);
void ossl_qtx_set_msg_callback_arg(OSSL_QTX *qtx, void *msg_callback_arg);

/*
* Secret Management
* -----------------
Expand Down
7 changes: 7 additions & 0 deletions include/internal/quic_txp.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,13 @@ void ossl_quic_tx_packetiser_schedule_ack_eliciting(OSSL_QUIC_TX_PACKETISER *txp
int ossl_quic_tx_packetiser_schedule_conn_close(OSSL_QUIC_TX_PACKETISER *txp,
const OSSL_QUIC_FRAME_CONN_CLOSE *f);

/* Setters for the msg_callback and msg_callback_arg */
void ossl_quic_tx_packetiser_set_msg_callback(OSSL_QUIC_TX_PACKETISER *txp,
ossl_msg_cb msg_callback,
SSL *msg_callback_ssl);
void ossl_quic_tx_packetiser_set_msg_callback_arg(OSSL_QUIC_TX_PACKETISER *txp,
void *msg_callback_arg);

# endif

#endif
1 change: 1 addition & 0 deletions include/internal/quic_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# define OSSL_QUIC_TYPES_H

# include <openssl/ssl.h>
# include <internal/ssl.h>
# include <assert.h>
# include <string.h>

Expand Down
12 changes: 9 additions & 3 deletions include/internal/quic_wire.h
Original file line number Diff line number Diff line change
Expand Up @@ -557,9 +557,11 @@ int ossl_quic_wire_decode_frame_stop_sending(PACKET *pkt,
* Decodes a QUIC CRYPTO frame.
*
* f->data is set to point inside the packet buffer inside the PACKET, therefore
* it is safe to access for as long as the packet buffer exists.
* it is safe to access for as long as the packet buffer exists. If nodata is
* set to 1 then reading the PACKET stops after the frame header and f->data is
* set to NULL.
*/
int ossl_quic_wire_decode_frame_crypto(PACKET *pkt,
int ossl_quic_wire_decode_frame_crypto(PACKET *pkt, int nodata,
OSSL_QUIC_FRAME_CRYPTO *f);

/*
Expand All @@ -573,6 +575,10 @@ int ossl_quic_wire_decode_frame_new_token(PACKET *pkt,
/*
* Decodes a QUIC STREAM frame.
*
* If nodata is set to 1 then reading the PACKET stops after the frame header
* and f->data is set to NULL. In this case f->len will also be 0 in the event
* that "has_explicit_len" is 0.
*
* If the frame did not contain an offset field, f->offset is set to 0, as the
* absence of an offset field is equivalent to an offset of 0.
*
Expand All @@ -595,7 +601,7 @@ int ossl_quic_wire_decode_frame_new_token(PACKET *pkt,
* f->is_fin is set according to whether the frame was marked as ending the
* stream.
*/
int ossl_quic_wire_decode_frame_stream(PACKET *pkt,
int ossl_quic_wire_decode_frame_stream(PACKET *pkt, int nodata,
OSSL_QUIC_FRAME_STREAM *f);

/*
Expand Down
4 changes: 4 additions & 0 deletions include/internal/quic_wire_pkt.h
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,9 @@ struct quic_pkt_hdr_ptrs_st {
* If partial is 0, the input is assumed to have already had header protection
* removed, and all header fields are decoded.
*
* If nodata is 1, the input is assumed to have no payload data in it. Otherwise
* payload data must be present.
*
* On success, the logical decode of the packet header is written to *hdr.
* hdr->partial is set or cleared according to whether a partial decode was
* performed. *ptrs is filled with pointers to various parts of the packet
Expand All @@ -441,6 +444,7 @@ struct quic_pkt_hdr_ptrs_st {
int ossl_quic_wire_decode_pkt_hdr(PACKET *pkt,
size_t short_conn_id_len,
int partial,
int nodata,
QUIC_PKT_HDR *hdr,
QUIC_PKT_HDR_PTRS *ptrs);

Expand Down
19 changes: 19 additions & 0 deletions include/internal/ssl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2023 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 <openssl/ssl.h>

#ifndef OSSL_INTERNAL_SSL_H
# define OSSL_INTERNAL_SSL_H
# pragma once

typedef void (*ossl_msg_cb)(int write_p, int version, int content_type,
const void *buf, size_t len, SSL *ssl, void *arg);

#endif
7 changes: 7 additions & 0 deletions include/openssl/ssl3.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,13 @@ extern "C" {
# define SSL3_RT_HEADER 0x100
# define SSL3_RT_INNER_CONTENT_TYPE 0x101

/* Pseudo content types for QUIC */
# define SSL3_RT_QUIC_DATAGRAM 0x200
# define SSL3_RT_QUIC_PACKET 0x201
# define SSL3_RT_QUIC_FRAME_FULL 0x202
# define SSL3_RT_QUIC_FRAME_HEADER 0x203
# define SSL3_RT_QUIC_FRAME_PADDING 0x204
Comment on lines +243 to +247
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SSL3_RT_ prefix sounds quite awkward for something that has no relation to SSL3 at all. Perhaps OSSL_RT_.... would be better?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. But the problem here is that the SSL3_RT_ prefix is well established for this namespace and is legacy. It would be quite weird to have some values in the same space to have different prefixes. Plausibly we could introduce OSSL_RT_* everywhere and have some compatibility defines for old usage of SSL3_RT_* but this is a significant change with knock-on impacts throughout libssl. The SSL3_RT_ values are used beyond just the msg_callback. I'd rather not do that in this PR.


# define SSL3_AL_WARNING 1
# define SSL3_AL_FATAL 2

Expand Down
1 change: 1 addition & 0 deletions ssl/quic/build.info
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ SOURCE[$LIBSSL]=quic_channel.c
SOURCE[$LIBSSL]=quic_tserver.c
SOURCE[$LIBSSL]=quic_tls.c
SOURCE[$LIBSSL]=quic_thread_assist.c
SOURCE[$LIBSSL]=quic_trace.c
24 changes: 23 additions & 1 deletion ssl/quic/quic_channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ static int ch_init(QUIC_CHANNEL *ch)
txp_args.cc_data = ch->cc_data;
txp_args.now = get_time;
txp_args.now_arg = ch;

for (pn_space = QUIC_PN_SPACE_INITIAL; pn_space < QUIC_PN_SPACE_NUM; ++pn_space) {
ch->crypto_send[pn_space] = ossl_quic_sstream_new(INIT_CRYPTO_BUF_LEN);
if (ch->crypto_send[pn_space] == NULL)
Expand Down Expand Up @@ -1589,7 +1590,7 @@ static void ch_default_packet_handler(QUIC_URXE *e, void *arg)
* operation to fail if we get a 1-RTT packet. This is fine since we only
* care about Initial packets.
*/
if (!ossl_quic_wire_decode_pkt_hdr(&pkt, SIZE_MAX, 1, &hdr, NULL))
if (!ossl_quic_wire_decode_pkt_hdr(&pkt, SIZE_MAX, 1, 0, &hdr, NULL))
goto undesirable;

switch (hdr.version) {
Expand Down Expand Up @@ -2508,3 +2509,24 @@ int ossl_quic_channel_replace_local_cid(QUIC_CHANNEL *ch,
return 0;
return 1;
}

void ossl_quic_channel_set_msg_callback(QUIC_CHANNEL *ch,
ossl_msg_cb msg_callback,
SSL *msg_callback_ssl)
{
ch->msg_callback = msg_callback;
ch->msg_callback_ssl = msg_callback_ssl;
ossl_qtx_set_msg_callback(ch->qtx, msg_callback, msg_callback_ssl);
ossl_quic_tx_packetiser_set_msg_callback(ch->txp, msg_callback,
msg_callback_ssl);
ossl_qrx_set_msg_callback(ch->qrx, msg_callback, msg_callback_ssl);
}

void ossl_quic_channel_set_msg_callback_arg(QUIC_CHANNEL *ch,
void *msg_callback_arg)
{
ch->msg_callback_arg = msg_callback_arg;
ossl_qtx_set_msg_callback_arg(ch->qtx, msg_callback_arg);
ossl_quic_tx_packetiser_set_msg_callback_arg(ch->txp, msg_callback_arg);
ossl_qrx_set_msg_callback_arg(ch->qrx, msg_callback_arg);
}
5 changes: 5 additions & 0 deletions ssl/quic/quic_channel_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ struct quic_channel_st {
OSSL_QTX *qtx;
OSSL_QRX *qrx;

/* Message callback related arguments */
ossl_msg_cb msg_callback;
void *msg_callback_arg;
SSL *msg_callback_ssl;

/*
* Send and receive parts of the crypto streams.
* crypto_send[QUIC_PN_SPACE_APP] is the 1-RTT crypto stream. There is no
Expand Down
26 changes: 25 additions & 1 deletion ssl/quic/quic_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,9 @@ SSL *ossl_quic_new(SSL_CTX *ctx)
if (!create_channel(qc))
goto err;

ossl_quic_channel_set_msg_callback(qc->ch, ctx->msg_callback, ssl_base);
ossl_quic_channel_set_msg_callback_arg(qc->ch, ctx->msg_callback_arg);

qc_update_reject_policy(qc);

/*
Expand Down Expand Up @@ -1009,6 +1012,12 @@ long ossl_quic_ctrl(SSL *s, int cmd, long larg, void *parg)
}

return ctx.qc->default_ssl_mode;

case SSL_CTRL_SET_MSG_CALLBACK_ARG:
ossl_quic_channel_set_msg_callback_arg(ctx.qc->ch, parg);
/* This ctrl also needs to be passed to the internal SSL object */
return SSL_ctrl(ctx.qc->tls, cmd, larg, parg);

default:
/* Probably a TLS related ctrl. Defer to our internal SSL object */
return SSL_ctrl(ctx.qc->tls, cmd, larg, parg);
Expand Down Expand Up @@ -2608,7 +2617,22 @@ long ossl_quic_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)

long ossl_quic_callback_ctrl(SSL *s, int cmd, void (*fp) (void))
{
return ssl3_callback_ctrl(s, cmd, fp);
QCTX ctx;

if (!expect_quic_conn_only(s, &ctx))
return 0;

switch (cmd) {
case SSL_CTRL_SET_MSG_CALLBACK:
ossl_quic_channel_set_msg_callback(ctx.qc->ch, (ossl_msg_cb)fp,
&ctx.qc->ssl);
/* This callback also needs to be set on the internal SSL object */
return ssl3_callback_ctrl(ctx.qc->tls, cmd, fp);;

default:
/* Probably a TLS related ctrl. Defer to our internal SSL object */
return ssl3_callback_ctrl(ctx.qc->tls, cmd, fp);
}
}

long ossl_quic_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp) (void))
Expand Down
3 changes: 3 additions & 0 deletions ssl/quic/quic_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ void ossl_quic_conn_raise_protocol_error(QUIC_CONNECTION *qc,
void ossl_quic_conn_on_remote_conn_close(QUIC_CONNECTION *qc,
OSSL_QUIC_FRAME_CONN_CLOSE *f);

int ossl_quic_trace(int write_p, int version, int content_type,
const void *buf, size_t msglen, SSL *ssl, void *arg);

# define OSSL_QUIC_ANY_VERSION 0xFFFFF

# define QUIC_CONNECTION_FROM_SSL_int(ssl, c) \
Expand Down