lsquic_parse_iquic_common.c revision 229fce07
1229fce07SDmitri Tikhonov/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
29626cfc2SDmitri Tikhonov#include <stddef.h>
39626cfc2SDmitri Tikhonov#include <stdint.h>
49626cfc2SDmitri Tikhonov#include <string.h>
59626cfc2SDmitri Tikhonov#include <sys/queue.h>
69626cfc2SDmitri Tikhonov#include <sys/types.h>
79626cfc2SDmitri Tikhonov
89626cfc2SDmitri Tikhonov#include <openssl/rand.h>
99626cfc2SDmitri Tikhonov
109626cfc2SDmitri Tikhonov#include "lsquic_types.h"
119626cfc2SDmitri Tikhonov#include "lsquic_int_types.h"
129626cfc2SDmitri Tikhonov#include "lsquic_packet_common.h"
139626cfc2SDmitri Tikhonov#include "lsquic_packet_in.h"
149626cfc2SDmitri Tikhonov#include "lsquic_parse_common.h"
159626cfc2SDmitri Tikhonov#include "lsquic_parse.h"
169626cfc2SDmitri Tikhonov#include "lsquic_version.h"
179626cfc2SDmitri Tikhonov#include "lsquic.h"
189626cfc2SDmitri Tikhonov#include "lsquic_logger.h"
199626cfc2SDmitri Tikhonov#include "lsquic_byteswap.h"
209626cfc2SDmitri Tikhonov#include "lsquic_str.h"
219626cfc2SDmitri Tikhonov#include "lsquic_handshake.h"
229626cfc2SDmitri Tikhonov
239626cfc2SDmitri Tikhonov
249626cfc2SDmitri Tikhonovstatic const enum header_type bin_2_header_type[0x100] =
259626cfc2SDmitri Tikhonov{
269626cfc2SDmitri Tikhonov    [0x80 | 0x7F]  =  HETY_INITIAL,
279626cfc2SDmitri Tikhonov    [0x80 | 0x7E]  =  HETY_RETRY,
289626cfc2SDmitri Tikhonov    [0x80 | 0x7D]  =  HETY_HANDSHAKE,
299626cfc2SDmitri Tikhonov    [0x80 | 0x7C]  =  HETY_0RTT,
309626cfc2SDmitri Tikhonov};
319626cfc2SDmitri Tikhonov
329626cfc2SDmitri Tikhonov
339626cfc2SDmitri Tikhonovint
349626cfc2SDmitri Tikhonovlsquic_iquic_parse_packet_in_long_begin (lsquic_packet_in_t *packet_in,
359626cfc2SDmitri Tikhonov            size_t length, int is_server, struct packin_parse_state *state)
369626cfc2SDmitri Tikhonov{
379626cfc2SDmitri Tikhonov    const unsigned char *p = packet_in->pi_data;
389626cfc2SDmitri Tikhonov    const unsigned char *const end = p + length;
399626cfc2SDmitri Tikhonov    lsquic_ver_tag_t tag;
409626cfc2SDmitri Tikhonov    enum header_type header_type;
419626cfc2SDmitri Tikhonov    unsigned dcil, scil;
429626cfc2SDmitri Tikhonov    int verneg;
439626cfc2SDmitri Tikhonov    unsigned char first_byte;
449626cfc2SDmitri Tikhonov    const unsigned cid_len = 8;
459626cfc2SDmitri Tikhonov
469626cfc2SDmitri Tikhonov    if (length < 6)
479626cfc2SDmitri Tikhonov        return -1;
489626cfc2SDmitri Tikhonov    first_byte = *p++;
499626cfc2SDmitri Tikhonov
509626cfc2SDmitri Tikhonov    memcpy(&tag, p, 4);
519626cfc2SDmitri Tikhonov    p += 4;
529626cfc2SDmitri Tikhonov    verneg = 0 == tag;
539626cfc2SDmitri Tikhonov    if (!verneg)
549626cfc2SDmitri Tikhonov    {
559626cfc2SDmitri Tikhonov        header_type = bin_2_header_type[ first_byte ];
569626cfc2SDmitri Tikhonov        if (!header_type)
579626cfc2SDmitri Tikhonov            return -1;
589626cfc2SDmitri Tikhonov    }
599626cfc2SDmitri Tikhonov    else
609626cfc2SDmitri Tikhonov        header_type = HETY_VERNEG;
619626cfc2SDmitri Tikhonov
629626cfc2SDmitri Tikhonov    packet_in->pi_header_type = header_type;
639626cfc2SDmitri Tikhonov
649626cfc2SDmitri Tikhonov    dcil = p[0] >> 4;
659626cfc2SDmitri Tikhonov    if (dcil)
669626cfc2SDmitri Tikhonov        dcil += 3;
679626cfc2SDmitri Tikhonov    scil = p[0] & 0xF;
689626cfc2SDmitri Tikhonov    if (scil)
699626cfc2SDmitri Tikhonov        scil += 3;
709626cfc2SDmitri Tikhonov    ++p;
719626cfc2SDmitri Tikhonov
729626cfc2SDmitri Tikhonov    /* Chromium comments state that the client sends packets with destination
739626cfc2SDmitri Tikhonov     * CID of 8 bytes and source CID of 0 bytes and the server does it the
749626cfc2SDmitri Tikhonov     * other way around.
759626cfc2SDmitri Tikhonov     *
769626cfc2SDmitri Tikhonov     * XXX When IETF branch is merged, this check for Q044 will have to be
779626cfc2SDmitri Tikhonov     * moved to the pf_parse_packet_in_finish().
789626cfc2SDmitri Tikhonov     */
799626cfc2SDmitri Tikhonov    if (is_server)
809626cfc2SDmitri Tikhonov    {
819626cfc2SDmitri Tikhonov        if (!(dcil == cid_len && scil == 0))
829626cfc2SDmitri Tikhonov            return -1;
839626cfc2SDmitri Tikhonov    }
849626cfc2SDmitri Tikhonov    else
859626cfc2SDmitri Tikhonov    {
869626cfc2SDmitri Tikhonov        if (!(dcil == 0 && scil == cid_len))
879626cfc2SDmitri Tikhonov            return -1;
889626cfc2SDmitri Tikhonov    }
899626cfc2SDmitri Tikhonov
909626cfc2SDmitri Tikhonov    const unsigned packet_len = 4;
919626cfc2SDmitri Tikhonov    /* XXX This checks both packet length or the first version of the version
929626cfc2SDmitri Tikhonov     * array in a version negotiation packet.  This is because the sizes of
939626cfc2SDmitri Tikhonov     * the packet number field and the version tag are the same.  The check
949626cfc2SDmitri Tikhonov     * will probably have to be split in the future.
959626cfc2SDmitri Tikhonov     */
96a37b0c96SDmitri Tikhonov    if (end - p < (ptrdiff_t) (dcil + scil + packet_len))
979626cfc2SDmitri Tikhonov        return -1;
989626cfc2SDmitri Tikhonov
999626cfc2SDmitri Tikhonov    memcpy(&packet_in->pi_conn_id, p, cid_len);
1009626cfc2SDmitri Tikhonov    p += cid_len;
1019626cfc2SDmitri Tikhonov    packet_in->pi_flags |= PI_CONN_ID;
1029626cfc2SDmitri Tikhonov
1039626cfc2SDmitri Tikhonov    packet_in->pi_packno       = 0;
1049626cfc2SDmitri Tikhonov
1059626cfc2SDmitri Tikhonov    if (!verneg)
1069626cfc2SDmitri Tikhonov    {
1079626cfc2SDmitri Tikhonov        state->pps_p      = p;
1089626cfc2SDmitri Tikhonov        state->pps_nbytes = packet_len;
1099626cfc2SDmitri Tikhonov        p += packet_len;
1109626cfc2SDmitri Tikhonov        packet_in->pi_quic_ver = 1;
1119626cfc2SDmitri Tikhonov        if (is_server || HETY_0RTT != header_type)
1129626cfc2SDmitri Tikhonov            packet_in->pi_nonce = 0;
1139626cfc2SDmitri Tikhonov        else
1149626cfc2SDmitri Tikhonov        {
1159626cfc2SDmitri Tikhonov            packet_in->pi_nonce = p - packet_in->pi_data;
1169626cfc2SDmitri Tikhonov            p += 32;
1179626cfc2SDmitri Tikhonov        }
1189626cfc2SDmitri Tikhonov    }
1199626cfc2SDmitri Tikhonov    else
1209626cfc2SDmitri Tikhonov    {
1219626cfc2SDmitri Tikhonov        if ((end - p) & 3)
1229626cfc2SDmitri Tikhonov            return -1;
1239626cfc2SDmitri Tikhonov        state->pps_p      = NULL;
1249626cfc2SDmitri Tikhonov        state->pps_nbytes = 0;
1259626cfc2SDmitri Tikhonov        packet_in->pi_quic_ver = p - packet_in->pi_data;
1269626cfc2SDmitri Tikhonov        p = packet_in->pi_data + length;
1279626cfc2SDmitri Tikhonov        packet_in->pi_nonce = 0;
1289626cfc2SDmitri Tikhonov    }
1299626cfc2SDmitri Tikhonov
1309626cfc2SDmitri Tikhonov    packet_in->pi_header_sz    = p - packet_in->pi_data;
1319626cfc2SDmitri Tikhonov    packet_in->pi_frame_types  = 0;
1329626cfc2SDmitri Tikhonov    packet_in->pi_data_sz      = length;
1339626cfc2SDmitri Tikhonov    packet_in->pi_refcnt       = 0;
1349626cfc2SDmitri Tikhonov    packet_in->pi_received     = 0;
1359626cfc2SDmitri Tikhonov
1369626cfc2SDmitri Tikhonov    return 0;
1379626cfc2SDmitri Tikhonov}
1389626cfc2SDmitri Tikhonov
1399626cfc2SDmitri Tikhonov
1409626cfc2SDmitri Tikhonovint
1419626cfc2SDmitri Tikhonovlsquic_iquic_parse_packet_in_short_begin (lsquic_packet_in_t *packet_in,
1429626cfc2SDmitri Tikhonov            size_t length, int is_server, struct packin_parse_state *state)
1439626cfc2SDmitri Tikhonov{
1449626cfc2SDmitri Tikhonov    const unsigned char *p = packet_in->pi_data;
1459626cfc2SDmitri Tikhonov    const unsigned char *const pend = packet_in->pi_data + length;
1469626cfc2SDmitri Tikhonov    unsigned cid_len = 8;   /* XXX this will need to be passed in */
1479626cfc2SDmitri Tikhonov    unsigned packet_len;
1489626cfc2SDmitri Tikhonov
1499626cfc2SDmitri Tikhonov    if ((*p & 0x30) != 0x30 || (*p & 3) == 3)
1509626cfc2SDmitri Tikhonov        return -1;
1519626cfc2SDmitri Tikhonov
1529626cfc2SDmitri Tikhonov    packet_len = 1 << (*p & 3);
153a37b0c96SDmitri Tikhonov    if (pend - p < (ptrdiff_t) (1 + cid_len + packet_len))
1549626cfc2SDmitri Tikhonov        return -1;
1559626cfc2SDmitri Tikhonov
1569626cfc2SDmitri Tikhonov    ++p;
1579626cfc2SDmitri Tikhonov
1589626cfc2SDmitri Tikhonov    if (is_server)
1599626cfc2SDmitri Tikhonov    {
1609626cfc2SDmitri Tikhonov        memcpy(&packet_in->pi_conn_id, p, cid_len);
1619626cfc2SDmitri Tikhonov        p += cid_len;
162dee31d56SDmitri Tikhonov        packet_in->pi_flags |= PI_CONN_ID;
1639626cfc2SDmitri Tikhonov    }
1649626cfc2SDmitri Tikhonov
1659626cfc2SDmitri Tikhonov    /* We could read in the packet number here, but we choose to do it in
1669626cfc2SDmitri Tikhonov     * the finish() call instead.
1679626cfc2SDmitri Tikhonov     */
1689626cfc2SDmitri Tikhonov    packet_in->pi_packno       = 0;
1699626cfc2SDmitri Tikhonov    state->pps_p      = p;
1709626cfc2SDmitri Tikhonov    state->pps_nbytes = packet_len;
1719626cfc2SDmitri Tikhonov    p += packet_len;
1729626cfc2SDmitri Tikhonov
1739626cfc2SDmitri Tikhonov    packet_in->pi_header_type  = HETY_NOT_SET;
1749626cfc2SDmitri Tikhonov    packet_in->pi_quic_ver     = 0;
1759626cfc2SDmitri Tikhonov    packet_in->pi_nonce        = 0;
1769626cfc2SDmitri Tikhonov    packet_in->pi_header_sz    = p - packet_in->pi_data;
1779626cfc2SDmitri Tikhonov    packet_in->pi_frame_types  = 0;
1789626cfc2SDmitri Tikhonov    packet_in->pi_data_sz      = length;
1799626cfc2SDmitri Tikhonov    packet_in->pi_refcnt       = 0;
1809626cfc2SDmitri Tikhonov    packet_in->pi_received     = 0;
1819626cfc2SDmitri Tikhonov
1829626cfc2SDmitri Tikhonov    return 0;
1839626cfc2SDmitri Tikhonov}
1849626cfc2SDmitri Tikhonov
1859626cfc2SDmitri Tikhonov
186