]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Generate initial packet keys based on new dcid for addr validation
authorNeil Horman <nhorman@openssl.org>
Tue, 5 Nov 2024 21:25:25 +0000 (16:25 -0500)
committerNeil Horman <nhorman@openssl.org>
Mon, 17 Feb 2025 16:27:33 +0000 (11:27 -0500)
When using retry packets in QUIC to implement address validation, the
2nd inital packet that arrives after the server sends the retry frame
will have its CRYPTO packet encrypted using keys derived from the new
dcid, rather than the dcid in the 1st initial packet.  Update the
channel creation code to update those keys on the server so that the
CRYPTO packet is decrypted successfully

Reviewed-by: Saša Nedvědický <sashan@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/25890)

ssl/quic/quic_channel.c

index 49ae84d2cd1612694833493635527be570c3452c..23edb1a635fa9d229ddcf017a2f5217dd339fc29 100644 (file)
@@ -3409,11 +3409,14 @@ static void ch_on_idle_timeout(QUIC_CHANNEL *ch)
  * @param peer     Address of the peer to which the channel connects.
  * @param peer_scid Peer-specified source connection ID.
  * @param peer_dcid Peer-specified destination connection ID.
+ * @param peer_odcid Peer-specified original destination connection ID
+ *                   may be NULL if retry frame not sent to client
  * @return         1 on success, 0 on failure to set required elements.
  */
 static int ch_on_new_conn_common(QUIC_CHANNEL *ch, const BIO_ADDR *peer,
                                  const QUIC_CONN_ID *peer_scid,
-                                 const QUIC_CONN_ID *peer_dcid)
+                                 const QUIC_CONN_ID *peer_dcid,
+                                 const QUIC_CONN_ID *peer_odcid)
 {
     /* Note our newly learnt peer address and CIDs. */
     ch->cur_peer_addr   = *peer;
@@ -3444,7 +3447,9 @@ static int ch_on_new_conn_common(QUIC_CHANNEL *ch, const BIO_ADDR *peer,
         return 0;
 
     /* Register the peer ODCID in the LCIDM. */
-    if (!ossl_quic_lcidm_enrol_odcid(ch->lcidm, ch, &ch->init_dcid))
+    if (!ossl_quic_lcidm_enrol_odcid(ch->lcidm, ch, peer_odcid == NULL ?
+                                                    &ch->init_dcid :
+                                                    peer_odcid))
         return 0;
 
     /* Change state. */
@@ -3465,9 +3470,32 @@ int ossl_quic_channel_on_new_conn(QUIC_CHANNEL *ch, const BIO_ADDR *peer,
     if (!ossl_quic_lcidm_generate_initial(ch->lcidm, ch, &ch->cur_local_cid))
         return 0;
 
-    return ch_on_new_conn_common(ch, peer, peer_scid, peer_dcid);
+    return ch_on_new_conn_common(ch, peer, peer_scid, peer_dcid, NULL);
 }
 
+/**
+ * Binds a QUIC channel to a specific peer's address and connection IDs.
+ *
+ * This function is used to establish a binding between a QUIC channel and a
+ * peer's address and connection IDs. The binding is performed only if the
+ * channel is idle and is on the server side. The peer's destination connection
+ * ID (`peer_dcid`) is mandatory, and the channel's current local connection ID
+ * is set to this value.
+ *
+ * @param ch          Pointer to the QUIC_CHANNEL structure representing the
+ *                    channel to be bound.
+ * @param peer        Pointer to a BIO_ADDR structure representing the peer's
+ *                    address.
+ * @param peer_scid   Pointer to the peer's source connection ID (QUIC_CONN_ID).
+ * @param peer_dcid   Pointer to the peer's destination connection ID
+ *                    (QUIC_CONN_ID). This must not be NULL.
+ * @param peer_odcid  Pointer to the original destination connection ID
+ *                    (QUIC_CONN_ID) chosen by the peer in its first initial
+ *                    packet received without a token.
+ *
+ * @return 1 on success, or 0 on failure if the conditions for binding are not
+ *         met (e.g., channel is not idle or not a server, or binding fails).
+ */
 int ossl_quic_bind_channel(QUIC_CHANNEL *ch, const BIO_ADDR *peer,
                            const QUIC_CONN_ID *peer_scid,
                            const QUIC_CONN_ID *peer_dcid,
@@ -3487,7 +3515,7 @@ int ossl_quic_bind_channel(QUIC_CHANNEL *ch, const BIO_ADDR *peer,
      * peer_odcid <=> is initial dst conn id chosen by peer in its
      * first initial packet we received without token.
      */
-    return ch_on_new_conn_common(ch, peer, peer_scid, peer_odcid);
+    return ch_on_new_conn_common(ch, peer, peer_scid, peer_dcid, peer_odcid);
 }
 
 SSL *ossl_quic_channel_get0_ssl(QUIC_CHANNEL *ch)