Path: blob/main/crypto/openssl/ssl/quic/quic_wire_pkt.c
48261 views
/*1* Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89#include <openssl/err.h>10#include "internal/common.h"11#include "internal/quic_wire_pkt.h"1213int ossl_quic_hdr_protector_init(QUIC_HDR_PROTECTOR *hpr,14OSSL_LIB_CTX *libctx,15const char *propq,16uint32_t cipher_id,17const unsigned char *quic_hp_key,18size_t quic_hp_key_len)19{20const char *cipher_name = NULL;2122switch (cipher_id) {23case QUIC_HDR_PROT_CIPHER_AES_128:24cipher_name = "AES-128-ECB";25break;26case QUIC_HDR_PROT_CIPHER_AES_256:27cipher_name = "AES-256-ECB";28break;29case QUIC_HDR_PROT_CIPHER_CHACHA:30cipher_name = "ChaCha20";31break;32default:33ERR_raise(ERR_LIB_SSL, ERR_R_UNSUPPORTED);34return 0;35}3637hpr->cipher_ctx = EVP_CIPHER_CTX_new();38if (hpr->cipher_ctx == NULL) {39ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);40return 0;41}4243hpr->cipher = EVP_CIPHER_fetch(libctx, cipher_name, propq);44if (hpr->cipher == NULL45|| quic_hp_key_len != (size_t)EVP_CIPHER_get_key_length(hpr->cipher)) {46ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);47goto err;48}4950if (!EVP_CipherInit_ex(hpr->cipher_ctx, hpr->cipher, NULL,51quic_hp_key, NULL, 1)) {52ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);53goto err;54}5556hpr->libctx = libctx;57hpr->propq = propq;58hpr->cipher_id = cipher_id;59return 1;6061err:62ossl_quic_hdr_protector_cleanup(hpr);63return 0;64}6566void ossl_quic_hdr_protector_cleanup(QUIC_HDR_PROTECTOR *hpr)67{68EVP_CIPHER_CTX_free(hpr->cipher_ctx);69hpr->cipher_ctx = NULL;7071EVP_CIPHER_free(hpr->cipher);72hpr->cipher = NULL;73}7475static int hdr_generate_mask(QUIC_HDR_PROTECTOR *hpr,76const unsigned char *sample, size_t sample_len,77unsigned char *mask)78{79int l = 0;80unsigned char dst[16];81static const unsigned char zeroes[5] = {0};82size_t i;8384if (hpr->cipher_id == QUIC_HDR_PROT_CIPHER_AES_12885|| hpr->cipher_id == QUIC_HDR_PROT_CIPHER_AES_256) {86if (sample_len < 16) {87ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);88return 0;89}9091if (!EVP_CipherInit_ex(hpr->cipher_ctx, NULL, NULL, NULL, NULL, 1)92|| !EVP_CipherUpdate(hpr->cipher_ctx, dst, &l, sample, 16)) {93ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);94return 0;95}9697for (i = 0; i < 5; ++i)98mask[i] = dst[i];99} else if (hpr->cipher_id == QUIC_HDR_PROT_CIPHER_CHACHA) {100if (sample_len < 16) {101ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);102return 0;103}104105if (!EVP_CipherInit_ex(hpr->cipher_ctx, NULL, NULL, NULL, sample, 1)106|| !EVP_CipherUpdate(hpr->cipher_ctx, mask, &l,107zeroes, sizeof(zeroes))) {108ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);109return 0;110}111} else {112ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);113assert(0);114return 0;115}116117#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION118/* No matter what we did above we use the same mask in fuzzing mode */119memset(mask, 0, 5);120#endif121122return 1;123}124125int ossl_quic_hdr_protector_decrypt(QUIC_HDR_PROTECTOR *hpr,126QUIC_PKT_HDR_PTRS *ptrs)127{128return ossl_quic_hdr_protector_decrypt_fields(hpr,129ptrs->raw_sample,130ptrs->raw_sample_len,131ptrs->raw_start,132ptrs->raw_pn);133}134135int ossl_quic_hdr_protector_decrypt_fields(QUIC_HDR_PROTECTOR *hpr,136const unsigned char *sample,137size_t sample_len,138unsigned char *first_byte,139unsigned char *pn_bytes)140{141unsigned char mask[5], pn_len, i;142143if (!hdr_generate_mask(hpr, sample, sample_len, mask))144return 0;145146*first_byte ^= mask[0] & ((*first_byte & 0x80) != 0 ? 0xf : 0x1f);147pn_len = (*first_byte & 0x3) + 1;148149for (i = 0; i < pn_len; ++i)150pn_bytes[i] ^= mask[i + 1];151152return 1;153}154155int ossl_quic_hdr_protector_encrypt(QUIC_HDR_PROTECTOR *hpr,156QUIC_PKT_HDR_PTRS *ptrs)157{158return ossl_quic_hdr_protector_encrypt_fields(hpr,159ptrs->raw_sample,160ptrs->raw_sample_len,161ptrs->raw_start,162ptrs->raw_pn);163}164165int ossl_quic_hdr_protector_encrypt_fields(QUIC_HDR_PROTECTOR *hpr,166const unsigned char *sample,167size_t sample_len,168unsigned char *first_byte,169unsigned char *pn_bytes)170{171unsigned char mask[5], pn_len, i;172173if (!hdr_generate_mask(hpr, sample, sample_len, mask))174return 0;175176pn_len = (*first_byte & 0x3) + 1;177for (i = 0; i < pn_len; ++i)178pn_bytes[i] ^= mask[i + 1];179180*first_byte ^= mask[0] & ((*first_byte & 0x80) != 0 ? 0xf : 0x1f);181return 1;182}183184int ossl_quic_wire_decode_pkt_hdr(PACKET *pkt,185size_t short_conn_id_len,186int partial,187int nodata,188QUIC_PKT_HDR *hdr,189QUIC_PKT_HDR_PTRS *ptrs,190uint64_t *fail_cause)191{192unsigned int b0;193unsigned char *pn = NULL;194size_t l = PACKET_remaining(pkt);195196if (fail_cause != NULL)197*fail_cause = QUIC_PKT_HDR_DECODE_DECODE_ERR;198199if (ptrs != NULL) {200ptrs->raw_start = (unsigned char *)PACKET_data(pkt);201ptrs->raw_sample = NULL;202ptrs->raw_sample_len = 0;203ptrs->raw_pn = NULL;204}205206if (l < QUIC_MIN_VALID_PKT_LEN207|| !PACKET_get_1(pkt, &b0))208return 0;209210hdr->partial = partial;211hdr->unused = 0;212hdr->reserved = 0;213214if ((b0 & 0x80) == 0) {215/* Short header. */216if (short_conn_id_len > QUIC_MAX_CONN_ID_LEN)217return 0;218219if ((b0 & 0x40) == 0 /* fixed bit not set? */220|| l < QUIC_MIN_VALID_PKT_LEN_CRYPTO)221return 0;222223hdr->type = QUIC_PKT_TYPE_1RTT;224hdr->fixed = 1;225hdr->spin_bit = (b0 & 0x20) != 0;226if (partial) {227hdr->key_phase = 0; /* protected, zero for now */228hdr->pn_len = 0; /* protected, zero for now */229hdr->reserved = 0; /* protected, zero for now */230} else {231hdr->key_phase = (b0 & 0x04) != 0;232hdr->pn_len = (b0 & 0x03) + 1;233hdr->reserved = (b0 & 0x18) >> 3;234}235236/* Copy destination connection ID field to header structure. */237if (!PACKET_copy_bytes(pkt, hdr->dst_conn_id.id, short_conn_id_len))238return 0;239240hdr->dst_conn_id.id_len = (unsigned char)short_conn_id_len;241242/*243* Skip over the PN. If this is a partial decode, the PN length field244* currently has header protection applied. Thus we do not know the245* length of the PN but we are allowed to assume it is 4 bytes long at246* this stage.247*/248memset(hdr->pn, 0, sizeof(hdr->pn));249pn = (unsigned char *)PACKET_data(pkt);250if (partial) {251if (!PACKET_forward(pkt, sizeof(hdr->pn)))252return 0;253} else {254if (!PACKET_copy_bytes(pkt, hdr->pn, hdr->pn_len))255return 0;256}257258/* Fields not used in short-header packets. */259hdr->version = 0;260hdr->src_conn_id.id_len = 0;261hdr->token = NULL;262hdr->token_len = 0;263264/*265* Short-header packets always come last in a datagram, the length266* is the remainder of the buffer.267*/268hdr->len = PACKET_remaining(pkt);269hdr->data = PACKET_data(pkt);270271/*272* Skip over payload. Since this is a short header packet, which cannot273* be followed by any other kind of packet, this advances us to the end274* of the datagram.275*/276if (!PACKET_forward(pkt, hdr->len))277return 0;278} else {279/* Long header. */280unsigned long version;281unsigned int dst_conn_id_len, src_conn_id_len, raw_type;282283if (!PACKET_get_net_4(pkt, &version))284return 0;285286/*287* All QUIC packets must have the fixed bit set, except exceptionally288* for Version Negotiation packets.289*/290if (version != 0 && (b0 & 0x40) == 0)291return 0;292293if (!PACKET_get_1(pkt, &dst_conn_id_len)294|| dst_conn_id_len > QUIC_MAX_CONN_ID_LEN295|| !PACKET_copy_bytes(pkt, hdr->dst_conn_id.id, dst_conn_id_len)296|| !PACKET_get_1(pkt, &src_conn_id_len)297|| src_conn_id_len > QUIC_MAX_CONN_ID_LEN298|| !PACKET_copy_bytes(pkt, hdr->src_conn_id.id, src_conn_id_len))299return 0;300301hdr->version = (uint32_t)version;302hdr->dst_conn_id.id_len = (unsigned char)dst_conn_id_len;303hdr->src_conn_id.id_len = (unsigned char)src_conn_id_len;304305if (version == 0) {306/*307* Version negotiation packet. Version negotiation packets are308* identified by a version field of 0 and the type bits in the first309* byte are ignored (they may take any value, and we ignore them).310*/311hdr->type = QUIC_PKT_TYPE_VERSION_NEG;312hdr->fixed = (b0 & 0x40) != 0;313314hdr->data = PACKET_data(pkt);315hdr->len = PACKET_remaining(pkt);316317/*318* Version negotiation packets must contain an array of u32s, so it319* is invalid for their payload length to not be divisible by 4.320*/321if ((hdr->len % 4) != 0)322return 0;323324/* Version negotiation packets are always fully decoded. */325hdr->partial = 0;326327/* Fields not used in version negotiation packets. */328hdr->pn_len = 0;329hdr->spin_bit = 0;330hdr->key_phase = 0;331hdr->token = NULL;332hdr->token_len = 0;333memset(hdr->pn, 0, sizeof(hdr->pn));334335if (!PACKET_forward(pkt, hdr->len))336return 0;337} else if (version != QUIC_VERSION_1) {338if (fail_cause != NULL)339*fail_cause |= QUIC_PKT_HDR_DECODE_BAD_VERSION;340/* Unknown version, do not decode. */341return 0;342} else {343if (l < QUIC_MIN_VALID_PKT_LEN_CRYPTO)344return 0;345346/* Get long packet type and decode to QUIC_PKT_TYPE_*. */347raw_type = ((b0 >> 4) & 0x3);348349switch (raw_type) {350case 0:351hdr->type = QUIC_PKT_TYPE_INITIAL;352break;353case 1:354hdr->type = QUIC_PKT_TYPE_0RTT;355break;356case 2:357hdr->type = QUIC_PKT_TYPE_HANDSHAKE;358break;359case 3:360hdr->type = QUIC_PKT_TYPE_RETRY;361break;362}363364hdr->pn_len = 0;365hdr->fixed = 1;366367/* Fields not used in long-header packets. */368hdr->spin_bit = 0;369hdr->key_phase = 0;370371if (hdr->type == QUIC_PKT_TYPE_INITIAL) {372/* Initial packet. */373uint64_t token_len;374375if (!PACKET_get_quic_vlint(pkt, &token_len)376|| token_len > SIZE_MAX377|| !PACKET_get_bytes(pkt, &hdr->token, (size_t)token_len))378return 0;379380hdr->token_len = (size_t)token_len;381if (token_len == 0)382hdr->token = NULL;383} else {384hdr->token = NULL;385hdr->token_len = 0;386}387388if (hdr->type == QUIC_PKT_TYPE_RETRY) {389/* Retry packet. */390hdr->data = PACKET_data(pkt);391hdr->len = PACKET_remaining(pkt);392393/* Retry packets are always fully decoded. */394hdr->partial = 0;395396/* Unused bits in Retry header. */397hdr->unused = b0 & 0x0f;398399/* Fields not used in Retry packets. */400memset(hdr->pn, 0, sizeof(hdr->pn));401402if (!PACKET_forward(pkt, hdr->len))403return 0;404} else {405/* Initial, 0-RTT or Handshake packet. */406uint64_t len;407408hdr->pn_len = partial ? 0 : ((b0 & 0x03) + 1);409hdr->reserved = partial ? 0 : ((b0 & 0x0C) >> 2);410411if (!PACKET_get_quic_vlint(pkt, &len)412|| len < sizeof(hdr->pn))413return 0;414415if (!nodata && len > PACKET_remaining(pkt))416return 0;417418/*419* Skip over the PN. If this is a partial decode, the PN length420* field currently has header protection applied. Thus we do not421* know the length of the PN but we are allowed to assume it is422* 4 bytes long at this stage.423*/424pn = (unsigned char *)PACKET_data(pkt);425memset(hdr->pn, 0, sizeof(hdr->pn));426if (partial) {427if (!PACKET_forward(pkt, sizeof(hdr->pn)))428return 0;429430hdr->len = (size_t)(len - sizeof(hdr->pn));431} else {432if (!PACKET_copy_bytes(pkt, hdr->pn, hdr->pn_len))433return 0;434435hdr->len = (size_t)(len - hdr->pn_len);436}437438if (nodata) {439hdr->data = NULL;440} else {441hdr->data = PACKET_data(pkt);442443/* Skip over packet body. */444if (!PACKET_forward(pkt, hdr->len))445return 0;446}447}448}449}450451if (ptrs != NULL) {452ptrs->raw_pn = pn;453if (pn != NULL) {454ptrs->raw_sample = pn + 4;455ptrs->raw_sample_len = PACKET_end(pkt) - ptrs->raw_sample;456}457}458459/*460* Good decode, clear the generic DECODE_ERR flag461*/462if (fail_cause != NULL)463*fail_cause &= ~QUIC_PKT_HDR_DECODE_DECODE_ERR;464465return 1;466}467468int ossl_quic_wire_encode_pkt_hdr(WPACKET *pkt,469size_t short_conn_id_len,470const QUIC_PKT_HDR *hdr,471QUIC_PKT_HDR_PTRS *ptrs)472{473unsigned char b0;474size_t off_start, off_sample, off_pn;475unsigned char *start = WPACKET_get_curr(pkt);476477if (!WPACKET_get_total_written(pkt, &off_start))478return 0;479480if (ptrs != NULL) {481/* ptrs would not be stable on non-static WPACKET */482if (!ossl_assert(pkt->staticbuf != NULL))483return 0;484ptrs->raw_start = NULL;485ptrs->raw_sample = NULL;486ptrs->raw_sample_len = 0;487ptrs->raw_pn = 0;488}489490/* Cannot serialize a partial header, or one whose DCID length is wrong. */491if (hdr->partial492|| (hdr->type == QUIC_PKT_TYPE_1RTT493&& hdr->dst_conn_id.id_len != short_conn_id_len))494return 0;495496if (hdr->type == QUIC_PKT_TYPE_1RTT) {497/* Short header. */498499/*500* Cannot serialize a header whose DCID length is wrong, or with an501* invalid PN length.502*/503if (hdr->dst_conn_id.id_len != short_conn_id_len504|| short_conn_id_len > QUIC_MAX_CONN_ID_LEN505|| hdr->pn_len < 1 || hdr->pn_len > 4)506return 0;507508b0 = (hdr->spin_bit << 5)509| (hdr->key_phase << 2)510| (hdr->pn_len - 1)511| (hdr->reserved << 3)512| 0x40; /* fixed bit */513514if (!WPACKET_put_bytes_u8(pkt, b0)515|| !WPACKET_memcpy(pkt, hdr->dst_conn_id.id, short_conn_id_len)516|| !WPACKET_get_total_written(pkt, &off_pn)517|| !WPACKET_memcpy(pkt, hdr->pn, hdr->pn_len))518return 0;519} else {520/* Long header. */521unsigned int raw_type;522523if (hdr->dst_conn_id.id_len > QUIC_MAX_CONN_ID_LEN524|| hdr->src_conn_id.id_len > QUIC_MAX_CONN_ID_LEN)525return 0;526527if (ossl_quic_pkt_type_has_pn(hdr->type)528&& (hdr->pn_len < 1 || hdr->pn_len > 4))529return 0;530531switch (hdr->type) {532case QUIC_PKT_TYPE_VERSION_NEG:533if (hdr->version != 0)534return 0;535536/* Version negotiation packets use zero for the type bits */537raw_type = 0;538break;539540case QUIC_PKT_TYPE_INITIAL: raw_type = 0; break;541case QUIC_PKT_TYPE_0RTT: raw_type = 1; break;542case QUIC_PKT_TYPE_HANDSHAKE: raw_type = 2; break;543case QUIC_PKT_TYPE_RETRY: raw_type = 3; break;544default:545return 0;546}547548b0 = (raw_type << 4) | 0x80; /* long */549if (hdr->type != QUIC_PKT_TYPE_VERSION_NEG || hdr->fixed)550b0 |= 0x40; /* fixed */551if (ossl_quic_pkt_type_has_pn(hdr->type)) {552b0 |= hdr->pn_len - 1;553b0 |= (hdr->reserved << 2);554}555if (hdr->type == QUIC_PKT_TYPE_RETRY)556b0 |= hdr->unused;557558if (!WPACKET_put_bytes_u8(pkt, b0)559|| !WPACKET_put_bytes_u32(pkt, hdr->version)560|| !WPACKET_put_bytes_u8(pkt, hdr->dst_conn_id.id_len)561|| !WPACKET_memcpy(pkt, hdr->dst_conn_id.id,562hdr->dst_conn_id.id_len)563|| !WPACKET_put_bytes_u8(pkt, hdr->src_conn_id.id_len)564|| !WPACKET_memcpy(pkt, hdr->src_conn_id.id,565hdr->src_conn_id.id_len))566return 0;567568if (hdr->type == QUIC_PKT_TYPE_VERSION_NEG) {569if (hdr->len > 0 && !WPACKET_reserve_bytes(pkt, hdr->len, NULL))570return 0;571572return 1;573}574575if (hdr->type == QUIC_PKT_TYPE_INITIAL) {576if (!WPACKET_quic_write_vlint(pkt, hdr->token_len)577|| !WPACKET_memcpy(pkt, hdr->token, hdr->token_len))578return 0;579}580581if (hdr->type == QUIC_PKT_TYPE_RETRY) {582if (!WPACKET_memcpy(pkt, hdr->token, hdr->token_len))583return 0;584return 1;585}586587if (!WPACKET_quic_write_vlint(pkt, hdr->len + hdr->pn_len)588|| !WPACKET_get_total_written(pkt, &off_pn)589|| !WPACKET_memcpy(pkt, hdr->pn, hdr->pn_len))590return 0;591}592593if (hdr->len > 0 && !WPACKET_reserve_bytes(pkt, hdr->len, NULL))594return 0;595596off_sample = off_pn + 4;597598if (ptrs != NULL) {599ptrs->raw_start = start;600ptrs->raw_sample = start + (off_sample - off_start);601ptrs->raw_sample_len602= WPACKET_get_curr(pkt) + hdr->len - ptrs->raw_sample;603ptrs->raw_pn = start + (off_pn - off_start);604}605606return 1;607}608609int ossl_quic_wire_get_encoded_pkt_hdr_len(size_t short_conn_id_len,610const QUIC_PKT_HDR *hdr)611{612size_t len = 0, enclen;613614/* Cannot serialize a partial header, or one whose DCID length is wrong. */615if (hdr->partial616|| (hdr->type == QUIC_PKT_TYPE_1RTT617&& hdr->dst_conn_id.id_len != short_conn_id_len))618return 0;619620if (hdr->type == QUIC_PKT_TYPE_1RTT) {621/* Short header. */622623/*624* Cannot serialize a header whose DCID length is wrong, or with an625* invalid PN length.626*/627if (hdr->dst_conn_id.id_len != short_conn_id_len628|| short_conn_id_len > QUIC_MAX_CONN_ID_LEN629|| hdr->pn_len < 1 || hdr->pn_len > 4)630return 0;631632return 1 + short_conn_id_len + hdr->pn_len;633} else {634/* Long header. */635if (hdr->dst_conn_id.id_len > QUIC_MAX_CONN_ID_LEN636|| hdr->src_conn_id.id_len > QUIC_MAX_CONN_ID_LEN)637return 0;638639len += 1 /* Initial byte */ + 4 /* Version */640+ 1 + hdr->dst_conn_id.id_len /* DCID Len, DCID */641+ 1 + hdr->src_conn_id.id_len /* SCID Len, SCID */642;643644if (ossl_quic_pkt_type_has_pn(hdr->type)) {645if (hdr->pn_len < 1 || hdr->pn_len > 4)646return 0;647648len += hdr->pn_len;649}650651if (hdr->type == QUIC_PKT_TYPE_INITIAL) {652enclen = ossl_quic_vlint_encode_len(hdr->token_len);653if (!enclen)654return 0;655656len += enclen + hdr->token_len;657}658659if (!ossl_quic_pkt_type_must_be_last(hdr->type)) {660enclen = ossl_quic_vlint_encode_len(hdr->len + hdr->pn_len);661if (!enclen)662return 0;663664len += enclen;665}666667return len;668}669}670671int ossl_quic_wire_get_pkt_hdr_dst_conn_id(const unsigned char *buf,672size_t buf_len,673size_t short_conn_id_len,674QUIC_CONN_ID *dst_conn_id)675{676unsigned char b0;677size_t blen;678679if (buf_len < QUIC_MIN_VALID_PKT_LEN680|| short_conn_id_len > QUIC_MAX_CONN_ID_LEN)681return 0;682683b0 = buf[0];684if ((b0 & 0x80) != 0) {685/*686* Long header. We need 6 bytes (initial byte, 4 version bytes, DCID687* length byte to begin with). This is covered by the buf_len test688* above.689*/690691/*692* If the version field is non-zero (meaning that this is not a Version693* Negotiation packet), the fixed bit must be set.694*/695if ((buf[1] || buf[2] || buf[3] || buf[4]) && (b0 & 0x40) == 0)696return 0;697698blen = (size_t)buf[5]; /* DCID Length */699if (blen > QUIC_MAX_CONN_ID_LEN700|| buf_len < QUIC_MIN_VALID_PKT_LEN + blen)701return 0;702703dst_conn_id->id_len = (unsigned char)blen;704memcpy(dst_conn_id->id, buf + 6, blen);705return 1;706} else {707/* Short header. */708if ((b0 & 0x40) == 0)709/* Fixed bit not set, not a valid QUIC packet header. */710return 0;711712if (buf_len < QUIC_MIN_VALID_PKT_LEN_CRYPTO + short_conn_id_len)713return 0;714715dst_conn_id->id_len = (unsigned char)short_conn_id_len;716memcpy(dst_conn_id->id, buf + 1, short_conn_id_len);717return 1;718}719}720721int ossl_quic_wire_decode_pkt_hdr_pn(const unsigned char *enc_pn,722size_t enc_pn_len,723QUIC_PN largest_pn,724QUIC_PN *res_pn)725{726int64_t expected_pn, truncated_pn, candidate_pn, pn_win, pn_hwin, pn_mask;727728switch (enc_pn_len) {729case 1:730truncated_pn = enc_pn[0];731break;732case 2:733truncated_pn = ((QUIC_PN)enc_pn[0] << 8)734| (QUIC_PN)enc_pn[1];735break;736case 3:737truncated_pn = ((QUIC_PN)enc_pn[0] << 16)738| ((QUIC_PN)enc_pn[1] << 8)739| (QUIC_PN)enc_pn[2];740break;741case 4:742truncated_pn = ((QUIC_PN)enc_pn[0] << 24)743| ((QUIC_PN)enc_pn[1] << 16)744| ((QUIC_PN)enc_pn[2] << 8)745| (QUIC_PN)enc_pn[3];746break;747default:748return 0;749}750751/* Implemented as per RFC 9000 Section A.3. */752expected_pn = largest_pn + 1;753pn_win = ((int64_t)1) << (enc_pn_len * 8);754pn_hwin = pn_win / 2;755pn_mask = pn_win - 1;756candidate_pn = (expected_pn & ~pn_mask) | truncated_pn;757if (candidate_pn <= expected_pn - pn_hwin758&& candidate_pn < (((int64_t)1) << 62) - pn_win)759*res_pn = candidate_pn + pn_win;760else if (candidate_pn > expected_pn + pn_hwin761&& candidate_pn >= pn_win)762*res_pn = candidate_pn - pn_win;763else764*res_pn = candidate_pn;765return 1;766}767768/* From RFC 9000 Section A.2. Simplified implementation. */769int ossl_quic_wire_determine_pn_len(QUIC_PN pn,770QUIC_PN largest_acked)771{772uint64_t num_unacked773= (largest_acked == QUIC_PN_INVALID) ? pn + 1 : pn - largest_acked;774775/*776* num_unacked \in [ 0, 2** 7] -> 1 byte777* num_unacked \in (2** 7, 2**15] -> 2 bytes778* num_unacked \in (2**15, 2**23] -> 3 bytes779* num_unacked \in (2**23, ] -> 4 bytes780*/781782if (num_unacked <= (1U<<7)) return 1;783if (num_unacked <= (1U<<15)) return 2;784if (num_unacked <= (1U<<23)) return 3;785return 4;786}787788int ossl_quic_wire_encode_pkt_hdr_pn(QUIC_PN pn,789unsigned char *enc_pn,790size_t enc_pn_len)791{792switch (enc_pn_len) {793case 1:794enc_pn[0] = (unsigned char)pn;795break;796case 2:797enc_pn[1] = (unsigned char)pn;798enc_pn[0] = (unsigned char)(pn >> 8);799break;800case 3:801enc_pn[2] = (unsigned char)pn;802enc_pn[1] = (unsigned char)(pn >> 8);803enc_pn[0] = (unsigned char)(pn >> 16);804break;805case 4:806enc_pn[3] = (unsigned char)pn;807enc_pn[2] = (unsigned char)(pn >> 8);808enc_pn[1] = (unsigned char)(pn >> 16);809enc_pn[0] = (unsigned char)(pn >> 24);810break;811default:812return 0;813}814815return 1;816}817818int ossl_quic_validate_retry_integrity_tag(OSSL_LIB_CTX *libctx,819const char *propq,820const QUIC_PKT_HDR *hdr,821const QUIC_CONN_ID *client_initial_dcid)822{823unsigned char expected_tag[QUIC_RETRY_INTEGRITY_TAG_LEN];824const unsigned char *actual_tag;825826if (hdr == NULL || hdr->len < QUIC_RETRY_INTEGRITY_TAG_LEN)827return 0;828829if (!ossl_quic_calculate_retry_integrity_tag(libctx, propq,830hdr, client_initial_dcid,831expected_tag))832return 0;833834actual_tag = hdr->data + hdr->len - QUIC_RETRY_INTEGRITY_TAG_LEN;835836return !CRYPTO_memcmp(expected_tag, actual_tag,837QUIC_RETRY_INTEGRITY_TAG_LEN);838}839840/* RFC 9001 s. 5.8 */841static const unsigned char retry_integrity_key[] = {8420xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a,8430x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e844};845846static const unsigned char retry_integrity_nonce[] = {8470x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2,8480x23, 0x98, 0x25, 0xbb849};850851int ossl_quic_calculate_retry_integrity_tag(OSSL_LIB_CTX *libctx,852const char *propq,853const QUIC_PKT_HDR *hdr,854const QUIC_CONN_ID *client_initial_dcid,855unsigned char *tag)856{857EVP_CIPHER *cipher = NULL;858EVP_CIPHER_CTX *cctx = NULL;859int ok = 0, l = 0, l2 = 0, wpkt_valid = 0;860WPACKET wpkt;861/* Worst case length of the Retry Psuedo-Packet header is 68 bytes. */862unsigned char buf[128];863QUIC_PKT_HDR hdr2;864size_t hdr_enc_len = 0;865866if (hdr->type != QUIC_PKT_TYPE_RETRY || hdr->version == 0867|| hdr->len < QUIC_RETRY_INTEGRITY_TAG_LEN868|| hdr->data == NULL869|| client_initial_dcid == NULL || tag == NULL870|| client_initial_dcid->id_len > QUIC_MAX_CONN_ID_LEN) {871ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);872goto err;873}874875/*876* Do not reserve packet body in WPACKET. Retry packet header877* does not contain a Length field so this does not affect878* the serialized packet header.879*/880hdr2 = *hdr;881hdr2.len = 0;882883/* Assemble retry psuedo-packet. */884if (!WPACKET_init_static_len(&wpkt, buf, sizeof(buf), 0)) {885ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);886goto err;887}888889wpkt_valid = 1;890891/* Prepend original DCID to the packet. */892if (!WPACKET_put_bytes_u8(&wpkt, client_initial_dcid->id_len)893|| !WPACKET_memcpy(&wpkt, client_initial_dcid->id,894client_initial_dcid->id_len)) {895ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);896goto err;897}898899/* Encode main retry header. */900if (!ossl_quic_wire_encode_pkt_hdr(&wpkt, hdr2.dst_conn_id.id_len,901&hdr2, NULL))902goto err;903904if (!WPACKET_get_total_written(&wpkt, &hdr_enc_len)) {905ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);906goto err;907}908909/* Create and initialise cipher context. */910/* TODO(QUIC FUTURE): Cipher fetch caching. */911if ((cipher = EVP_CIPHER_fetch(libctx, "AES-128-GCM", propq)) == NULL) {912ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);913goto err;914}915916if ((cctx = EVP_CIPHER_CTX_new()) == NULL) {917ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);918goto err;919}920921if (!EVP_CipherInit_ex(cctx, cipher, NULL,922retry_integrity_key, retry_integrity_nonce, /*enc=*/1)) {923ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);924goto err;925}926927/* Feed packet header as AAD data. */928if (EVP_CipherUpdate(cctx, NULL, &l, buf, hdr_enc_len) != 1) {929ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);930goto err;931}932933/* Feed packet body as AAD data. */934if (EVP_CipherUpdate(cctx, NULL, &l, hdr->data,935hdr->len - QUIC_RETRY_INTEGRITY_TAG_LEN) != 1) {936ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);937goto err;938}939940/* Finalise and get tag. */941if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1) {942ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);943goto err;944}945946if (EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_GET_TAG,947QUIC_RETRY_INTEGRITY_TAG_LEN,948tag) != 1) {949ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);950goto err;951}952953ok = 1;954err:955EVP_CIPHER_free(cipher);956EVP_CIPHER_CTX_free(cctx);957if (wpkt_valid)958WPACKET_finish(&wpkt);959960return ok;961}962963964