lsquic_parse_iquic_common.c revision e5d4bc6d
1/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
2#include <stddef.h>
3#include <stdint.h>
4#include <string.h>
5#include <sys/queue.h>
6#include <sys/types.h>
7
8#include <openssl/rand.h>
9
10#include "lsquic_types.h"
11#include "lsquic_int_types.h"
12#include "lsquic_packet_common.h"
13#include "lsquic_packet_in.h"
14#include "lsquic_parse_common.h"
15#include "lsquic_parse.h"
16#include "lsquic_version.h"
17#include "lsquic.h"
18#include "lsquic_logger.h"
19#include "lsquic_byteswap.h"
20#include "lsquic_str.h"
21#include "lsquic_handshake.h"
22
23
24static const enum header_type bin_2_header_type_Q044[0x100] =
25{
26    [0x80 | 0x7F]  =  HETY_INITIAL,
27    [0x80 | 0x7E]  =  HETY_RETRY,
28    [0x80 | 0x7D]  =  HETY_HANDSHAKE,
29    [0x80 | 0x7C]  =  HETY_0RTT,
30};
31
32
33/* [draft-ietf-quic-transport-17] Section-17.2 */
34static const enum header_type bits2ht[4] =
35{
36    [0] = HETY_INITIAL,
37    [1] = HETY_0RTT,
38    [2] = HETY_HANDSHAKE,
39    [3] = HETY_RETRY,
40};
41
42
43/* This function supports versions Q044 and higher */
44int
45lsquic_iquic_parse_packet_in_long_begin (lsquic_packet_in_t *packet_in,
46            size_t length, int is_server, struct packin_parse_state *state)
47{
48    const unsigned char *p = packet_in->pi_data;
49    const unsigned char *const end = p + length;
50    lsquic_ver_tag_t tag;
51    enum header_type header_type;
52    unsigned dcil, scil, packet_len;
53    int verneg;
54    enum lsquic_version version;
55    unsigned char first_byte;
56    const unsigned cid_len = 8;
57
58    if (length < 6)
59        return -1;
60    first_byte = *p++;
61
62    memcpy(&tag, p, 4);
63    p += 4;
64    verneg = 0 == tag;
65    if (!verneg)
66    {
67        version = lsquic_tag2ver(tag);
68        if (version == LSQVER_044)
69        {
70            header_type = bin_2_header_type_Q044[ first_byte ];
71            if (!header_type)
72                return -1;
73        }
74        else
75            header_type = bits2ht[ (first_byte >> 4) & 3 ];
76    }
77    else
78    {
79        header_type = HETY_VERNEG;
80#ifdef WIN32
81        /* Useless initialization: */
82        version = -1;
83#endif
84    }
85
86
87    packet_in->pi_header_type = header_type;
88
89    dcil = p[0] >> 4;
90    if (dcil)
91        dcil += 3;
92    scil = p[0] & 0xF;
93    if (scil)
94        scil += 3;
95    ++p;
96
97    /* Chromium comments state that the client sends packets with destination
98     * CID of 8 bytes and source CID of 0 bytes and the server does it the
99     * other way around.
100     *
101     * XXX When IETF branch is merged, this check for Q044 and higher will
102     * have to be moved to the pf_parse_packet_in_finish().
103     */
104    if (is_server)
105    {
106        if (!(dcil == cid_len && scil == 0))
107            return -1;
108    }
109    else
110    {
111        if (!(dcil == 0 && scil == cid_len))
112            return -1;
113    }
114
115    if (!verneg)
116    {
117        if (version == LSQVER_044)
118        {
119            packet_in->pi_flags |= GQUIC_PACKNO_LEN_4 << PIBIT_BITS_SHIFT;
120            packet_len = 4;
121        }
122        else
123        {
124            packet_in->pi_flags |= (first_byte & 3) << PIBIT_BITS_SHIFT;
125            packet_len = 1 + (first_byte & 3);
126        }
127        if (end - p < (ptrdiff_t) (dcil + scil + packet_len))
128            return -1;
129    }
130    else
131    {
132        /* Need at least one version in the version array: add 4 */
133        if (end - p < (ptrdiff_t) (dcil + scil + 4))
134            return -1;
135#ifdef WIN32
136        /* Useless initialization: */
137        packet_len = 0;
138#endif
139    }
140
141    memcpy(&packet_in->pi_conn_id, p, cid_len);
142    p += cid_len;
143    packet_in->pi_flags |= PI_CONN_ID;
144
145    packet_in->pi_packno       = 0;
146
147    if (!verneg)
148    {
149        state->pps_p      = p;
150        state->pps_nbytes = packet_len;
151        p += packet_len;
152        packet_in->pi_quic_ver = 1;
153        if (is_server || HETY_0RTT != header_type)
154            packet_in->pi_nonce = 0;
155        else
156        {
157            packet_in->pi_nonce = p - packet_in->pi_data;
158            p += 32;
159        }
160    }
161    else
162    {
163        if ((end - p) & 3)
164            return -1;
165        state->pps_p      = NULL;
166        state->pps_nbytes = 0;
167        packet_in->pi_quic_ver = p - packet_in->pi_data;
168        p = packet_in->pi_data + length;
169        packet_in->pi_nonce = 0;
170    }
171
172    packet_in->pi_header_sz    = p - packet_in->pi_data;
173    packet_in->pi_frame_types  = 0;
174    packet_in->pi_data_sz      = length;
175    packet_in->pi_refcnt       = 0;
176    packet_in->pi_received     = 0;
177
178    return 0;
179}
180
181
182int
183lsquic_iquic_parse_packet_in_short_begin (lsquic_packet_in_t *packet_in,
184            size_t length, int is_server, struct packin_parse_state *state)
185{
186    const unsigned char *p = packet_in->pi_data;
187    const unsigned char *const pend = packet_in->pi_data + length;
188    unsigned cid_len = 8;   /* XXX this will need to be passed in */
189    unsigned packet_len;
190
191    if (*p & 0x40)  /* Q046 and higher */
192        packet_len = 1 + (*p & 3);
193    else
194    {
195        if ((*p & 0x30) != 0x30 || (*p & 3) == 3)
196            return -1;
197        packet_len = 1 << (*p & 3);
198    }
199
200    if (pend - p < (ptrdiff_t) (1 + cid_len + packet_len))
201        return -1;
202
203    packet_in->pi_flags |= (*p & 3) << PIBIT_BITS_SHIFT;
204    ++p;
205
206    if (is_server)
207    {
208        memcpy(&packet_in->pi_conn_id, p, cid_len);
209        p += cid_len;
210        packet_in->pi_flags |= PI_CONN_ID;
211    }
212
213    /* We could read in the packet number here, but we choose to do it in
214     * the finish() call instead.
215     */
216    packet_in->pi_packno       = 0;
217    state->pps_p      = p;
218    state->pps_nbytes = packet_len;
219    p += packet_len;
220
221    packet_in->pi_header_type  = HETY_NOT_SET;
222    packet_in->pi_quic_ver     = 0;
223    packet_in->pi_nonce        = 0;
224    packet_in->pi_header_sz    = p - packet_in->pi_data;
225    packet_in->pi_frame_types  = 0;
226    packet_in->pi_data_sz      = length;
227    packet_in->pi_refcnt       = 0;
228    packet_in->pi_received     = 0;
229
230    return 0;
231}
232
233
234