lsquic_parse_iquic_common.c revision a37b0c96
1/* Copyright (c) 2017 - 2018 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[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
33int
34lsquic_iquic_parse_packet_in_long_begin (lsquic_packet_in_t *packet_in,
35            size_t length, int is_server, struct packin_parse_state *state)
36{
37    const unsigned char *p = packet_in->pi_data;
38    const unsigned char *const end = p + length;
39    lsquic_ver_tag_t tag;
40    enum header_type header_type;
41    unsigned dcil, scil;
42    int verneg;
43    unsigned char first_byte;
44    const unsigned cid_len = 8;
45
46    if (length < 6)
47        return -1;
48    first_byte = *p++;
49
50    memcpy(&tag, p, 4);
51    p += 4;
52    verneg = 0 == tag;
53    if (!verneg)
54    {
55        header_type = bin_2_header_type[ first_byte ];
56        if (!header_type)
57            return -1;
58    }
59    else
60        header_type = HETY_VERNEG;
61
62    packet_in->pi_header_type = header_type;
63
64    dcil = p[0] >> 4;
65    if (dcil)
66        dcil += 3;
67    scil = p[0] & 0xF;
68    if (scil)
69        scil += 3;
70    ++p;
71
72    /* Chromium comments state that the client sends packets with destination
73     * CID of 8 bytes and source CID of 0 bytes and the server does it the
74     * other way around.
75     *
76     * XXX When IETF branch is merged, this check for Q044 will have to be
77     * moved to the pf_parse_packet_in_finish().
78     */
79    if (is_server)
80    {
81        if (!(dcil == cid_len && scil == 0))
82            return -1;
83    }
84    else
85    {
86        if (!(dcil == 0 && scil == cid_len))
87            return -1;
88    }
89
90    const unsigned packet_len = 4;
91    /* XXX This checks both packet length or the first version of the version
92     * array in a version negotiation packet.  This is because the sizes of
93     * the packet number field and the version tag are the same.  The check
94     * will probably have to be split in the future.
95     */
96    if (end - p < (ptrdiff_t) (dcil + scil + packet_len))
97        return -1;
98
99    memcpy(&packet_in->pi_conn_id, p, cid_len);
100    p += cid_len;
101    packet_in->pi_flags |= PI_CONN_ID;
102
103    packet_in->pi_packno       = 0;
104
105    if (!verneg)
106    {
107        state->pps_p      = p;
108        state->pps_nbytes = packet_len;
109        p += packet_len;
110        packet_in->pi_quic_ver = 1;
111        if (is_server || HETY_0RTT != header_type)
112            packet_in->pi_nonce = 0;
113        else
114        {
115            packet_in->pi_nonce = p - packet_in->pi_data;
116            p += 32;
117        }
118    }
119    else
120    {
121        if ((end - p) & 3)
122            return -1;
123        state->pps_p      = NULL;
124        state->pps_nbytes = 0;
125        packet_in->pi_quic_ver = p - packet_in->pi_data;
126        p = packet_in->pi_data + length;
127        packet_in->pi_nonce = 0;
128    }
129
130    packet_in->pi_header_sz    = p - packet_in->pi_data;
131    packet_in->pi_frame_types  = 0;
132    packet_in->pi_data_sz      = length;
133    packet_in->pi_refcnt       = 0;
134    packet_in->pi_received     = 0;
135
136    return 0;
137}
138
139
140int
141lsquic_iquic_parse_packet_in_short_begin (lsquic_packet_in_t *packet_in,
142            size_t length, int is_server, struct packin_parse_state *state)
143{
144    const unsigned char *p = packet_in->pi_data;
145    const unsigned char *const pend = packet_in->pi_data + length;
146    unsigned cid_len = 8;   /* XXX this will need to be passed in */
147    unsigned packet_len;
148
149    if ((*p & 0x30) != 0x30 || (*p & 3) == 3)
150        return -1;
151
152    packet_len = 1 << (*p & 3);
153    if (pend - p < (ptrdiff_t) (1 + cid_len + packet_len))
154        return -1;
155
156    ++p;
157
158    if (is_server)
159    {
160        memcpy(&packet_in->pi_conn_id, p, cid_len);
161        p += cid_len;
162        packet_in->pi_flags |= PI_CONN_ID;
163    }
164
165    /* We could read in the packet number here, but we choose to do it in
166     * the finish() call instead.
167     */
168    packet_in->pi_packno       = 0;
169    state->pps_p      = p;
170    state->pps_nbytes = packet_len;
171    p += packet_len;
172
173    packet_in->pi_header_type  = HETY_NOT_SET;
174    packet_in->pi_quic_ver     = 0;
175    packet_in->pi_nonce        = 0;
176    packet_in->pi_header_sz    = p - packet_in->pi_data;
177    packet_in->pi_frame_types  = 0;
178    packet_in->pi_data_sz      = length;
179    packet_in->pi_refcnt       = 0;
180    packet_in->pi_received     = 0;
181
182    return 0;
183}
184
185
186