lsquic_parse_iquic_common.c revision 55cd0b38
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        header_type = HETY_VERNEG;
79
80    packet_in->pi_header_type = header_type;
81
82    dcil = p[0] >> 4;
83    if (dcil)
84        dcil += 3;
85    scil = p[0] & 0xF;
86    if (scil)
87        scil += 3;
88    ++p;
89
90    /* Chromium comments state that the client sends packets with destination
91     * CID of 8 bytes and source CID of 0 bytes and the server does it the
92     * other way around.
93     *
94     * XXX When IETF branch is merged, this check for Q044 and higher will
95     * have to be moved to the pf_parse_packet_in_finish().
96     */
97    if (is_server)
98    {
99        if (!(dcil == cid_len && scil == 0))
100            return -1;
101    }
102    else
103    {
104        if (!(dcil == 0 && scil == cid_len))
105            return -1;
106    }
107
108    if (!verneg)
109    {
110        if (version == LSQVER_044)
111        {
112            packet_in->pi_flags |= GQUIC_PACKNO_LEN_4 << PIBIT_BITS_SHIFT;
113            packet_len = 4;
114        }
115        else
116        {
117            packet_in->pi_flags |= (first_byte & 3) << PIBIT_BITS_SHIFT;
118            packet_len = 1 + (first_byte & 3);
119        }
120        if (end - p < (ptrdiff_t) (dcil + scil + packet_len))
121            return -1;
122    }
123    else
124    {
125        /* Need at least one version in the version array: add 4 */
126        if (end - p < (ptrdiff_t) (dcil + scil + 4))
127            return -1;
128    }
129
130    memcpy(&packet_in->pi_conn_id, p, cid_len);
131    p += cid_len;
132    packet_in->pi_flags |= PI_CONN_ID;
133
134    packet_in->pi_packno       = 0;
135
136    if (!verneg)
137    {
138        state->pps_p      = p;
139        state->pps_nbytes = packet_len;
140        p += packet_len;
141        packet_in->pi_quic_ver = 1;
142        if (is_server || HETY_0RTT != header_type)
143            packet_in->pi_nonce = 0;
144        else
145        {
146            packet_in->pi_nonce = p - packet_in->pi_data;
147            p += 32;
148        }
149    }
150    else
151    {
152        if ((end - p) & 3)
153            return -1;
154        state->pps_p      = NULL;
155        state->pps_nbytes = 0;
156        packet_in->pi_quic_ver = p - packet_in->pi_data;
157        p = packet_in->pi_data + length;
158        packet_in->pi_nonce = 0;
159    }
160
161    packet_in->pi_header_sz    = p - packet_in->pi_data;
162    packet_in->pi_frame_types  = 0;
163    packet_in->pi_data_sz      = length;
164    packet_in->pi_refcnt       = 0;
165    packet_in->pi_received     = 0;
166
167    return 0;
168}
169
170
171int
172lsquic_iquic_parse_packet_in_short_begin (lsquic_packet_in_t *packet_in,
173            size_t length, int is_server, struct packin_parse_state *state)
174{
175    const unsigned char *p = packet_in->pi_data;
176    const unsigned char *const pend = packet_in->pi_data + length;
177    unsigned cid_len = 8;   /* XXX this will need to be passed in */
178    unsigned packet_len;
179
180    if (*p & 0x40)  /* Q046 and higher */
181        packet_len = 1 + (*p & 3);
182    else
183    {
184        if ((*p & 0x30) != 0x30 || (*p & 3) == 3)
185            return -1;
186        packet_len = 1 << (*p & 3);
187    }
188
189    if (pend - p < (ptrdiff_t) (1 + cid_len + packet_len))
190        return -1;
191
192    packet_in->pi_flags |= (*p & 3) << PIBIT_BITS_SHIFT;
193    ++p;
194
195    if (is_server)
196    {
197        memcpy(&packet_in->pi_conn_id, p, cid_len);
198        p += cid_len;
199        packet_in->pi_flags |= PI_CONN_ID;
200    }
201
202    /* We could read in the packet number here, but we choose to do it in
203     * the finish() call instead.
204     */
205    packet_in->pi_packno       = 0;
206    state->pps_p      = p;
207    state->pps_nbytes = packet_len;
208    p += packet_len;
209
210    packet_in->pi_header_type  = HETY_NOT_SET;
211    packet_in->pi_quic_ver     = 0;
212    packet_in->pi_nonce        = 0;
213    packet_in->pi_header_sz    = p - packet_in->pi_data;
214    packet_in->pi_frame_types  = 0;
215    packet_in->pi_data_sz      = length;
216    packet_in->pi_refcnt       = 0;
217    packet_in->pi_received     = 0;
218
219    return 0;
220}
221
222
223