1 /* 2 * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #ifndef OSSL_INTERNAL_QUIC_LCIDM_H 11 # define OSSL_INTERNAL_QUIC_LCIDM_H 12 # pragma once 13 14 # include "internal/e_os.h" 15 # include "internal/time.h" 16 # include "internal/quic_types.h" 17 # include "internal/quic_wire.h" 18 # include "internal/quic_predef.h" 19 20 # ifndef OPENSSL_NO_QUIC 21 22 /* 23 * QUIC Local Connection ID Manager 24 * ================================ 25 * 26 * This manages connection IDs for the RX side, which is to say that it issues 27 * local CIDs (LCIDs) to a peer which that peer can then use to address us via a 28 * packet DCID. This is as opposed to CID management for the TX side, which 29 * determines which CIDs we use to transmit based on remote CIDs (RCIDs) the 30 * peer sent to us. 31 * 32 * An opaque pointer can be associated with each LCID. Pointer identity 33 * (equality) is used to distinguish distinct connections. 34 * 35 * LCIDs fall into three categories: 36 * 37 * 1. A client's Initial ODCID (1) 38 * 2. Our local Initial SCID (1) 39 * 3. A CID issued via a NEW_CONNECTION_ID frame (n) 40 * 4. A server's Retry SCID (0..1) 41 * 42 * (1) is enrolled using ossl_quic_lcidm_enrol_odcid() and retired by the time 43 * of handshake completion at the latest. It is needed in case the first 44 * response packet from a server is lost and the client keeps using its Initial 45 * ODCID. There is never more than one of these, and no sequence number is 46 * associated with this temporary LCID. 47 * 48 * (2) is created by a client when it begins connecting, or by a server when it 49 * responds to a new connection request. In the latter case, it is generated by 50 * the server as the preferred DCID for traffic directed towards it. A client 51 * should switch to using this as a RCID as soon as it receives a valid packet 52 * from the server. This LCID has a sequence number of 0. 53 * 54 * (3) is created when we issue a NEW_CONNECTION_ID frame. Arbitrarily many of 55 * these can exist. 56 * 57 * (4) is a special case. When a server issues a retry it generates a new SCID 58 * much as it does for (2). However since retries are supposed to be stateless, 59 * we don't actually register it as an LCID. When the client subsequently 60 * replies with an Initial packet with token in response to the Retry, the 61 * server will handle this as a new connection attempt due to not recognising 62 * the DCID, which is what we want anyway. (The Retry SCID is subsequently 63 * validated as matching the new Initial ODCID via attestation in the encrypted 64 * contents of the opaque retry token.) Thus, the LCIDM is not actually involved 65 * at all here. 66 * 67 * Retirement is as follows: 68 * 69 * (1) is retired automatically when we know it won't be needed anymore. This is 70 * when the handshake is completed at the latest, and could potentially be 71 * earlier. 72 * 73 * Both (2) and (3) are retired normally via RETIRE_CONNECTION_ID frames, as it 74 * has a sequence number of 0. 75 * 76 * 77 * ODCID Peculiarities 78 * ------------------- 79 * 80 * Almost all LCIDs are issued by the receiver responsible for routing them, 81 * which means that almost all LCIDs will have the same length (specified in 82 * lcid_len below). The only exception to this is (1); the ODCID is the only 83 * case where we recognise an LCID we didn't ourselves generate. Since an ODCID 84 * is chosen by the peer, it can be any length and doesn't necessarily match the 85 * length we use for LCIDs we generate ourselves. 86 * 87 * Since DCID decoding for short-header packets requires an implicitly known 88 * DCID length, it logically follows that an ODCID can never be used in a 1-RTT 89 * packet. This is fine as by the time the 1-RTT EL is reached the peer should 90 * already have switched away from the ODCID to a CID we generated ourselves, 91 * and if this has not happened we can consider that a protocol violation. 92 * 93 * In any case, this means that the LCIDM must necessarily support LCIDs of 94 * different lengths, even if it always generates LCIDs of a given length. 95 * 96 * An ODCID has no sequence number associated with it. It is the only CID to 97 * lack one. 98 */ 99 100 /* 101 * Creates a new LCIDM. lcid_len is the length to use for LCIDs in bytes, which 102 * may be zero. 103 * 104 * Returns NULL on failure. 105 */ 106 QUIC_LCIDM *ossl_quic_lcidm_new(OSSL_LIB_CTX *libctx, size_t lcid_len); 107 108 /* Frees a LCIDM. */ 109 void ossl_quic_lcidm_free(QUIC_LCIDM *lcidm); 110 111 /* Gets the local CID length this LCIDM was configured to use. */ 112 size_t ossl_quic_lcidm_get_lcid_len(const QUIC_LCIDM *lcidm); 113 114 /* 115 * Determines the number of active LCIDs (i.e,. LCIDs which can be used for 116 * reception) currently associated with the given opaque pointer. 117 */ 118 size_t ossl_quic_lcidm_get_num_active_lcid(const QUIC_LCIDM *lcidm, 119 void *opaque); 120 121 /* 122 * Enrol an Initial ODCID sent by the peer. This is the DCID in the first 123 * Initial packet sent by a client. When we receive a client's first Initial 124 * packet, we immediately respond with our own SCID (generated using 125 * ossl_quic_lcidm_generate_initial) to tell the client to switch to using that, 126 * so ideally the ODCID will only be used for a single packet. However since 127 * that response might be lost, we also need to accept additional packets using 128 * the ODCID and need to make sure they get routed to the same connection and 129 * not interpreted as another new connection attempt. Thus before the CID 130 * switchover is confirmed, we also have to handle incoming packets addressed to 131 * the ODCID. This function is used to temporarily enroll the ODCID for a 132 * connection. Such a LCID is considered to have a sequence number of 133 * LCIDM_ODCID_SEQ_NUM internally for our purposes. 134 * 135 * Note that this is the *only* circumstance where we recognise an LCID we did 136 * not generate ourselves, or allow an LCID with a different length to lcid_len. 137 * 138 * An ODCID MUST be at least 8 bytes in length (RFC 9000 s. 7.2). 139 * 140 * This function may only be called once for a given connection. 141 * Returns 1 on success or 0 on failure. 142 */ 143 int ossl_quic_lcidm_enrol_odcid(QUIC_LCIDM *lcidm, void *opaque, 144 const QUIC_CONN_ID *initial_odcid); 145 146 /* 147 * Retire a previously enrolled ODCID for a connection. This is generally done 148 * when we know the peer won't be using it any more (when the handshake is 149 * completed at the absolute latest, possibly earlier). 150 * 151 * Returns 1 if there was an enrolled ODCID which was retired and 0 if there was 152 * not or on other failure. 153 */ 154 int ossl_quic_lcidm_retire_odcid(QUIC_LCIDM *lcidm, void *opaque); 155 156 /* 157 * Create the first LCID for a given opaque pointer. The generated LCID is 158 * written to *initial_lcid and associated with the given opaque pointer. 159 * 160 * After this function returns successfully, the caller can for example 161 * register the new LCID with a DEMUX. 162 * 163 * May not be called more than once for a given opaque pointer value. 164 */ 165 int ossl_quic_lcidm_generate_initial(QUIC_LCIDM *lcidm, 166 void *opaque, 167 QUIC_CONN_ID *initial_lcid); 168 169 /* 170 * Create a subsequent LCID for a given opaque pointer. The information needed 171 * for a NEW_CONN_ID frame informing the peer of the new LCID, including the 172 * LCID itself, is written to *ncid_frame. 173 * 174 * ncid_frame->stateless_reset is not initialised and the caller is responsible 175 * for setting it. 176 * 177 * After this function returns successfully, the caller can for example 178 * register the new LCID with a DEMUX and queue the NEW_CONN_ID frame. 179 */ 180 int ossl_quic_lcidm_generate(QUIC_LCIDM *lcidm, 181 void *opaque, 182 OSSL_QUIC_FRAME_NEW_CONN_ID *ncid_frame); 183 184 /* 185 * Retire up to one LCID for a given opaque pointer value. Called repeatedly to 186 * handle a RETIRE_CONN_ID frame. 187 * 188 * If containing_pkt_dcid is non-NULL, this function enforces the requirement 189 * that a CID not be retired by a packet using that CID as the DCID. If 190 * containing_pkt_dcid is NULL, this check is skipped. 191 * 192 * If a LCID is retired as a result of a call to this function, the LCID which 193 * was retired is written to *retired_lcid, the sequence number of the LCID is 194 * written to *retired_seq_num and *did_retire is set to 1. Otherwise, 195 * *did_retire is set to 0. This enables a caller to e.g. unregister the LCID 196 * from a DEMUX. A caller should call this function repeatedly until the 197 * function returns with *did_retire set to 0. 198 * 199 * This call is likely to cause the value returned by 200 * ossl_quic_lcidm_get_num_active_lcid() to go down. A caller may wish to call 201 * ossl_quic_lcidm_generate() repeatedly to bring the number of active LCIDs 202 * back up to some threshold in response after calling this function. 203 * 204 * Returns 1 on success and 0 on failure. If arguments are valid but zero LCIDs 205 * are retired, this is considered a success condition. 206 */ 207 int ossl_quic_lcidm_retire(QUIC_LCIDM *lcidm, 208 void *opaque, 209 uint64_t retire_prior_to, 210 const QUIC_CONN_ID *containing_pkt_dcid, 211 QUIC_CONN_ID *retired_lcid, 212 uint64_t *retired_seq_num, 213 int *did_retire); 214 215 /* 216 * Cull all LCIDM state relating to a given opaque pointer value. This is useful 217 * if connection state is spontaneously freed. The caller is responsible for 218 * e.g. DEMUX state updates. 219 */ 220 int ossl_quic_lcidm_cull(QUIC_LCIDM *lcidm, void *opaque); 221 222 /* 223 * Lookup a LCID. If the LCID is found, writes the associated opaque pointer to 224 * *opaque and the associated sequence number to *seq_num. Returns 1 on success 225 * and 0 if an entry is not found. An output argument may be set to NULL if its 226 * value is not required. 227 * 228 * If the LCID is for an Initial ODCID, *seq_num is set to 229 * LCIDM_ODCID_SEQ_NUM. 230 */ 231 #define LCIDM_ODCID_SEQ_NUM UINT64_MAX 232 233 int ossl_quic_lcidm_lookup(QUIC_LCIDM *lcidm, 234 const QUIC_CONN_ID *lcid, 235 uint64_t *seq_num, 236 void **opaque); 237 238 /* 239 * Debug call to manually remove a specific LCID. Should not be needed in normal 240 * usage. Returns 1 if the LCID was successfully found and removed and 0 241 * otherwise. 242 */ 243 int ossl_quic_lcidm_debug_remove(QUIC_LCIDM *lcidm, 244 const QUIC_CONN_ID *lcid); 245 246 /* 247 * Debug call to manually add a numbered LCID with a specific CID value and 248 * sequence number. Should not be needed in normal usage. Returns 1 on success 249 * and 0 on failure. 250 */ 251 int ossl_quic_lcidm_debug_add(QUIC_LCIDM *lcidm, void *opaque, 252 const QUIC_CONN_ID *lcid, 253 uint64_t seq_num); 254 255 # endif 256 257 #endif 258