1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 25392f7a3SLiteSpeed Tech/* 35392f7a3SLiteSpeed Tech * lsquic_hspack_valid.c -- Handshake packet validator. 45392f7a3SLiteSpeed Tech * 55392f7a3SLiteSpeed Tech * We want to eliminate invalid packets as soon as we read them in and not 65392f7a3SLiteSpeed Tech * feed them to lsquic engine if we can avoid it. The handshake packet 75392f7a3SLiteSpeed Tech * possesses several characteristics which make it possible to detect 85392f7a3SLiteSpeed Tech * garbage packets. 95392f7a3SLiteSpeed Tech */ 105392f7a3SLiteSpeed Tech 115392f7a3SLiteSpeed Tech 125392f7a3SLiteSpeed Tech#include <assert.h> 135392f7a3SLiteSpeed Tech#include <string.h> 145392f7a3SLiteSpeed Tech#include <sys/queue.h> 155392f7a3SLiteSpeed Tech 165392f7a3SLiteSpeed Tech#include "lsquic.h" 175392f7a3SLiteSpeed Tech#include "lsquic_types.h" 185392f7a3SLiteSpeed Tech#include "lsquic_int_types.h" 195392f7a3SLiteSpeed Tech#include "lsquic_packet_common.h" 205392f7a3SLiteSpeed Tech#include "lsquic_packet_gquic.h" 215392f7a3SLiteSpeed Tech#include "lsquic_packet_ietf.h" 225392f7a3SLiteSpeed Tech#include "lsquic_mm.h" 235392f7a3SLiteSpeed Tech#include "lsquic_engine_public.h" 245392f7a3SLiteSpeed Tech#include "lsquic_version.h" 255392f7a3SLiteSpeed Tech#include "lsquic_parse_common.h" 265392f7a3SLiteSpeed Tech 275392f7a3SLiteSpeed Tech 285392f7a3SLiteSpeed Tech#define SMALLEST_GQUIC_OVERHEAD \ 295392f7a3SLiteSpeed Tech 1 /* Type */ \ 305392f7a3SLiteSpeed Tech + GQUIC_CID_LEN \ 315392f7a3SLiteSpeed Tech + sizeof(lsquic_ver_tag_t) \ 325392f7a3SLiteSpeed Tech + 1 /* Packet number */ \ 335392f7a3SLiteSpeed Tech + 1 /* Stream frame */ \ 345392f7a3SLiteSpeed Tech + 1 /* Stream ID */ \ 355392f7a3SLiteSpeed Tech + 2 /* Data length */ \ 365392f7a3SLiteSpeed Tech + 12 /* IV */ 375392f7a3SLiteSpeed Tech 385392f7a3SLiteSpeed Tech 395392f7a3SLiteSpeed Tech 405392f7a3SLiteSpeed Tech/* Note that we ignore nonce: even if the flag is set, we know that Chrome 415392f7a3SLiteSpeed Tech * does not actually include the 32-byte nonce. 425392f7a3SLiteSpeed Tech */ 435392f7a3SLiteSpeed Techstatic int 445392f7a3SLiteSpeed Techis_valid_gquic_hs_packet (const unsigned char *buf, size_t bufsz, 455392f7a3SLiteSpeed Tech lsquic_ver_tag_t *tag) 465392f7a3SLiteSpeed Tech{ 475392f7a3SLiteSpeed Tech if (bufsz > GQUIC_MAX_PACKET_SZ || 485392f7a3SLiteSpeed Tech /* Data: HPACKed :method GET :path / is 2 bytes */ 495392f7a3SLiteSpeed Tech bufsz < SMALLEST_GQUIC_OVERHEAD + 2 || 505392f7a3SLiteSpeed Tech /* Check maximum packet number: */ 515392f7a3SLiteSpeed Tech buf[1 + GQUIC_CID_LEN + sizeof(lsquic_ver_tag_t)] > 64 || 525392f7a3SLiteSpeed Tech /* From [draft-hamilton-quic-transport-protocol-01]: 535392f7a3SLiteSpeed Tech * 0x80 is currently unused, and must be set to 0. 545392f7a3SLiteSpeed Tech * 0x40 = MULTIPATH. This bit is reserved for multipath use. 555392f7a3SLiteSpeed Tech * 565392f7a3SLiteSpeed Tech * 0x30 = Packet number length. We expect these bits to be 575392f7a3SLiteSpeed Tech * unset. 585392f7a3SLiteSpeed Tech * 595392f7a3SLiteSpeed Tech * The reference implementation checks that two high bits are not 605392f7a3SLiteSpeed Tech * set if version flag is not set or if the version is the same. 615392f7a3SLiteSpeed Tech * For our purposes, all GQUIC version we support so far have these 625392f7a3SLiteSpeed Tech * bits set to zero. 635392f7a3SLiteSpeed Tech * 645392f7a3SLiteSpeed Tech * Incoming handshake packets must have both connection ID and 655392f7a3SLiteSpeed Tech * version bits set. 665392f7a3SLiteSpeed Tech * 675392f7a3SLiteSpeed Tech * Nonce flag is ignored: Chrome sets it erronesously, but it may 685392f7a3SLiteSpeed Tech * not be true (a) in the future or (b) in other clients. 695392f7a3SLiteSpeed Tech */ 705392f7a3SLiteSpeed Tech ((buf[0] ^ ( 715392f7a3SLiteSpeed Tech /* These should be unset: */ 725392f7a3SLiteSpeed Tech (~(0x80|0x40|0x30|PACKET_PUBLIC_FLAGS_RST)) 735392f7a3SLiteSpeed Tech & 745392f7a3SLiteSpeed Tech /* While these should be set: */ 755392f7a3SLiteSpeed Tech (PACKET_PUBLIC_FLAGS_VERSION| 765392f7a3SLiteSpeed Tech PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID) 775392f7a3SLiteSpeed Tech )) & /* Ignore this bit: */ ~PACKET_PUBLIC_FLAGS_NONCE) 785392f7a3SLiteSpeed Tech ) 795392f7a3SLiteSpeed Tech { 805392f7a3SLiteSpeed Tech return 0; 815392f7a3SLiteSpeed Tech } 825392f7a3SLiteSpeed Tech 835392f7a3SLiteSpeed Tech memcpy(tag, buf + 1 + 8, sizeof(*tag)); 845392f7a3SLiteSpeed Tech 855392f7a3SLiteSpeed Tech return 1; 865392f7a3SLiteSpeed Tech} 875392f7a3SLiteSpeed Tech 885392f7a3SLiteSpeed Tech 895392f7a3SLiteSpeed Techint 905392f7a3SLiteSpeed Techlsquic_is_valid_hs_packet (struct lsquic_engine *engine, 9104f8f447SDmitri Tikhonov const unsigned char *buf, size_t bufsz) 925392f7a3SLiteSpeed Tech{ 935392f7a3SLiteSpeed Tech lsquic_ver_tag_t tag; 945392f7a3SLiteSpeed Tech int is_valid; 955392f7a3SLiteSpeed Tech 965392f7a3SLiteSpeed Tech if (bufsz < 1) 975392f7a3SLiteSpeed Tech return 0; 985392f7a3SLiteSpeed Tech 995392f7a3SLiteSpeed Tech switch (buf[0] & 0xF8) 1005392f7a3SLiteSpeed Tech { 1015392f7a3SLiteSpeed Tech /* Xs vary, Gs are iGnored: */ 1025392f7a3SLiteSpeed Tech /* 1X11 XGGG: Q046 long header */ 1035392f7a3SLiteSpeed Tech case 0x80|0x40|0x20|0x10|0x08: 1045392f7a3SLiteSpeed Tech case 0x80|0x00|0x20|0x10|0x08: 1055392f7a3SLiteSpeed Tech case 0x80|0x40|0x20|0x10|0x00: 1065392f7a3SLiteSpeed Tech case 0x80|0x00|0x20|0x10|0x00: 10704f8f447SDmitri Tikhonov is_valid = bufsz >= IQUIC_MIN_INIT_PACKET_SZ 108de46bf2fSDmitri Tikhonov && lsquic_is_valid_iquic_hs_packet(buf, bufsz, &tag); 1095392f7a3SLiteSpeed Tech break; 1105392f7a3SLiteSpeed Tech /* 1X00 XGGG: ID-22 long header */ 1115392f7a3SLiteSpeed Tech case 0x80|0x40|0x00|0x00|0x08: 1125392f7a3SLiteSpeed Tech case 0x80|0x00|0x00|0x00|0x08: 1135392f7a3SLiteSpeed Tech case 0x80|0x40|0x00|0x00|0x00: 1145392f7a3SLiteSpeed Tech case 0x80|0x00|0x00|0x00|0x00: 1155392f7a3SLiteSpeed Tech /* 1X01 XGGG: ID-22 long header */ 1165392f7a3SLiteSpeed Tech case 0x80|0x40|0x00|0x10|0x08: 1175392f7a3SLiteSpeed Tech case 0x80|0x00|0x00|0x10|0x08: 1185392f7a3SLiteSpeed Tech case 0x80|0x40|0x00|0x10|0x00: 1195392f7a3SLiteSpeed Tech case 0x80|0x00|0x00|0x10|0x00: 1205392f7a3SLiteSpeed Tech /* 1X10 XGGG: ID-22 long header */ 1215392f7a3SLiteSpeed Tech case 0x80|0x40|0x20|0x00|0x08: 1225392f7a3SLiteSpeed Tech case 0x80|0x00|0x20|0x00|0x08: 1235392f7a3SLiteSpeed Tech case 0x80|0x40|0x20|0x00|0x00: 1245392f7a3SLiteSpeed Tech case 0x80|0x00|0x20|0x00|0x00: 12504f8f447SDmitri Tikhonov is_valid = bufsz >= IQUIC_MIN_INIT_PACKET_SZ 126de46bf2fSDmitri Tikhonov && lsquic_is_valid_ietf_v1_or_Q046plus_hs_packet(buf, bufsz, &tag); 1275392f7a3SLiteSpeed Tech break; 1285392f7a3SLiteSpeed Tech /* 01XX XGGG: ID-22 short header */ 1295392f7a3SLiteSpeed Tech case 0x00|0x40|0x00|0x00|0x00: 1305392f7a3SLiteSpeed Tech case 0x00|0x40|0x00|0x00|0x08: 1315392f7a3SLiteSpeed Tech case 0x00|0x40|0x00|0x10|0x00: 1325392f7a3SLiteSpeed Tech case 0x00|0x40|0x00|0x10|0x08: 1335392f7a3SLiteSpeed Tech case 0x00|0x40|0x20|0x00|0x00: 1345392f7a3SLiteSpeed Tech case 0x00|0x40|0x20|0x00|0x08: 1355392f7a3SLiteSpeed Tech case 0x00|0x40|0x20|0x10|0x00: 1365392f7a3SLiteSpeed Tech case 0x00|0x40|0x20|0x10|0x08: 1375392f7a3SLiteSpeed Tech is_valid = 0; 1385392f7a3SLiteSpeed Tech break; 1395392f7a3SLiteSpeed Tech /* 00XX 0GGG: Q046 short header */ 1405392f7a3SLiteSpeed Tech case 0x00|0x00|0x00|0x00|0x00: 1415392f7a3SLiteSpeed Tech case 0x00|0x00|0x00|0x10|0x00: 1425392f7a3SLiteSpeed Tech case 0x00|0x00|0x20|0x00|0x00: 1435392f7a3SLiteSpeed Tech case 0x00|0x00|0x20|0x10|0x00: 1445392f7a3SLiteSpeed Tech is_valid = 0; 1455392f7a3SLiteSpeed Tech break; 1465392f7a3SLiteSpeed Tech /* 00XX 1GGG: GQUIC */ 1475392f7a3SLiteSpeed Tech case 0x00|0x00|0x00|0x00|0x08: 1485392f7a3SLiteSpeed Tech case 0x00|0x00|0x00|0x10|0x08: 1495392f7a3SLiteSpeed Tech case 0x00|0x00|0x20|0x00|0x08: 1505392f7a3SLiteSpeed Tech case 0x00|0x00|0x20|0x10|0x08: 1515392f7a3SLiteSpeed Tech is_valid = is_valid_gquic_hs_packet(buf, bufsz, &tag); 1525392f7a3SLiteSpeed Tech break; 1535392f7a3SLiteSpeed Tech default: /* gcc thinks this is possible?! */ 1545392f7a3SLiteSpeed Tech assert(0); 1555392f7a3SLiteSpeed Tech is_valid = 0; 1565392f7a3SLiteSpeed Tech break; 1575392f7a3SLiteSpeed Tech } 1585392f7a3SLiteSpeed Tech 1595392f7a3SLiteSpeed Tech if (is_valid) 1605392f7a3SLiteSpeed Tech { 1615392f7a3SLiteSpeed Tech return 1; 1625392f7a3SLiteSpeed Tech } 1635392f7a3SLiteSpeed Tech else 1645392f7a3SLiteSpeed Tech return 0; 1655392f7a3SLiteSpeed Tech} 166