• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ngtcp2
3  *
4  * Copyright (c) 2017 ngtcp2 contributors
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #include "ngtcp2_crypto.h"
26 
27 #include <string.h>
28 #include <assert.h>
29 
30 #include "ngtcp2_str.h"
31 #include "ngtcp2_conv.h"
32 #include "ngtcp2_conn.h"
33 #include "ngtcp2_net.h"
34 
ngtcp2_crypto_km_new(ngtcp2_crypto_km ** pckm,const uint8_t * secret,size_t secretlen,const ngtcp2_crypto_aead_ctx * aead_ctx,const uint8_t * iv,size_t ivlen,const ngtcp2_mem * mem)35 int ngtcp2_crypto_km_new(ngtcp2_crypto_km **pckm, const uint8_t *secret,
36                          size_t secretlen,
37                          const ngtcp2_crypto_aead_ctx *aead_ctx,
38                          const uint8_t *iv, size_t ivlen,
39                          const ngtcp2_mem *mem) {
40   int rv = ngtcp2_crypto_km_nocopy_new(pckm, secretlen, ivlen, mem);
41   if (rv != 0) {
42     return rv;
43   }
44 
45   if (secretlen) {
46     memcpy((*pckm)->secret.base, secret, secretlen);
47   }
48   if (aead_ctx) {
49     (*pckm)->aead_ctx = *aead_ctx;
50   }
51   memcpy((*pckm)->iv.base, iv, ivlen);
52 
53   return 0;
54 }
55 
ngtcp2_crypto_km_nocopy_new(ngtcp2_crypto_km ** pckm,size_t secretlen,size_t ivlen,const ngtcp2_mem * mem)56 int ngtcp2_crypto_km_nocopy_new(ngtcp2_crypto_km **pckm, size_t secretlen,
57                                 size_t ivlen, const ngtcp2_mem *mem) {
58   size_t len;
59   uint8_t *p;
60 
61   len = sizeof(ngtcp2_crypto_km) + secretlen + ivlen;
62 
63   *pckm = ngtcp2_mem_malloc(mem, len);
64   if (*pckm == NULL) {
65     return NGTCP2_ERR_NOMEM;
66   }
67 
68   p = (uint8_t *)(*pckm) + sizeof(ngtcp2_crypto_km);
69   (*pckm)->secret.base = p;
70   (*pckm)->secret.len = secretlen;
71   p += secretlen;
72   (*pckm)->iv.base = p;
73   (*pckm)->iv.len = ivlen;
74   (*pckm)->aead_ctx.native_handle = NULL;
75   (*pckm)->pkt_num = -1;
76   (*pckm)->use_count = 0;
77   (*pckm)->flags = NGTCP2_CRYPTO_KM_FLAG_NONE;
78 
79   return 0;
80 }
81 
ngtcp2_crypto_km_del(ngtcp2_crypto_km * ckm,const ngtcp2_mem * mem)82 void ngtcp2_crypto_km_del(ngtcp2_crypto_km *ckm, const ngtcp2_mem *mem) {
83   if (ckm == NULL) {
84     return;
85   }
86 
87   ngtcp2_mem_free(mem, ckm);
88 }
89 
ngtcp2_crypto_create_nonce(uint8_t * dest,const uint8_t * iv,size_t ivlen,int64_t pkt_num)90 void ngtcp2_crypto_create_nonce(uint8_t *dest, const uint8_t *iv, size_t ivlen,
91                                 int64_t pkt_num) {
92   size_t i;
93   uint64_t n;
94 
95   assert(ivlen >= 8);
96 
97   memcpy(dest, iv, ivlen);
98   n = ngtcp2_htonl64((uint64_t)pkt_num);
99 
100   for (i = 0; i < 8; ++i) {
101     dest[ivlen - 8 + i] ^= ((uint8_t *)&n)[i];
102   }
103 }
104 
105 /*
106  * varint_paramlen returns the length of a single transport parameter
107  * which has variable integer in its parameter.
108  */
varint_paramlen(ngtcp2_transport_param_id id,uint64_t param)109 static size_t varint_paramlen(ngtcp2_transport_param_id id, uint64_t param) {
110   size_t valuelen = ngtcp2_put_varint_len(param);
111   return ngtcp2_put_varint_len(id) + ngtcp2_put_varint_len(valuelen) + valuelen;
112 }
113 
114 /*
115  * write_varint_param writes parameter |id| of the given |value| in
116  * varint encoding.  It returns p + the number of bytes written.
117  */
write_varint_param(uint8_t * p,ngtcp2_transport_param_id id,uint64_t value)118 static uint8_t *write_varint_param(uint8_t *p, ngtcp2_transport_param_id id,
119                                    uint64_t value) {
120   p = ngtcp2_put_varint(p, id);
121   p = ngtcp2_put_varint(p, ngtcp2_put_varint_len(value));
122   return ngtcp2_put_varint(p, value);
123 }
124 
125 /*
126  * cid_paramlen returns the length of a single transport parameter
127  * which has |cid| as value.
128  */
cid_paramlen(ngtcp2_transport_param_id id,const ngtcp2_cid * cid)129 static size_t cid_paramlen(ngtcp2_transport_param_id id,
130                            const ngtcp2_cid *cid) {
131   return ngtcp2_put_varint_len(id) + ngtcp2_put_varint_len(cid->datalen) +
132          cid->datalen;
133 }
134 
135 /*
136  * write_cid_param writes parameter |id| of the given |cid|.  It
137  * returns p + the number of bytes written.
138  */
write_cid_param(uint8_t * p,ngtcp2_transport_param_id id,const ngtcp2_cid * cid)139 static uint8_t *write_cid_param(uint8_t *p, ngtcp2_transport_param_id id,
140                                 const ngtcp2_cid *cid) {
141   assert(cid->datalen == 0 || cid->datalen >= NGTCP2_MIN_CIDLEN);
142   assert(cid->datalen <= NGTCP2_MAX_CIDLEN);
143 
144   p = ngtcp2_put_varint(p, id);
145   p = ngtcp2_put_varint(p, cid->datalen);
146   if (cid->datalen) {
147     p = ngtcp2_cpymem(p, cid->data, cid->datalen);
148   }
149   return p;
150 }
151 
152 static const uint8_t empty_address[16];
153 
ngtcp2_encode_transport_params_versioned(uint8_t * dest,size_t destlen,ngtcp2_transport_params_type exttype,int transport_params_version,const ngtcp2_transport_params * params)154 ngtcp2_ssize ngtcp2_encode_transport_params_versioned(
155     uint8_t *dest, size_t destlen, ngtcp2_transport_params_type exttype,
156     int transport_params_version, const ngtcp2_transport_params *params) {
157   uint8_t *p;
158   size_t len = 0;
159   /* For some reason, gcc 7.3.0 requires this initialization. */
160   size_t preferred_addrlen = 0;
161   size_t version_infolen = 0;
162   (void)transport_params_version;
163 
164   switch (exttype) {
165   case NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO:
166     break;
167   case NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS:
168     len +=
169         cid_paramlen(NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID,
170                      &params->original_dcid);
171 
172     if (params->stateless_reset_token_present) {
173       len +=
174           ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN) +
175           ngtcp2_put_varint_len(NGTCP2_STATELESS_RESET_TOKENLEN) +
176           NGTCP2_STATELESS_RESET_TOKENLEN;
177     }
178     if (params->preferred_address_present) {
179       assert(params->preferred_address.cid.datalen >= NGTCP2_MIN_CIDLEN);
180       assert(params->preferred_address.cid.datalen <= NGTCP2_MAX_CIDLEN);
181       preferred_addrlen = 4 /* ipv4Address */ + 2 /* ipv4Port */ +
182                           16 /* ipv6Address */ + 2 /* ipv6Port */
183                           + 1 +
184                           params->preferred_address.cid.datalen /* CID */ +
185                           NGTCP2_STATELESS_RESET_TOKENLEN;
186       len += ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS) +
187              ngtcp2_put_varint_len(preferred_addrlen) + preferred_addrlen;
188     }
189     if (params->retry_scid_present) {
190       len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID,
191                           &params->retry_scid);
192     }
193     break;
194   default:
195     return NGTCP2_ERR_INVALID_ARGUMENT;
196   }
197 
198   len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID,
199                       &params->initial_scid);
200 
201   if (params->initial_max_stream_data_bidi_local) {
202     len += varint_paramlen(
203         NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
204         params->initial_max_stream_data_bidi_local);
205   }
206   if (params->initial_max_stream_data_bidi_remote) {
207     len += varint_paramlen(
208         NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
209         params->initial_max_stream_data_bidi_remote);
210   }
211   if (params->initial_max_stream_data_uni) {
212     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI,
213                            params->initial_max_stream_data_uni);
214   }
215   if (params->initial_max_data) {
216     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA,
217                            params->initial_max_data);
218   }
219   if (params->initial_max_streams_bidi) {
220     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI,
221                            params->initial_max_streams_bidi);
222   }
223   if (params->initial_max_streams_uni) {
224     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI,
225                            params->initial_max_streams_uni);
226   }
227   if (params->max_udp_payload_size !=
228       NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE) {
229     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE,
230                            params->max_udp_payload_size);
231   }
232   if (params->ack_delay_exponent != NGTCP2_DEFAULT_ACK_DELAY_EXPONENT) {
233     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT,
234                            params->ack_delay_exponent);
235   }
236   if (params->disable_active_migration) {
237     len +=
238         ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION) +
239         ngtcp2_put_varint_len(0);
240   }
241   if (params->max_ack_delay != NGTCP2_DEFAULT_MAX_ACK_DELAY) {
242     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY,
243                            params->max_ack_delay / NGTCP2_MILLISECONDS);
244   }
245   if (params->max_idle_timeout) {
246     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT,
247                            params->max_idle_timeout / NGTCP2_MILLISECONDS);
248   }
249   if (params->active_connection_id_limit &&
250       params->active_connection_id_limit !=
251           NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT) {
252     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT,
253                            params->active_connection_id_limit);
254   }
255   if (params->max_datagram_frame_size) {
256     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE,
257                            params->max_datagram_frame_size);
258   }
259   if (params->grease_quic_bit) {
260     len += ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT) +
261            ngtcp2_put_varint_len(0);
262   }
263   if (params->version_info_present) {
264     version_infolen = sizeof(uint32_t) + params->version_info.other_versionslen;
265     len += ngtcp2_put_varint_len(
266                NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION_DRAFT) +
267            ngtcp2_put_varint_len(version_infolen) + version_infolen;
268   }
269 
270   if (dest == NULL && destlen == 0) {
271     return (ngtcp2_ssize)len;
272   }
273 
274   if (destlen < len) {
275     return NGTCP2_ERR_NOBUF;
276   }
277 
278   p = dest;
279 
280   if (exttype == NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
281     p = write_cid_param(
282         p, NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID,
283         &params->original_dcid);
284 
285     if (params->stateless_reset_token_present) {
286       p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN);
287       p = ngtcp2_put_varint(p, sizeof(params->stateless_reset_token));
288       p = ngtcp2_cpymem(p, params->stateless_reset_token,
289                         sizeof(params->stateless_reset_token));
290     }
291     if (params->preferred_address_present) {
292       p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS);
293       p = ngtcp2_put_varint(p, preferred_addrlen);
294 
295       if (params->preferred_address.ipv4_present) {
296         p = ngtcp2_cpymem(p, params->preferred_address.ipv4_addr,
297                           sizeof(params->preferred_address.ipv4_addr));
298         p = ngtcp2_put_uint16be(p, params->preferred_address.ipv4_port);
299       } else {
300         p = ngtcp2_cpymem(p, empty_address,
301                           sizeof(params->preferred_address.ipv4_addr));
302         p = ngtcp2_put_uint16be(p, 0);
303       }
304 
305       if (params->preferred_address.ipv6_present) {
306         p = ngtcp2_cpymem(p, params->preferred_address.ipv6_addr,
307                           sizeof(params->preferred_address.ipv6_addr));
308         p = ngtcp2_put_uint16be(p, params->preferred_address.ipv6_port);
309       } else {
310         p = ngtcp2_cpymem(p, empty_address,
311                           sizeof(params->preferred_address.ipv6_addr));
312         p = ngtcp2_put_uint16be(p, 0);
313       }
314 
315       *p++ = (uint8_t)params->preferred_address.cid.datalen;
316       if (params->preferred_address.cid.datalen) {
317         p = ngtcp2_cpymem(p, params->preferred_address.cid.data,
318                           params->preferred_address.cid.datalen);
319       }
320       p = ngtcp2_cpymem(
321           p, params->preferred_address.stateless_reset_token,
322           sizeof(params->preferred_address.stateless_reset_token));
323     }
324     if (params->retry_scid_present) {
325       p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID,
326                           &params->retry_scid);
327     }
328   }
329 
330   p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID,
331                       &params->initial_scid);
332 
333   if (params->initial_max_stream_data_bidi_local) {
334     p = write_varint_param(
335         p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
336         params->initial_max_stream_data_bidi_local);
337   }
338 
339   if (params->initial_max_stream_data_bidi_remote) {
340     p = write_varint_param(
341         p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
342         params->initial_max_stream_data_bidi_remote);
343   }
344 
345   if (params->initial_max_stream_data_uni) {
346     p = write_varint_param(p,
347                            NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI,
348                            params->initial_max_stream_data_uni);
349   }
350 
351   if (params->initial_max_data) {
352     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA,
353                            params->initial_max_data);
354   }
355 
356   if (params->initial_max_streams_bidi) {
357     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI,
358                            params->initial_max_streams_bidi);
359   }
360 
361   if (params->initial_max_streams_uni) {
362     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI,
363                            params->initial_max_streams_uni);
364   }
365 
366   if (params->max_udp_payload_size !=
367       NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE) {
368     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE,
369                            params->max_udp_payload_size);
370   }
371 
372   if (params->ack_delay_exponent != NGTCP2_DEFAULT_ACK_DELAY_EXPONENT) {
373     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT,
374                            params->ack_delay_exponent);
375   }
376 
377   if (params->disable_active_migration) {
378     p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION);
379     p = ngtcp2_put_varint(p, 0);
380   }
381 
382   if (params->max_ack_delay != NGTCP2_DEFAULT_MAX_ACK_DELAY) {
383     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY,
384                            params->max_ack_delay / NGTCP2_MILLISECONDS);
385   }
386 
387   if (params->max_idle_timeout) {
388     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT,
389                            params->max_idle_timeout / NGTCP2_MILLISECONDS);
390   }
391 
392   if (params->active_connection_id_limit &&
393       params->active_connection_id_limit !=
394           NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT) {
395     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT,
396                            params->active_connection_id_limit);
397   }
398 
399   if (params->max_datagram_frame_size) {
400     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE,
401                            params->max_datagram_frame_size);
402   }
403 
404   if (params->grease_quic_bit) {
405     p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT);
406     p = ngtcp2_put_varint(p, 0);
407   }
408 
409   if (params->version_info_present) {
410     p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION_DRAFT);
411     p = ngtcp2_put_varint(p, version_infolen);
412     p = ngtcp2_put_uint32be(p, params->version_info.chosen_version);
413     if (params->version_info.other_versionslen) {
414       p = ngtcp2_cpymem(p, params->version_info.other_versions,
415                         params->version_info.other_versionslen);
416     }
417   }
418 
419   assert((size_t)(p - dest) == len);
420 
421   return (ngtcp2_ssize)len;
422 }
423 
424 /*
425  * decode_varint decodes a single varint from the buffer pointed by
426  * |p| of length |end - p|.  If it decodes an integer successfully, it
427  * stores the integer in |*pdest| and returns 0.  Otherwise it returns
428  * -1.
429  */
decode_varint(uint64_t * pdest,const uint8_t * p,const uint8_t * end)430 static ngtcp2_ssize decode_varint(uint64_t *pdest, const uint8_t *p,
431                                   const uint8_t *end) {
432   size_t len;
433 
434   if (p == end) {
435     return -1;
436   }
437 
438   len = ngtcp2_get_varint_len(p);
439   if ((uint64_t)(end - p) < len) {
440     return -1;
441   }
442 
443   *pdest = ngtcp2_get_varint(&len, p);
444 
445   return (ngtcp2_ssize)len;
446 }
447 
448 /*
449  * decode_varint_param decodes length prefixed value from the buffer
450  * pointed by |p| of length |end - p|.  The length and value are
451  * encoded in varint form.  If it decodes a value successfully, it
452  * stores the value in |*pdest| and returns 0.  Otherwise it returns
453  * -1.
454  */
decode_varint_param(uint64_t * pdest,const uint8_t * p,const uint8_t * end)455 static ngtcp2_ssize decode_varint_param(uint64_t *pdest, const uint8_t *p,
456                                         const uint8_t *end) {
457   const uint8_t *begin = p;
458   ngtcp2_ssize nread;
459   uint64_t valuelen;
460   size_t n;
461 
462   nread = decode_varint(&valuelen, p, end);
463   if (nread < 0) {
464     return -1;
465   }
466 
467   p += nread;
468 
469   if (p == end) {
470     return -1;
471   }
472 
473   if ((uint64_t)(end - p) < valuelen) {
474     return -1;
475   }
476 
477   if (ngtcp2_get_varint_len(p) != valuelen) {
478     return -1;
479   }
480 
481   *pdest = ngtcp2_get_varint(&n, p);
482 
483   p += valuelen;
484 
485   return (ngtcp2_ssize)(p - begin);
486 }
487 
488 /*
489  * decode_cid_param decodes length prefixed ngtcp2_cid from the buffer
490  * pointed by |p| of length |end - p|.  The length is encoded in
491  * varint form.  If it decodes a value successfully, it stores the
492  * value in |*pdest| and returns the number of bytes read.  Otherwise
493  * it returns -1.
494  */
decode_cid_param(ngtcp2_cid * pdest,const uint8_t * p,const uint8_t * end)495 static ngtcp2_ssize decode_cid_param(ngtcp2_cid *pdest, const uint8_t *p,
496                                      const uint8_t *end) {
497   const uint8_t *begin = p;
498   uint64_t valuelen;
499   ngtcp2_ssize nread = decode_varint(&valuelen, p, end);
500 
501   if (nread < 0) {
502     return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
503   }
504 
505   p += nread;
506 
507   if ((valuelen != 0 && valuelen < NGTCP2_MIN_CIDLEN) ||
508       valuelen > NGTCP2_MAX_CIDLEN || (size_t)(end - p) < valuelen) {
509     return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
510   }
511 
512   ngtcp2_cid_init(pdest, p, (size_t)valuelen);
513 
514   p += valuelen;
515 
516   return (ngtcp2_ssize)(p - begin);
517 }
518 
ngtcp2_decode_transport_params_versioned(int transport_params_version,ngtcp2_transport_params * params,ngtcp2_transport_params_type exttype,const uint8_t * data,size_t datalen)519 int ngtcp2_decode_transport_params_versioned(
520     int transport_params_version, ngtcp2_transport_params *params,
521     ngtcp2_transport_params_type exttype, const uint8_t *data, size_t datalen) {
522   const uint8_t *p, *end;
523   size_t len;
524   uint64_t param_type;
525   uint64_t valuelen;
526   ngtcp2_ssize nread;
527   int initial_scid_present = 0;
528   int original_dcid_present = 0;
529   size_t i;
530   (void)transport_params_version;
531 
532   if (datalen == 0) {
533     return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM;
534   }
535 
536   /* Set default values */
537   memset(params, 0, sizeof(*params));
538   params->initial_max_streams_bidi = 0;
539   params->initial_max_streams_uni = 0;
540   params->initial_max_stream_data_bidi_local = 0;
541   params->initial_max_stream_data_bidi_remote = 0;
542   params->initial_max_stream_data_uni = 0;
543   params->max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE;
544   params->ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT;
545   params->stateless_reset_token_present = 0;
546   params->preferred_address_present = 0;
547   params->disable_active_migration = 0;
548   params->max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY;
549   params->max_idle_timeout = 0;
550   params->active_connection_id_limit =
551       NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT;
552   params->retry_scid_present = 0;
553   params->max_datagram_frame_size = 0;
554   memset(&params->retry_scid, 0, sizeof(params->retry_scid));
555   memset(&params->initial_scid, 0, sizeof(params->initial_scid));
556   memset(&params->original_dcid, 0, sizeof(params->original_dcid));
557   params->version_info_present = 0;
558 
559   p = data;
560   end = data + datalen;
561 
562   for (; (size_t)(end - p) >= 2;) {
563     nread = decode_varint(&param_type, p, end);
564     if (nread < 0) {
565       return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
566     }
567     p += nread;
568 
569     switch (param_type) {
570     case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
571       nread = decode_varint_param(&params->initial_max_stream_data_bidi_local,
572                                   p, end);
573       if (nread < 0) {
574         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
575       }
576       p += nread;
577       break;
578     case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
579       nread = decode_varint_param(&params->initial_max_stream_data_bidi_remote,
580                                   p, end);
581       if (nread < 0) {
582         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
583       }
584       p += nread;
585       break;
586     case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI:
587       nread = decode_varint_param(&params->initial_max_stream_data_uni, p, end);
588       if (nread < 0) {
589         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
590       }
591       p += nread;
592       break;
593     case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA:
594       nread = decode_varint_param(&params->initial_max_data, p, end);
595       if (nread < 0) {
596         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
597       }
598       p += nread;
599       break;
600     case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI:
601       nread = decode_varint_param(&params->initial_max_streams_bidi, p, end);
602       if (nread < 0) {
603         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
604       }
605       if (params->initial_max_streams_bidi > NGTCP2_MAX_STREAMS) {
606         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
607       }
608       p += nread;
609       break;
610     case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI:
611       nread = decode_varint_param(&params->initial_max_streams_uni, p, end);
612       if (nread < 0) {
613         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
614       }
615       if (params->initial_max_streams_uni > NGTCP2_MAX_STREAMS) {
616         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
617       }
618       p += nread;
619       break;
620     case NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT:
621       nread = decode_varint_param(&params->max_idle_timeout, p, end);
622       if (nread < 0) {
623         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
624       }
625       params->max_idle_timeout *= NGTCP2_MILLISECONDS;
626       p += nread;
627       break;
628     case NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE:
629       nread = decode_varint_param(&params->max_udp_payload_size, p, end);
630       if (nread < 0) {
631         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
632       }
633       p += nread;
634       break;
635     case NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN:
636       if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
637         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
638       }
639       nread = decode_varint(&valuelen, p, end);
640       if (nread < 0) {
641         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
642       }
643       p += nread;
644       if ((size_t)valuelen != sizeof(params->stateless_reset_token)) {
645         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
646       }
647       if ((size_t)(end - p) < sizeof(params->stateless_reset_token)) {
648         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
649       }
650 
651       memcpy(params->stateless_reset_token, p,
652              sizeof(params->stateless_reset_token));
653       params->stateless_reset_token_present = 1;
654 
655       p += sizeof(params->stateless_reset_token);
656       break;
657     case NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT:
658       nread = decode_varint_param(&params->ack_delay_exponent, p, end);
659       if (nread < 0 || params->ack_delay_exponent > 20) {
660         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
661       }
662       p += nread;
663       break;
664     case NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS:
665       if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
666         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
667       }
668       nread = decode_varint(&valuelen, p, end);
669       if (nread < 0) {
670         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
671       }
672       p += nread;
673       if ((size_t)(end - p) < valuelen) {
674         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
675       }
676       len = 4 /* ipv4Address */ + 2 /* ipv4Port */ + 16 /* ipv6Address */ +
677             2 /* ipv6Port */
678             + 1 /* cid length */ + NGTCP2_STATELESS_RESET_TOKENLEN;
679       if (valuelen < len) {
680         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
681       }
682 
683       memcpy(params->preferred_address.ipv4_addr, p,
684              sizeof(params->preferred_address.ipv4_addr));
685       p += sizeof(params->preferred_address.ipv4_addr);
686       params->preferred_address.ipv4_port = ngtcp2_get_uint16(p);
687       p += sizeof(uint16_t);
688 
689       if (params->preferred_address.ipv4_port ||
690           memcmp(empty_address, params->preferred_address.ipv4_addr,
691                  sizeof(params->preferred_address.ipv4_addr)) != 0) {
692         params->preferred_address.ipv4_present = 1;
693       }
694 
695       memcpy(params->preferred_address.ipv6_addr, p,
696              sizeof(params->preferred_address.ipv6_addr));
697       p += sizeof(params->preferred_address.ipv6_addr);
698       params->preferred_address.ipv6_port = ngtcp2_get_uint16(p);
699       p += sizeof(uint16_t);
700 
701       if (params->preferred_address.ipv6_port ||
702           memcmp(empty_address, params->preferred_address.ipv6_addr,
703                  sizeof(params->preferred_address.ipv6_addr)) != 0) {
704         params->preferred_address.ipv6_present = 1;
705       }
706 
707       /* cid */
708       params->preferred_address.cid.datalen = *p++;
709       len += params->preferred_address.cid.datalen;
710       if (valuelen != len ||
711           params->preferred_address.cid.datalen > NGTCP2_MAX_CIDLEN ||
712           params->preferred_address.cid.datalen < NGTCP2_MIN_CIDLEN) {
713         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
714       }
715       if (params->preferred_address.cid.datalen) {
716         memcpy(params->preferred_address.cid.data, p,
717                params->preferred_address.cid.datalen);
718         p += params->preferred_address.cid.datalen;
719       }
720 
721       /* stateless reset token */
722       memcpy(params->preferred_address.stateless_reset_token, p,
723              sizeof(params->preferred_address.stateless_reset_token));
724       p += sizeof(params->preferred_address.stateless_reset_token);
725       params->preferred_address_present = 1;
726       break;
727     case NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION:
728       nread = decode_varint(&valuelen, p, end);
729       if (nread < 0 || valuelen != 0) {
730         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
731       }
732       p += nread;
733       params->disable_active_migration = 1;
734       break;
735     case NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID:
736       if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
737         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
738       }
739       nread = decode_cid_param(&params->original_dcid, p, end);
740       if (nread < 0) {
741         return (int)nread;
742       }
743       original_dcid_present = 1;
744       p += nread;
745       break;
746     case NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID:
747       if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
748         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
749       }
750       nread = decode_cid_param(&params->retry_scid, p, end);
751       if (nread < 0) {
752         return (int)nread;
753       }
754       params->retry_scid_present = 1;
755       p += nread;
756       break;
757     case NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID:
758       nread = decode_cid_param(&params->initial_scid, p, end);
759       if (nread < 0) {
760         return (int)nread;
761       }
762       initial_scid_present = 1;
763       p += nread;
764       break;
765     case NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY:
766       nread = decode_varint_param(&params->max_ack_delay, p, end);
767       if (nread < 0 || params->max_ack_delay >= 16384) {
768         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
769       }
770       params->max_ack_delay *= NGTCP2_MILLISECONDS;
771       p += nread;
772       break;
773     case NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT:
774       nread = decode_varint_param(&params->active_connection_id_limit, p, end);
775       if (nread < 0) {
776         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
777       }
778       p += nread;
779       break;
780     case NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE:
781       nread = decode_varint_param(&params->max_datagram_frame_size, p, end);
782       if (nread < 0) {
783         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
784       }
785       p += nread;
786       break;
787     case NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT:
788       nread = decode_varint(&valuelen, p, end);
789       if (nread < 0 || valuelen != 0) {
790         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
791       }
792       p += nread;
793       params->grease_quic_bit = 1;
794       break;
795     case NGTCP2_TRANSPORT_PARAM_VERSION_INFORMATION_DRAFT:
796       nread = decode_varint(&valuelen, p, end);
797       if (nread < 0) {
798         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
799       }
800       p += nread;
801       if ((size_t)(end - p) < valuelen) {
802         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
803       }
804       if (valuelen < sizeof(uint32_t) || (valuelen & 0x3)) {
805         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
806       }
807       params->version_info.chosen_version = ngtcp2_get_uint32(p);
808       if (params->version_info.chosen_version == 0) {
809         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
810       }
811       p += sizeof(uint32_t);
812       if (valuelen > sizeof(uint32_t)) {
813         params->version_info.other_versions = (uint8_t *)p;
814         params->version_info.other_versionslen =
815             (size_t)valuelen - sizeof(uint32_t);
816 
817         for (i = sizeof(uint32_t); i < valuelen;
818              i += sizeof(uint32_t), p += sizeof(uint32_t)) {
819           if (ngtcp2_get_uint32(p) == 0) {
820             return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
821           }
822         }
823       }
824       params->version_info_present = 1;
825       break;
826     default:
827       /* Ignore unknown parameter */
828       nread = decode_varint(&valuelen, p, end);
829       if (nread < 0) {
830         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
831       }
832       p += nread;
833       if ((size_t)(end - p) < valuelen) {
834         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
835       }
836       p += valuelen;
837       break;
838     }
839   }
840 
841   if (end - p != 0) {
842     return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
843   }
844 
845   if (!initial_scid_present ||
846       (exttype == NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS &&
847        !original_dcid_present)) {
848     return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM;
849   }
850 
851   return 0;
852 }
853 
transport_params_copy_new(ngtcp2_transport_params ** pdest,const ngtcp2_transport_params * src,const ngtcp2_mem * mem)854 static int transport_params_copy_new(ngtcp2_transport_params **pdest,
855                                      const ngtcp2_transport_params *src,
856                                      const ngtcp2_mem *mem) {
857   size_t len = sizeof(**pdest);
858   ngtcp2_transport_params *dest;
859   uint8_t *p;
860 
861   if (src->version_info_present) {
862     len += src->version_info.other_versionslen;
863   }
864 
865   dest = ngtcp2_mem_malloc(mem, len);
866   if (dest == NULL) {
867     return NGTCP2_ERR_NOMEM;
868   }
869 
870   *dest = *src;
871 
872   if (src->version_info_present && src->version_info.other_versionslen) {
873     p = (uint8_t *)dest + sizeof(*dest);
874     memcpy(p, src->version_info.other_versions,
875            src->version_info.other_versionslen);
876     dest->version_info.other_versions = p;
877   }
878 
879   *pdest = dest;
880 
881   return 0;
882 }
883 
ngtcp2_decode_transport_params_new(ngtcp2_transport_params ** pparams,ngtcp2_transport_params_type exttype,const uint8_t * data,size_t datalen,const ngtcp2_mem * mem)884 int ngtcp2_decode_transport_params_new(ngtcp2_transport_params **pparams,
885                                        ngtcp2_transport_params_type exttype,
886                                        const uint8_t *data, size_t datalen,
887                                        const ngtcp2_mem *mem) {
888   int rv;
889   ngtcp2_transport_params params;
890 
891   rv = ngtcp2_decode_transport_params(&params, exttype, data, datalen);
892   if (rv < 0) {
893     return rv;
894   }
895 
896   if (mem == NULL) {
897     mem = ngtcp2_mem_default();
898   }
899 
900   return transport_params_copy_new(pparams, &params, mem);
901 }
902 
ngtcp2_transport_params_del(ngtcp2_transport_params * params,const ngtcp2_mem * mem)903 void ngtcp2_transport_params_del(ngtcp2_transport_params *params,
904                                  const ngtcp2_mem *mem) {
905   if (params == NULL) {
906     return;
907   }
908 
909   if (mem == NULL) {
910     mem = ngtcp2_mem_default();
911   }
912 
913   ngtcp2_mem_free(mem, params);
914 }
915 
ngtcp2_transport_params_copy_new(ngtcp2_transport_params ** pdest,const ngtcp2_transport_params * src,const ngtcp2_mem * mem)916 int ngtcp2_transport_params_copy_new(ngtcp2_transport_params **pdest,
917                                      const ngtcp2_transport_params *src,
918                                      const ngtcp2_mem *mem) {
919   if (src == NULL) {
920     *pdest = NULL;
921     return 0;
922   }
923 
924   return transport_params_copy_new(pdest, src, mem);
925 }
926