diff options
author | Hugo Landau <hlandau@openssl.org> | 2023-08-17 08:55:52 +0100 |
---|---|---|
committer | Tomas Mraz <tomas@openssl.org> | 2023-08-29 15:33:22 +0200 |
commit | 777a8a7f5d5b80919da906cdaf8825f502bcad4e (patch) | |
tree | dd9ed6452465c7e381e8640a6573acca3783a1f8 /ssl | |
parent | 1cfdbdd0d454b9b3882e364addfab920af3a29d5 (diff) |
QUIC: Minimally handle version negotiation packets
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21764)
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/quic/quic_channel.c | 56 | ||||
-rw-r--r-- | ssl/quic/quic_channel_local.h | 7 | ||||
-rw-r--r-- | ssl/quic/quic_wire_pkt.c | 7 |
3 files changed, 70 insertions, 0 deletions
diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 98e1a0110f..516b895d8d 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -99,6 +99,8 @@ static int ch_server_on_new_conn(QUIC_CHANNEL *ch, const BIO_ADDR *peer, const QUIC_CONN_ID *peer_dcid); static void ch_on_txp_ack_tx(const OSSL_QUIC_FRAME_ACK *ack, uint32_t pn_space, void *arg); +static void ch_rx_handle_version_neg(QUIC_CHANNEL *ch, OSSL_QRX_PKT *pkt); +static void ch_raise_version_neg_failure(QUIC_CHANNEL *ch); DEFINE_LHASH_OF_EX(QUIC_SRT_ELEM); @@ -2092,6 +2094,7 @@ static int bio_addr_eq(const BIO_ADDR *a, const BIO_ADDR *b) static void ch_rx_handle_packet(QUIC_CHANNEL *ch) { uint32_t enc_level; + int old_have_processed_any_pkt = ch->have_processed_any_pkt; assert(ch->qrx_pkt != NULL); @@ -2164,6 +2167,8 @@ static void ch_rx_handle_packet(QUIC_CHANNEL *ch) */ return; + ch->have_processed_any_pkt = 1; + /* * RFC 9000 s. 17.2: "An endpoint MUST treat receipt of a packet that has a * non-zero value for [the reserved bits] after removing both packet and @@ -2281,12 +2286,63 @@ static void ch_rx_handle_packet(QUIC_CHANNEL *ch) ossl_quic_handle_frames(ch, ch->qrx_pkt); /* best effort */ break; + case QUIC_PKT_TYPE_VERSION_NEG: + /* + * "A client MUST discard any Version Negotiation packet if it has + * received and successfully processed any other packet." + */ + if (!old_have_processed_any_pkt) + ch_rx_handle_version_neg(ch, ch->qrx_pkt); + + break; + default: assert(0); break; } } +static void ch_rx_handle_version_neg(QUIC_CHANNEL *ch, OSSL_QRX_PKT *pkt) +{ + /* + * We do not support version negotiation at this time. As per RFC 9000 s. + * 6.2., we MUST abandon the connection attempt if we receive a Version + * Negotiation packet, unless we have already successfully processed another + * incoming packet, or the packet lists the QUIC version we want to use. + */ + PACKET vpkt; + unsigned long v; + + if (!PACKET_buf_init(&vpkt, pkt->hdr->data, pkt->hdr->len)) + return; + + while (PACKET_remaining(&vpkt) > 0) { + if (!PACKET_get_net_4(&vpkt, &v)) + break; + + if ((uint32_t)v == QUIC_VERSION_1) + return; + } + + /* No match, this is a failure case. */ + ch_raise_version_neg_failure(ch); +} + +static void ch_raise_version_neg_failure(QUIC_CHANNEL *ch) +{ + QUIC_TERMINATE_CAUSE tcause = {0}; + + tcause.error_code = QUIC_ERR_CONNECTION_REFUSED; + tcause.reason = "version negotiation failure"; + tcause.reason_len = strlen(tcause.reason); + + /* + * Skip TERMINATING state; this is not considered a protocol error and we do + * not send CONNECTION_CLOSE. + */ + ch_start_terminating(ch, &tcause, 1); +} + /* * This is called by the demux when we get a packet not destined for any known * DCID. diff --git a/ssl/quic/quic_channel_local.h b/ssl/quic/quic_channel_local.h index ff861f18c7..8cef137255 100644 --- a/ssl/quic/quic_channel_local.h +++ b/ssl/quic/quic_channel_local.h @@ -305,6 +305,13 @@ struct quic_channel_st { unsigned int have_received_enc_pkt : 1; /* + * Have we successfully processed any packet, including a Version + * Negotiation packet? If so, further Version Negotiation packets should be + * ignored. + */ + unsigned int have_processed_any_pkt : 1; + + /* * Have we sent literally any packet yet? If not, there is no point polling * RX. */ diff --git a/ssl/quic/quic_wire_pkt.c b/ssl/quic/quic_wire_pkt.c index bd218b2361..069f0c8fa5 100644 --- a/ssl/quic/quic_wire_pkt.c +++ b/ssl/quic/quic_wire_pkt.c @@ -306,6 +306,13 @@ int ossl_quic_wire_decode_pkt_hdr(PACKET *pkt, hdr->data = PACKET_data(pkt); hdr->len = PACKET_remaining(pkt); + /* + * Version negotiation packets must contain an array of u32s, so it + * is invalid for their payload length to not be divisible by 4. + */ + if ((hdr->len % 4) != 0) + return 0; + /* Version negotiation packets are always fully decoded. */ hdr->partial = 0; |