Skip to content

Commit

Permalink
QUIC RXDP: Strictly enforce ACK PNs with regard to TX key epochs
Browse files Browse the repository at this point in the history
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from #21029)
  • Loading branch information
hlandau authored and paulidale committed Jun 15, 2023
1 parent 54fb007 commit c93f766
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 7 deletions.
1 change: 1 addition & 0 deletions ssl/quic/quic_channel.c
Expand Up @@ -691,6 +691,7 @@ static void rxku_detected(QUIC_PN pn, void *arg)
ch->rxku_pending_confirm = 1;
ch->rxku_trigger_pn = pn;
ch->rxku_update_end_deadline = ossl_time_add(get_time(ch), pto);
ch->rxku_expected = 0;

if (decision == DECISION_SOLICITED_TXKU)
/* NOT gated by usual txku_allowed() */
Expand Down
15 changes: 10 additions & 5 deletions ssl/quic/quic_channel_local.h
Expand Up @@ -228,11 +228,11 @@ struct quic_channel_st {
OSSL_TIME rxku_update_end_deadline;

/*
* The first (application space) PN sent with a new key phase. Valid if
* txku_in_progress. Once a packet we sent with a PN p (p >= txku_pn) is
* ACKed, the TXKU is considered completed and txku_in_progress becomes 0.
* For sanity's sake, such a PN p should also be <= the highest PN we have
* ever sent, of course.
* The first (application space) PN sent with a new key phase. Valid if the
* QTX key epoch is greater than 0. Once a packet we sent with a PN p (p >=
* txku_pn) is ACKed, the TXKU is considered completed and txku_in_progress
* becomes 0. For sanity's sake, such a PN p should also be <= the highest
* PN we have ever sent, of course.
*/
QUIC_PN txku_pn;

Expand Down Expand Up @@ -386,6 +386,11 @@ struct quic_channel_st {

/* Temporary variable indicating rxku_pending_confirm is to become 0. */
unsigned int rxku_pending_confirm_done : 1;

/*
* If set, RXKU is expected (because we initiated a spontaneous TXKU).
*/
unsigned int rxku_expected : 1;
};

# endif
Expand Down
39 changes: 37 additions & 2 deletions ssl/quic/quic_rx_depack.c
Expand Up @@ -60,7 +60,8 @@ static int depack_do_frame_ping(PACKET *pkt, QUIC_CHANNEL *ch,

static int depack_do_frame_ack(PACKET *pkt, QUIC_CHANNEL *ch,
int packet_space, OSSL_TIME received,
uint64_t frame_type)
uint64_t frame_type,
OSSL_QRX_PKT *qpacket)
{
OSSL_QUIC_FRAME_ACK ack;
OSSL_QUIC_ACK_RANGE *ack_ranges = NULL;
Expand All @@ -80,6 +81,40 @@ static int depack_do_frame_ack(PACKET *pkt, QUIC_CHANNEL *ch,
if (!ossl_quic_wire_decode_frame_ack(pkt, ack_delay_exp, &ack, NULL))
goto malformed;

if (qpacket->hdr->type == QUIC_PKT_TYPE_1RTT
&& (qpacket->key_epoch < ossl_qrx_get_key_epoch(ch->qrx)
|| ch->rxku_expected)
&& ack.ack_ranges[0].end >= ch->txku_pn) {
/*
* RFC 9001 s. 6.2: An endpoint that receives an acknowledgment that is
* carried in a packet protected with old keys where any acknowledged
* packet was protected with newer keys MAY treat that as a connection
* error of type KEY_UPDATE_ERROR.
*
* Two cases to handle here:
*
* - We did spontaneous TXKU, the peer has responded in kind and we
* have detected RXKU; !ch->rxku_expected, but then it sent a packet
* with old keys acknowledging a packet in the new key epoch.
*
* This also covers the case where we got RXKU and triggered
* solicited TXKU, and then for some reason the peer sent an ACK of
* a PN in our new TX key epoch with old keys.
*
* - We did spontaneous TXKU; ch->txku_pn is the starting PN of our
* new TX key epoch; the peer has not initiated a solicited TXKU in
* response (so we have not detected RXKU); in this case the RX key
* epoch has not incremented and ch->rxku_expected is still 1.
*/
ossl_quic_channel_raise_protocol_error(ch,
QUIC_ERR_KEY_UPDATE_ERROR,
frame_type,
"acked packet which initiated a "
"key update without a "
"corresponding key update");
return 0;
}

if (!ossl_ackm_on_rx_ack_frame(ch->ackm, &ack,
packet_space, received))
goto malformed;
Expand Down Expand Up @@ -837,7 +872,7 @@ static int depack_process_frames(QUIC_CHANNEL *ch, PACKET *pkt,
return 0;
}
if (!depack_do_frame_ack(pkt, ch, packet_space, received,
frame_type))
frame_type, parent_pkt))
return 0;
break;

Expand Down

0 comments on commit c93f766

Please sign in to comment.