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