1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 25392f7a3SLiteSpeed Tech/* 35392f7a3SLiteSpeed Tech * Parsing routines shared by all IETF QUIC versions. 45392f7a3SLiteSpeed Tech */ 55392f7a3SLiteSpeed Tech 65392f7a3SLiteSpeed Tech#include <assert.h> 79626cfc2SDmitri Tikhonov#include <stddef.h> 89626cfc2SDmitri Tikhonov#include <stdint.h> 99626cfc2SDmitri Tikhonov#include <string.h> 109626cfc2SDmitri Tikhonov#include <sys/queue.h> 119626cfc2SDmitri Tikhonov#include <sys/types.h> 129626cfc2SDmitri Tikhonov 139626cfc2SDmitri Tikhonov#include <openssl/rand.h> 149626cfc2SDmitri Tikhonov 159626cfc2SDmitri Tikhonov#include "lsquic_types.h" 169626cfc2SDmitri Tikhonov#include "lsquic_int_types.h" 179626cfc2SDmitri Tikhonov#include "lsquic_packet_common.h" 189626cfc2SDmitri Tikhonov#include "lsquic_packet_in.h" 199626cfc2SDmitri Tikhonov#include "lsquic_parse_common.h" 209626cfc2SDmitri Tikhonov#include "lsquic_parse.h" 219626cfc2SDmitri Tikhonov#include "lsquic_version.h" 229626cfc2SDmitri Tikhonov#include "lsquic.h" 239626cfc2SDmitri Tikhonov#include "lsquic_logger.h" 249626cfc2SDmitri Tikhonov#include "lsquic_byteswap.h" 255392f7a3SLiteSpeed Tech#include "lsquic_varint.h" 265392f7a3SLiteSpeed Tech#include "lsquic_enc_sess.h" 275392f7a3SLiteSpeed Tech#include "lsquic_tokgen.h" 285392f7a3SLiteSpeed Tech#include "lsquic_mm.h" 295392f7a3SLiteSpeed Tech#include "lsquic_engine_public.h" 309fc12041SDmitri Tikhonov#include "lsquic_ietf.h" 319626cfc2SDmitri Tikhonov 329626cfc2SDmitri Tikhonov 33c7d81ce1SDmitri Tikhonov/* [draft-ietf-quic-transport-17] Section-17.2 */ 34c7d81ce1SDmitri Tikhonovstatic const enum header_type bits2ht[4] = 35c7d81ce1SDmitri Tikhonov{ 36c7d81ce1SDmitri Tikhonov [0] = HETY_INITIAL, 37c7d81ce1SDmitri Tikhonov [1] = HETY_0RTT, 38c7d81ce1SDmitri Tikhonov [2] = HETY_HANDSHAKE, 39c7d81ce1SDmitri Tikhonov [3] = HETY_RETRY, 40c7d81ce1SDmitri Tikhonov}; 41c7d81ce1SDmitri Tikhonov 42c7d81ce1SDmitri Tikhonov 439626cfc2SDmitri Tikhonovint 445392f7a3SLiteSpeed Techlsquic_Q046_parse_packet_in_long_begin (struct lsquic_packet_in *packet_in, 455392f7a3SLiteSpeed Tech size_t length, int is_server, unsigned cid_len, 465392f7a3SLiteSpeed Tech struct packin_parse_state *state) 479626cfc2SDmitri Tikhonov{ 489626cfc2SDmitri Tikhonov const unsigned char *p = packet_in->pi_data; 499626cfc2SDmitri Tikhonov const unsigned char *const end = p + length; 509626cfc2SDmitri Tikhonov lsquic_ver_tag_t tag; 519626cfc2SDmitri Tikhonov enum header_type header_type; 52c7d81ce1SDmitri Tikhonov unsigned dcil, scil, packet_len; 539626cfc2SDmitri Tikhonov int verneg; 549626cfc2SDmitri Tikhonov unsigned char first_byte; 555392f7a3SLiteSpeed Tech lsquic_packno_t packno; 569626cfc2SDmitri Tikhonov 579626cfc2SDmitri Tikhonov if (length < 6) 589626cfc2SDmitri Tikhonov return -1; 599626cfc2SDmitri Tikhonov first_byte = *p++; 609626cfc2SDmitri Tikhonov 619626cfc2SDmitri Tikhonov memcpy(&tag, p, 4); 629626cfc2SDmitri Tikhonov p += 4; 639626cfc2SDmitri Tikhonov verneg = 0 == tag; 649626cfc2SDmitri Tikhonov if (!verneg) 655392f7a3SLiteSpeed Tech header_type = bits2ht[ (first_byte >> 4) & 3 ]; 669626cfc2SDmitri Tikhonov else 679626cfc2SDmitri Tikhonov header_type = HETY_VERNEG; 689626cfc2SDmitri Tikhonov 699626cfc2SDmitri Tikhonov packet_in->pi_header_type = header_type; 709626cfc2SDmitri Tikhonov 719626cfc2SDmitri Tikhonov dcil = p[0] >> 4; 729626cfc2SDmitri Tikhonov if (dcil) 739626cfc2SDmitri Tikhonov dcil += 3; 749626cfc2SDmitri Tikhonov scil = p[0] & 0xF; 759626cfc2SDmitri Tikhonov if (scil) 769626cfc2SDmitri Tikhonov scil += 3; 779626cfc2SDmitri Tikhonov ++p; 789626cfc2SDmitri Tikhonov 799626cfc2SDmitri Tikhonov /* Chromium comments state that the client sends packets with destination 809626cfc2SDmitri Tikhonov * CID of 8 bytes and source CID of 0 bytes and the server does it the 819626cfc2SDmitri Tikhonov * other way around. 829626cfc2SDmitri Tikhonov */ 839626cfc2SDmitri Tikhonov if (is_server) 849626cfc2SDmitri Tikhonov { 859626cfc2SDmitri Tikhonov if (!(dcil == cid_len && scil == 0)) 869626cfc2SDmitri Tikhonov return -1; 879626cfc2SDmitri Tikhonov } 889626cfc2SDmitri Tikhonov else 895392f7a3SLiteSpeed Tech if (!(dcil == 0 && scil == cid_len)) 905392f7a3SLiteSpeed Tech return -1; 919626cfc2SDmitri Tikhonov 92c7d81ce1SDmitri Tikhonov if (!verneg) 93c7d81ce1SDmitri Tikhonov { 945392f7a3SLiteSpeed Tech packet_in->pi_flags |= (first_byte & 3) << PIBIT_BITS_SHIFT; 955392f7a3SLiteSpeed Tech packet_len = 1 + (first_byte & 3); 96c7d81ce1SDmitri Tikhonov if (end - p < (ptrdiff_t) (dcil + scil + packet_len)) 97c7d81ce1SDmitri Tikhonov return -1; 98c7d81ce1SDmitri Tikhonov } 99c7d81ce1SDmitri Tikhonov else 100c7d81ce1SDmitri Tikhonov { 101c7d81ce1SDmitri Tikhonov /* Need at least one version in the version array: add 4 */ 102c7d81ce1SDmitri Tikhonov if (end - p < (ptrdiff_t) (dcil + scil + 4)) 103c7d81ce1SDmitri Tikhonov return -1; 104e5d4bc6dSDmitri Tikhonov#ifdef WIN32 105e5d4bc6dSDmitri Tikhonov /* Useless initialization: */ 106e5d4bc6dSDmitri Tikhonov packet_len = 0; 107e5d4bc6dSDmitri Tikhonov#endif 108c7d81ce1SDmitri Tikhonov } 1099626cfc2SDmitri Tikhonov 1105392f7a3SLiteSpeed Tech memcpy(&packet_in->pi_dcid.idbuf, p, cid_len); 1115392f7a3SLiteSpeed Tech packet_in->pi_dcid.len = cid_len; 1129626cfc2SDmitri Tikhonov p += cid_len; 1139626cfc2SDmitri Tikhonov packet_in->pi_flags |= PI_CONN_ID; 1149626cfc2SDmitri Tikhonov 1159626cfc2SDmitri Tikhonov if (!verneg) 1169626cfc2SDmitri Tikhonov { 1175392f7a3SLiteSpeed Tech READ_UINT(packno, 64, p, packet_len); 1185392f7a3SLiteSpeed Tech packet_in->pi_packno = packno; 1199626cfc2SDmitri Tikhonov p += packet_len; 1209626cfc2SDmitri Tikhonov packet_in->pi_quic_ver = 1; 1219626cfc2SDmitri Tikhonov if (is_server || HETY_0RTT != header_type) 1229626cfc2SDmitri Tikhonov packet_in->pi_nonce = 0; 1239626cfc2SDmitri Tikhonov else 1249626cfc2SDmitri Tikhonov { 1259626cfc2SDmitri Tikhonov packet_in->pi_nonce = p - packet_in->pi_data; 1269626cfc2SDmitri Tikhonov p += 32; 1279626cfc2SDmitri Tikhonov } 1289626cfc2SDmitri Tikhonov } 1299626cfc2SDmitri Tikhonov else 1309626cfc2SDmitri Tikhonov { 1315392f7a3SLiteSpeed Tech if (p >= end || (3 & (uintptr_t) (end - p))) 1329626cfc2SDmitri Tikhonov return -1; 1339626cfc2SDmitri Tikhonov packet_in->pi_quic_ver = p - packet_in->pi_data; 1345392f7a3SLiteSpeed Tech p = end; 1359626cfc2SDmitri Tikhonov } 1369626cfc2SDmitri Tikhonov 1379626cfc2SDmitri Tikhonov packet_in->pi_header_sz = p - packet_in->pi_data; 1389626cfc2SDmitri Tikhonov packet_in->pi_frame_types = 0; 1399626cfc2SDmitri Tikhonov packet_in->pi_data_sz = length; 1409626cfc2SDmitri Tikhonov packet_in->pi_refcnt = 0; 1419626cfc2SDmitri Tikhonov packet_in->pi_received = 0; 1429626cfc2SDmitri Tikhonov 1439626cfc2SDmitri Tikhonov return 0; 1449626cfc2SDmitri Tikhonov} 1459626cfc2SDmitri Tikhonov 1469626cfc2SDmitri Tikhonov 1479626cfc2SDmitri Tikhonovint 1485392f7a3SLiteSpeed Techlsquic_Q046_parse_packet_in_short_begin (lsquic_packet_in_t *packet_in, 1495392f7a3SLiteSpeed Tech size_t length, int is_server, unsigned cid_len, 1505392f7a3SLiteSpeed Tech struct packin_parse_state *state) 1519626cfc2SDmitri Tikhonov{ 1529626cfc2SDmitri Tikhonov const unsigned char *p = packet_in->pi_data; 1539626cfc2SDmitri Tikhonov const unsigned char *const pend = packet_in->pi_data + length; 1545392f7a3SLiteSpeed Tech unsigned packet_len, header_len; 1555392f7a3SLiteSpeed Tech lsquic_packno_t packno; 1569626cfc2SDmitri Tikhonov 157c7d81ce1SDmitri Tikhonov if (*p & 0x40) /* Q046 and higher */ 158c7d81ce1SDmitri Tikhonov packet_len = 1 + (*p & 3); 159c7d81ce1SDmitri Tikhonov else 1605392f7a3SLiteSpeed Tech return -1; 1615392f7a3SLiteSpeed Tech 1625392f7a3SLiteSpeed Tech if (is_server) 1635392f7a3SLiteSpeed Tech header_len = 1 + cid_len + packet_len; 1645392f7a3SLiteSpeed Tech else 1655392f7a3SLiteSpeed Tech header_len = 1 + packet_len; 1669626cfc2SDmitri Tikhonov 1675392f7a3SLiteSpeed Tech if (pend - p < (ptrdiff_t) header_len) 1689626cfc2SDmitri Tikhonov return -1; 1699626cfc2SDmitri Tikhonov 170c7d81ce1SDmitri Tikhonov packet_in->pi_flags |= (*p & 3) << PIBIT_BITS_SHIFT; 1719626cfc2SDmitri Tikhonov ++p; 1729626cfc2SDmitri Tikhonov if (is_server) 1739626cfc2SDmitri Tikhonov { 1745392f7a3SLiteSpeed Tech memcpy(packet_in->pi_dcid.idbuf, packet_in->pi_data + 1, cid_len); 1755392f7a3SLiteSpeed Tech packet_in->pi_dcid.len = cid_len; 176dee31d56SDmitri Tikhonov packet_in->pi_flags |= PI_CONN_ID; 1775392f7a3SLiteSpeed Tech p += cid_len; 1789626cfc2SDmitri Tikhonov } 1799626cfc2SDmitri Tikhonov 1805392f7a3SLiteSpeed Tech READ_UINT(packno, 64, p, packet_len); 1815392f7a3SLiteSpeed Tech packet_in->pi_packno = packno; 1829626cfc2SDmitri Tikhonov p += packet_len; 1839626cfc2SDmitri Tikhonov 1849626cfc2SDmitri Tikhonov packet_in->pi_header_type = HETY_NOT_SET; 1859626cfc2SDmitri Tikhonov packet_in->pi_quic_ver = 0; 1869626cfc2SDmitri Tikhonov packet_in->pi_nonce = 0; 1879626cfc2SDmitri Tikhonov packet_in->pi_header_sz = p - packet_in->pi_data; 1889626cfc2SDmitri Tikhonov packet_in->pi_frame_types = 0; 1899626cfc2SDmitri Tikhonov packet_in->pi_data_sz = length; 1909626cfc2SDmitri Tikhonov packet_in->pi_refcnt = 0; 1919626cfc2SDmitri Tikhonov packet_in->pi_received = 0; 1929626cfc2SDmitri Tikhonov 1939626cfc2SDmitri Tikhonov return 0; 1949626cfc2SDmitri Tikhonov} 1959626cfc2SDmitri Tikhonov 1969626cfc2SDmitri Tikhonov 1975392f7a3SLiteSpeed Tech/* This is a bare-bones version of lsquic_Q046_parse_packet_in_long_begin() 1985392f7a3SLiteSpeed Tech */ 1995392f7a3SLiteSpeed Techint 2005392f7a3SLiteSpeed Techlsquic_is_valid_iquic_hs_packet (const unsigned char *buf, size_t length, 2015392f7a3SLiteSpeed Tech lsquic_ver_tag_t *tagp) 2025392f7a3SLiteSpeed Tech{ 2035392f7a3SLiteSpeed Tech const unsigned char *p = buf; 2045392f7a3SLiteSpeed Tech const unsigned char *const end = p + length; 2055392f7a3SLiteSpeed Tech lsquic_ver_tag_t tag; 2065392f7a3SLiteSpeed Tech unsigned dcil, scil, packet_len; 2075392f7a3SLiteSpeed Tech unsigned char first_byte; 2085392f7a3SLiteSpeed Tech const unsigned cid_len = 8; 2095392f7a3SLiteSpeed Tech 2105392f7a3SLiteSpeed Tech if (length < 6) 2115392f7a3SLiteSpeed Tech return 0; 2125392f7a3SLiteSpeed Tech first_byte = *p++; 2135392f7a3SLiteSpeed Tech 2145392f7a3SLiteSpeed Tech memcpy(&tag, p, 4); 2155392f7a3SLiteSpeed Tech p += 4; 2165392f7a3SLiteSpeed Tech if (0 == tag) 2175392f7a3SLiteSpeed Tech return 0; /* Client never sends version negotiation */ 2185392f7a3SLiteSpeed Tech 2195392f7a3SLiteSpeed Tech dcil = p[0] >> 4; 2205392f7a3SLiteSpeed Tech if (dcil) 2215392f7a3SLiteSpeed Tech dcil += 3; 2225392f7a3SLiteSpeed Tech scil = p[0] & 0xF; 2235392f7a3SLiteSpeed Tech if (scil) 2245392f7a3SLiteSpeed Tech scil += 3; 2255392f7a3SLiteSpeed Tech ++p; 2265392f7a3SLiteSpeed Tech 2275392f7a3SLiteSpeed Tech if (!(dcil == cid_len && scil == 0)) 2285392f7a3SLiteSpeed Tech return 0; 2295392f7a3SLiteSpeed Tech 2305392f7a3SLiteSpeed Tech packet_len = first_byte & 3; 2315392f7a3SLiteSpeed Tech 2325392f7a3SLiteSpeed Tech if (end - p >= (ptrdiff_t) (dcil + scil + packet_len)) 2335392f7a3SLiteSpeed Tech { 2345392f7a3SLiteSpeed Tech *tagp = tag; 2355392f7a3SLiteSpeed Tech return 1; 2365392f7a3SLiteSpeed Tech } 2375392f7a3SLiteSpeed Tech else 2385392f7a3SLiteSpeed Tech return 0; 2395392f7a3SLiteSpeed Tech} 2405392f7a3SLiteSpeed Tech 2415392f7a3SLiteSpeed Tech 242feca77f5SDmitri Tikhonovconst enum quic_frame_type lsquic_iquic_byte2type[0x40] = 2435392f7a3SLiteSpeed Tech{ 2445392f7a3SLiteSpeed Tech [0x00] = QUIC_FRAME_PADDING, 2455392f7a3SLiteSpeed Tech [0x01] = QUIC_FRAME_PING, 2465392f7a3SLiteSpeed Tech [0x02] = QUIC_FRAME_ACK, 2475392f7a3SLiteSpeed Tech [0x03] = QUIC_FRAME_ACK, 2485392f7a3SLiteSpeed Tech [0x04] = QUIC_FRAME_RST_STREAM, 2495392f7a3SLiteSpeed Tech [0x05] = QUIC_FRAME_STOP_SENDING, 2505392f7a3SLiteSpeed Tech [0x06] = QUIC_FRAME_CRYPTO, 2515392f7a3SLiteSpeed Tech [0x07] = QUIC_FRAME_NEW_TOKEN, 2525392f7a3SLiteSpeed Tech [0x08] = QUIC_FRAME_STREAM, 2535392f7a3SLiteSpeed Tech [0x09] = QUIC_FRAME_STREAM, 2545392f7a3SLiteSpeed Tech [0x0A] = QUIC_FRAME_STREAM, 2555392f7a3SLiteSpeed Tech [0x0B] = QUIC_FRAME_STREAM, 2565392f7a3SLiteSpeed Tech [0x0C] = QUIC_FRAME_STREAM, 2575392f7a3SLiteSpeed Tech [0x0D] = QUIC_FRAME_STREAM, 2585392f7a3SLiteSpeed Tech [0x0E] = QUIC_FRAME_STREAM, 2595392f7a3SLiteSpeed Tech [0x0F] = QUIC_FRAME_STREAM, 2605392f7a3SLiteSpeed Tech [0x10] = QUIC_FRAME_MAX_DATA, 2615392f7a3SLiteSpeed Tech [0x11] = QUIC_FRAME_MAX_STREAM_DATA, 2625392f7a3SLiteSpeed Tech [0x12] = QUIC_FRAME_MAX_STREAMS, 2635392f7a3SLiteSpeed Tech [0x13] = QUIC_FRAME_MAX_STREAMS, 2645392f7a3SLiteSpeed Tech [0x14] = QUIC_FRAME_BLOCKED, 2655392f7a3SLiteSpeed Tech [0x15] = QUIC_FRAME_STREAM_BLOCKED, 2665392f7a3SLiteSpeed Tech [0x16] = QUIC_FRAME_STREAMS_BLOCKED, 2675392f7a3SLiteSpeed Tech [0x17] = QUIC_FRAME_STREAMS_BLOCKED, 2685392f7a3SLiteSpeed Tech [0x18] = QUIC_FRAME_NEW_CONNECTION_ID, 2695392f7a3SLiteSpeed Tech [0x19] = QUIC_FRAME_RETIRE_CONNECTION_ID, 2705392f7a3SLiteSpeed Tech [0x1A] = QUIC_FRAME_PATH_CHALLENGE, 2715392f7a3SLiteSpeed Tech [0x1B] = QUIC_FRAME_PATH_RESPONSE, 2725392f7a3SLiteSpeed Tech [0x1C] = QUIC_FRAME_CONNECTION_CLOSE, 2735392f7a3SLiteSpeed Tech [0x1D] = QUIC_FRAME_CONNECTION_CLOSE, 2749fc12041SDmitri Tikhonov [0x1E] = QUIC_FRAME_HANDSHAKE_DONE, 2755392f7a3SLiteSpeed Tech [0x1F] = QUIC_FRAME_INVALID, 2765392f7a3SLiteSpeed Tech [0x20] = QUIC_FRAME_INVALID, 2775392f7a3SLiteSpeed Tech [0x21] = QUIC_FRAME_INVALID, 2785392f7a3SLiteSpeed Tech [0x22] = QUIC_FRAME_INVALID, 2795392f7a3SLiteSpeed Tech [0x23] = QUIC_FRAME_INVALID, 2805392f7a3SLiteSpeed Tech [0x24] = QUIC_FRAME_INVALID, 2815392f7a3SLiteSpeed Tech [0x25] = QUIC_FRAME_INVALID, 2825392f7a3SLiteSpeed Tech [0x26] = QUIC_FRAME_INVALID, 2835392f7a3SLiteSpeed Tech [0x27] = QUIC_FRAME_INVALID, 2845392f7a3SLiteSpeed Tech [0x28] = QUIC_FRAME_INVALID, 2855392f7a3SLiteSpeed Tech [0x29] = QUIC_FRAME_INVALID, 2865392f7a3SLiteSpeed Tech [0x2A] = QUIC_FRAME_INVALID, 2875392f7a3SLiteSpeed Tech [0x2B] = QUIC_FRAME_INVALID, 2885392f7a3SLiteSpeed Tech [0x2C] = QUIC_FRAME_INVALID, 2895392f7a3SLiteSpeed Tech [0x2D] = QUIC_FRAME_INVALID, 2905392f7a3SLiteSpeed Tech [0x2E] = QUIC_FRAME_INVALID, 2915392f7a3SLiteSpeed Tech [0x2F] = QUIC_FRAME_INVALID, 292b1a7c3f9SDmitri Tikhonov [0x30] = QUIC_FRAME_DATAGRAM, 293b1a7c3f9SDmitri Tikhonov [0x31] = QUIC_FRAME_DATAGRAM, 2945392f7a3SLiteSpeed Tech [0x32] = QUIC_FRAME_INVALID, 2955392f7a3SLiteSpeed Tech [0x33] = QUIC_FRAME_INVALID, 2965392f7a3SLiteSpeed Tech [0x34] = QUIC_FRAME_INVALID, 2975392f7a3SLiteSpeed Tech [0x35] = QUIC_FRAME_INVALID, 2985392f7a3SLiteSpeed Tech [0x36] = QUIC_FRAME_INVALID, 2995392f7a3SLiteSpeed Tech [0x37] = QUIC_FRAME_INVALID, 3005392f7a3SLiteSpeed Tech [0x38] = QUIC_FRAME_INVALID, 3015392f7a3SLiteSpeed Tech [0x39] = QUIC_FRAME_INVALID, 3025392f7a3SLiteSpeed Tech [0x3A] = QUIC_FRAME_INVALID, 3035392f7a3SLiteSpeed Tech [0x3B] = QUIC_FRAME_INVALID, 3045392f7a3SLiteSpeed Tech [0x3C] = QUIC_FRAME_INVALID, 3055392f7a3SLiteSpeed Tech [0x3D] = QUIC_FRAME_INVALID, 3065392f7a3SLiteSpeed Tech [0x3E] = QUIC_FRAME_INVALID, 3075392f7a3SLiteSpeed Tech [0x3F] = QUIC_FRAME_INVALID, 3085392f7a3SLiteSpeed Tech}; 3095392f7a3SLiteSpeed Tech 3105392f7a3SLiteSpeed Tech 3115392f7a3SLiteSpeed Tech#if __GNUC__ 3125392f7a3SLiteSpeed Tech# define popcount __builtin_popcount 3135392f7a3SLiteSpeed Tech#else 3145392f7a3SLiteSpeed Techstatic int 3155392f7a3SLiteSpeed Techpopcount (unsigned v) 3165392f7a3SLiteSpeed Tech{ 3175392f7a3SLiteSpeed Tech int count, i; 3185392f7a3SLiteSpeed Tech for (i = 0, count = 0; i < sizeof(v) * 8; ++i) 3195392f7a3SLiteSpeed Tech if (v & (1 << i)) 3205392f7a3SLiteSpeed Tech ++count; 3215392f7a3SLiteSpeed Tech return count; 3225392f7a3SLiteSpeed Tech} 3235392f7a3SLiteSpeed Tech 3245392f7a3SLiteSpeed Tech 3255392f7a3SLiteSpeed Tech#endif 3265392f7a3SLiteSpeed Tech 3275392f7a3SLiteSpeed Tech 3285392f7a3SLiteSpeed Techint 3295392f7a3SLiteSpeed Techlsquic_Q046_gen_ver_nego_pkt (unsigned char *buf, size_t bufsz, 330a0e1aeeeSDmitri Tikhonov const lsquic_cid_t *scid, const lsquic_cid_t *dcid, unsigned versions, 331a0e1aeeeSDmitri Tikhonov uint8_t rand) 3325392f7a3SLiteSpeed Tech{ 3335392f7a3SLiteSpeed Tech unsigned slen, dlen; 3345392f7a3SLiteSpeed Tech size_t need; 3355392f7a3SLiteSpeed Tech int r; 3365392f7a3SLiteSpeed Tech 3375392f7a3SLiteSpeed Tech need = 1 /* Type */ + 4 /* Packet number */ + 1 /* SCIL */ 3385392f7a3SLiteSpeed Tech + scid->len + dcid->len + popcount(versions) * 4; 3395392f7a3SLiteSpeed Tech 3405392f7a3SLiteSpeed Tech if (need > bufsz) 3415392f7a3SLiteSpeed Tech return -1; 3425392f7a3SLiteSpeed Tech 3431c9cee3eSDmitri Tikhonov *buf++ = 0x80 | 0x40 | rand; 3445392f7a3SLiteSpeed Tech memset(buf, 0, 4); 3455392f7a3SLiteSpeed Tech buf += 4; 3465392f7a3SLiteSpeed Tech 3475392f7a3SLiteSpeed Tech /* From [draft-ietf-quic-transport-11], Section 4.3: 3485392f7a3SLiteSpeed Tech * 3495392f7a3SLiteSpeed Tech * The server MUST include the value from the Source Connection ID field 3505392f7a3SLiteSpeed Tech * of the packet it receives in the Destination Connection ID field. 3515392f7a3SLiteSpeed Tech * The value for Source Connection ID MUST be copied from the 3525392f7a3SLiteSpeed Tech * Destination Connection ID of the received packet, which is initially 3535392f7a3SLiteSpeed Tech * randomly selected by a client. Echoing both connection IDs gives 3545392f7a3SLiteSpeed Tech * clients some assurance that the server received the packet and that 3555392f7a3SLiteSpeed Tech * the Version Negotiation packet was not generated by an off-path 3565392f7a3SLiteSpeed Tech * attacker. 3575392f7a3SLiteSpeed Tech */ 3585392f7a3SLiteSpeed Tech 3595392f7a3SLiteSpeed Tech dlen = dcid->len; 3605392f7a3SLiteSpeed Tech if (dlen) 3615392f7a3SLiteSpeed Tech dlen -= 3; 3625392f7a3SLiteSpeed Tech slen = scid->len; 3635392f7a3SLiteSpeed Tech if (slen) 3645392f7a3SLiteSpeed Tech slen -= 3; 3655392f7a3SLiteSpeed Tech *buf++ = (dlen << 4) | slen; 3665392f7a3SLiteSpeed Tech 3675392f7a3SLiteSpeed Tech memcpy(buf, dcid->idbuf, dcid->len); 3685392f7a3SLiteSpeed Tech buf += dcid->len; 3695392f7a3SLiteSpeed Tech memcpy(buf, scid->idbuf, scid->len); 3705392f7a3SLiteSpeed Tech buf += scid->len; 3715392f7a3SLiteSpeed Tech 3725392f7a3SLiteSpeed Tech r = lsquic_gen_ver_tags(buf, bufsz - 1 - 4 - 1 - dcid->len - scid->len, 3735392f7a3SLiteSpeed Tech versions); 3745392f7a3SLiteSpeed Tech if (r < 0) 3755392f7a3SLiteSpeed Tech return -1; 3765392f7a3SLiteSpeed Tech assert((unsigned) r == popcount(versions) * 4u); 3775392f7a3SLiteSpeed Tech 3785392f7a3SLiteSpeed Tech return need; 3795392f7a3SLiteSpeed Tech} 3805392f7a3SLiteSpeed Tech 3815392f7a3SLiteSpeed Tech 382