* secret_len is the length of the secret buffer in bytes. The buffer must be
* sized correctly to the chosen suite, else the function fails.
*
- * This function can only be called once for a given EL. Subsequent calls fail,
- * as do calls made after a corresponding call to ossl_qrx_discard_enc_level for
- * that EL. The secret for a EL cannot be changed after it is set because QUIC
- * has no facility for introducing additional key material after an EL is setup.
- * QUIC key updates are managed semi-automatically by the QRX but do require
- * some caller handling (see below).
+ * This function can only be called once for a given EL, except for the INITIAL
+ * EL, which can need rekeying when a connection retry occurs. Subsequent calls
+ * for non-INITIAL ELs fail, as do calls made after a corresponding call to
+ * ossl_qrx_discard_enc_level for that EL. The secret for a non-INITIAL EL
+ * cannot be changed after it is set because QUIC has no facility for
+ * introducing additional key material after an EL is setup. QUIC key updates
+ * are managed semi-automatically by the QRX but do require some caller handling
+ * (see below).
*
* md is for internal use and should be NULL.
*
* secret_len is the length of the secret buffer in bytes. The buffer must be
* sized correctly to the chosen suite, else the function fails.
*
- * This function can only be called once for a given EL. Subsequent calls fail,
- * as do calls made after a corresponding call to ossl_qtx_discard_enc_level for
- * that EL. The secret for a EL cannot be changed after it is set because QUIC
- * has no facility for introducing additional key material after an EL is setup.
- * (QUIC key updates generate new keys from existing key material and do not
- * introduce new entropy into a connection's key material.)
+ * This function can only be called once for a given EL, except for the INITIAL
+ * EL, as the INITIAL EL can need to be rekeyed if connection retry occurs.
+ * Subsequent calls for non-INITIAL ELs fail. Calls made after a corresponding
+ * call to ossl_qtx_discard_enc_level for a given EL also fail, including for
+ * the INITIAL EL. The secret for a non-INITIAL EL cannot be changed after it is
+ * set because QUIC has no facility for introducing additional key material
+ * after an EL is setup. (QUIC key updates generate new keys from existing key
+ * material and do not introduce new entropy into a connection's key material.)
*
* Returns 1 on success or 0 on failure.
*/
const char *md_name = ossl_qrl_get_suite_md_name(suite_id);
size_t hpr_key_len, init_keyslot;
- if (el == NULL || el->state != QRL_EL_STATE_UNPROV || md_name == NULL
- || init_key_phase_bit > 1 || is_tx < 0 || is_tx > 1)
+ if (el == NULL
+ || md_name == NULL
+ || init_key_phase_bit > 1 || is_tx < 0 || is_tx > 1
+ || (init_key_phase_bit > 0 && enc_level != QUIC_ENC_LEVEL_1RTT))
return 0;
+ if (enc_level == QUIC_ENC_LEVEL_INITIAL
+ && el->state == QRL_EL_STATE_PROV_NORMAL) {
+ /*
+ * Sometimes the INITIAL EL needs to be reprovisioned, namely if a
+ * connection retry occurs. Exceptionally, if the caller wants to
+ * reprovision the INITIAL EL, tear it down as usual and then override
+ * the state so it can be provisioned again.
+ */
+ ossl_qrl_enc_level_set_discard(els, enc_level);
+ el->state = QRL_EL_STATE_UNPROV;
+ }
+
+ if (el->state != QRL_EL_STATE_UNPROV)
+ return 0;
+
+
+
init_keyslot = is_tx ? 0 : init_key_phase_bit;
hpr_key_len = ossl_qrl_get_suite_hdr_prot_key_len(suite_id);
if (hpr_key_len == 0)