uint64_t ossl_qrx_get_bytes_received(OSSL_QRX *qrx, int clear);
/*
- * Sets a callback which is called when a packet is received and being
- * validated before being queued in the read queue. This is called before packet
- * body decryption. pn_space is a QUIC_PN_SPACE_* value denoting which PN space
- * the PN belongs to.
+ * Sets a callback which is called when a packet is received and being validated
+ * before being queued in the read queue. This is called after packet body
+ * decryption and authentication to prevent exposing side channels. pn_space is
+ * a QUIC_PN_SPACE_* value denoting which PN space the PN belongs to.
*
* If this callback returns 1, processing continues normally.
* If this callback returns 0, the packet is discarded.
*
* Other packets in the same datagram will still be processed where possible.
*
- * The intended use for this function is to allow early validation of whether
- * a PN is a potential duplicate before spending CPU time decrypting the
- * packet payload.
+ * The intended use for this function is to allow validation of whether a PN is
+ * a potential duplicate before spending CPU time decrypting the packet payload.
*
* The callback is optional and can be unset by passing NULL for cb.
* cb_arg is an opaque value passed to cb.
*/
-typedef int (ossl_qrx_early_validation_cb)(QUIC_PN pn, int pn_space,
- void *arg);
+typedef int (ossl_qrx_late_validation_cb)(QUIC_PN pn, int pn_space,
+ void *arg);
-int ossl_qrx_set_early_validation_cb(OSSL_QRX *qrx,
- ossl_qrx_early_validation_cb *cb,
- void *cb_arg);
+int ossl_qrx_set_late_validation_cb(OSSL_QRX *qrx,
+ ossl_qrx_late_validation_cb *cb,
+ void *cb_arg);
/*
* Forcibly injects a URXE which has been issued by the DEMUX into the QRX for
size_t *consumed, void *arg);
static OSSL_TIME get_time(void *arg);
static uint64_t get_stream_limit(int uni, void *arg);
-static int rx_early_validate(QUIC_PN pn, int pn_space, void *arg);
+static int rx_late_validate(QUIC_PN pn, int pn_space, void *arg);
static void rxku_detected(QUIC_PN pn, void *arg);
static int ch_retry(QUIC_CHANNEL *ch,
const unsigned char *retry_token,
if ((ch->qrx = ossl_qrx_new(&qrx_args)) == NULL)
goto err;
- if (!ossl_qrx_set_early_validation_cb(ch->qrx,
- rx_early_validate,
- ch))
+ if (!ossl_qrx_set_late_validation_cb(ch->qrx,
+ rx_late_validate,
+ ch))
goto err;
if (!ossl_qrx_set_key_update_cb(ch->qrx,
* Called by QRX to determine if a packet is potentially invalid before trying
* to decrypt it.
*/
-static int rx_early_validate(QUIC_PN pn, int pn_space, void *arg)
+static int rx_late_validate(QUIC_PN pn, int pn_space, void *arg)
{
QUIC_CHANNEL *ch = arg;
uint64_t forged_pkt_count;
/* Validation callback. */
- ossl_qrx_early_validation_cb *validation_cb;
+ ossl_qrx_late_validation_cb *validation_cb;
void *validation_cb_arg;
/* Key update callback. */
&rxe->pn))
return 0;
+ return 1;
+}
+
+/* Late packet header validation. */
+static int qrx_validate_hdr_late(OSSL_QRX *qrx, RXE *rxe)
+{
+ int pn_space = rxe_determine_pn_space(rxe);
+
/*
* Allow our user to decide whether to discard the packet before we try and
* decrypt it.
* -----------------------------------------------------
*
* At this point, we have successfully authenticated the AEAD tag and no
- * longer need to worry about exposing the Key Phase bit in timing channels.
- * Check for a Key Phase bit differing from our expectation.
+ * longer need to worry about exposing the PN, PN length or Key Phase bit in
+ * timing channels. Invoke any configured validation callback to allow for
+ * rejection of duplicate PNs.
*/
+ if (!qrx_validate_hdr_late(qrx, rxe))
+ goto malformed;
+
+ /* Check for a Key Phase bit differing from our expectation. */
if (rxe->hdr.type == QUIC_PKT_TYPE_1RTT
&& rxe->hdr.key_phase != (el->key_epoch & 1))
qrx_key_update_initiated(qrx, rxe->pn);
return v;
}
-int ossl_qrx_set_early_validation_cb(OSSL_QRX *qrx,
- ossl_qrx_early_validation_cb *cb,
- void *cb_arg)
+int ossl_qrx_set_late_validation_cb(OSSL_QRX *qrx,
+ ossl_qrx_late_validation_cb *cb,
+ void *cb_arg)
{
qrx->validation_cb = cb;
qrx->validation_cb_arg = cb_arg;