lsquic_hspack_valid.c revision 06b2a236
1/* Copyright (c) 2017 - 2021 LiteSpeed Technologies Inc. See LICENSE. */ 2/* 3 * lsquic_hspack_valid.c -- Handshake packet validator. 4 * 5 * We want to eliminate invalid packets as soon as we read them in and not 6 * feed them to lsquic engine if we can avoid it. The handshake packet 7 * possesses several characteristics which make it possible to detect 8 * garbage packets. 9 */ 10 11 12#include <assert.h> 13#include <string.h> 14#include <sys/queue.h> 15 16#include "lsquic.h" 17#include "lsquic_types.h" 18#include "lsquic_int_types.h" 19#include "lsquic_packet_common.h" 20#include "lsquic_packet_gquic.h" 21#include "lsquic_packet_ietf.h" 22#include "lsquic_mm.h" 23#include "lsquic_engine_public.h" 24#include "lsquic_version.h" 25#include "lsquic_parse_common.h" 26 27 28#define SMALLEST_GQUIC_OVERHEAD \ 29 1 /* Type */ \ 30 + GQUIC_CID_LEN \ 31 + sizeof(lsquic_ver_tag_t) \ 32 + 1 /* Packet number */ \ 33 + 1 /* Stream frame */ \ 34 + 1 /* Stream ID */ \ 35 + 2 /* Data length */ \ 36 + 12 /* IV */ 37 38 39 40/* Note that we ignore nonce: even if the flag is set, we know that Chrome 41 * does not actually include the 32-byte nonce. 42 */ 43static int 44is_valid_gquic_hs_packet (const unsigned char *buf, size_t bufsz, 45 lsquic_ver_tag_t *tag) 46{ 47 if (bufsz > GQUIC_MAX_PACKET_SZ || 48 /* Data: HPACKed :method GET :path / is 2 bytes */ 49 bufsz < SMALLEST_GQUIC_OVERHEAD + 2 || 50 /* Check maximum packet number: */ 51 buf[1 + GQUIC_CID_LEN + sizeof(lsquic_ver_tag_t)] > 64 || 52 /* From [draft-hamilton-quic-transport-protocol-01]: 53 * 0x80 is currently unused, and must be set to 0. 54 * 0x40 = MULTIPATH. This bit is reserved for multipath use. 55 * 56 * 0x30 = Packet number length. We expect these bits to be 57 * unset. 58 * 59 * The reference implementation checks that two high bits are not 60 * set if version flag is not set or if the version is the same. 61 * For our purposes, all GQUIC version we support so far have these 62 * bits set to zero. 63 * 64 * Incoming handshake packets must have both connection ID and 65 * version bits set. 66 * 67 * Nonce flag is ignored: Chrome sets it erronesously, but it may 68 * not be true (a) in the future or (b) in other clients. 69 */ 70 ((buf[0] ^ ( 71 /* These should be unset: */ 72 (~(0x80|0x40|0x30|PACKET_PUBLIC_FLAGS_RST)) 73 & 74 /* While these should be set: */ 75 (PACKET_PUBLIC_FLAGS_VERSION| 76 PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID) 77 )) & /* Ignore this bit: */ ~PACKET_PUBLIC_FLAGS_NONCE) 78 ) 79 { 80 return 0; 81 } 82 83 memcpy(tag, buf + 1 + 8, sizeof(*tag)); 84 85 return 1; 86} 87 88 89int 90lsquic_is_valid_hs_packet (struct lsquic_engine *engine, 91 const unsigned char *buf, size_t bufsz) 92{ 93 lsquic_ver_tag_t tag; 94 int is_valid; 95 96 if (bufsz < 1) 97 return 0; 98 99 switch (buf[0] & 0xF8) 100 { 101 /* Xs vary, Gs are iGnored: */ 102 /* 1X11 XGGG: Q046 long header */ 103 case 0x80|0x40|0x20|0x10|0x08: 104 case 0x80|0x00|0x20|0x10|0x08: 105 case 0x80|0x40|0x20|0x10|0x00: 106 case 0x80|0x00|0x20|0x10|0x00: 107 is_valid = bufsz >= IQUIC_MIN_INIT_PACKET_SZ 108 && lsquic_is_valid_iquic_hs_packet(buf, bufsz, &tag); 109 break; 110 /* 1X00 XGGG: ID-22 long header */ 111 case 0x80|0x40|0x00|0x00|0x08: 112 case 0x80|0x00|0x00|0x00|0x08: 113 case 0x80|0x40|0x00|0x00|0x00: 114 case 0x80|0x00|0x00|0x00|0x00: 115 /* 1X01 XGGG: ID-22 long header */ 116 case 0x80|0x40|0x00|0x10|0x08: 117 case 0x80|0x00|0x00|0x10|0x08: 118 case 0x80|0x40|0x00|0x10|0x00: 119 case 0x80|0x00|0x00|0x10|0x00: 120 /* 1X10 XGGG: ID-22 long header */ 121 case 0x80|0x40|0x20|0x00|0x08: 122 case 0x80|0x00|0x20|0x00|0x08: 123 case 0x80|0x40|0x20|0x00|0x00: 124 case 0x80|0x00|0x20|0x00|0x00: 125 is_valid = bufsz >= IQUIC_MIN_INIT_PACKET_SZ 126 && lsquic_is_valid_ietf_v1_or_Q046plus_hs_packet(buf, bufsz, &tag); 127 break; 128 /* 01XX XGGG: ID-22 short header */ 129 case 0x00|0x40|0x00|0x00|0x00: 130 case 0x00|0x40|0x00|0x00|0x08: 131 case 0x00|0x40|0x00|0x10|0x00: 132 case 0x00|0x40|0x00|0x10|0x08: 133 case 0x00|0x40|0x20|0x00|0x00: 134 case 0x00|0x40|0x20|0x00|0x08: 135 case 0x00|0x40|0x20|0x10|0x00: 136 case 0x00|0x40|0x20|0x10|0x08: 137 is_valid = 0; 138 break; 139 /* 00XX 0GGG: Q046 short header */ 140 case 0x00|0x00|0x00|0x00|0x00: 141 case 0x00|0x00|0x00|0x10|0x00: 142 case 0x00|0x00|0x20|0x00|0x00: 143 case 0x00|0x00|0x20|0x10|0x00: 144 is_valid = 0; 145 break; 146 /* 00XX 1GGG: GQUIC */ 147 case 0x00|0x00|0x00|0x00|0x08: 148 case 0x00|0x00|0x00|0x10|0x08: 149 case 0x00|0x00|0x20|0x00|0x08: 150 case 0x00|0x00|0x20|0x10|0x08: 151 is_valid = is_valid_gquic_hs_packet(buf, bufsz, &tag); 152 break; 153 default: /* gcc thinks this is possible?! */ 154 assert(0); 155 is_valid = 0; 156 break; 157 } 158 159 if (is_valid) 160 { 161 return 1; 162 } 163 else 164 return 0; 165} 166