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 
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)34 int ngtcp2_crypto_km_new(ngtcp2_crypto_km **pckm, const uint8_t *secret,
35                          size_t secretlen,
36                          const ngtcp2_crypto_aead_ctx *aead_ctx,
37                          const uint8_t *iv, size_t ivlen,
38                          const ngtcp2_mem *mem) {
39   int rv = ngtcp2_crypto_km_nocopy_new(pckm, secretlen, ivlen, mem);
40   if (rv != 0) {
41     return rv;
42   }
43 
44   if (secretlen) {
45     memcpy((*pckm)->secret.base, secret, secretlen);
46   }
47   if (aead_ctx) {
48     (*pckm)->aead_ctx = *aead_ctx;
49   }
50   memcpy((*pckm)->iv.base, iv, ivlen);
51 
52   return 0;
53 }
54 
ngtcp2_crypto_km_nocopy_new(ngtcp2_crypto_km ** pckm,size_t secretlen,size_t ivlen,const ngtcp2_mem * mem)55 int ngtcp2_crypto_km_nocopy_new(ngtcp2_crypto_km **pckm, size_t secretlen,
56                                 size_t ivlen, const ngtcp2_mem *mem) {
57   size_t len;
58   uint8_t *p;
59 
60   len = sizeof(ngtcp2_crypto_km) + secretlen + ivlen;
61 
62   *pckm = ngtcp2_mem_malloc(mem, len);
63   if (*pckm == NULL) {
64     return NGTCP2_ERR_NOMEM;
65   }
66 
67   p = (uint8_t *)(*pckm) + sizeof(ngtcp2_crypto_km);
68   (*pckm)->secret.base = p;
69   (*pckm)->secret.len = secretlen;
70   p += secretlen;
71   (*pckm)->iv.base = p;
72   (*pckm)->iv.len = ivlen;
73   (*pckm)->aead_ctx.native_handle = NULL;
74   (*pckm)->pkt_num = -1;
75   (*pckm)->use_count = 0;
76   (*pckm)->flags = NGTCP2_CRYPTO_KM_FLAG_NONE;
77 
78   return 0;
79 }
80 
ngtcp2_crypto_km_del(ngtcp2_crypto_km * ckm,const ngtcp2_mem * mem)81 void ngtcp2_crypto_km_del(ngtcp2_crypto_km *ckm, const ngtcp2_mem *mem) {
82   if (ckm == NULL) {
83     return;
84   }
85 
86   ngtcp2_mem_free(mem, ckm);
87 }
88 
ngtcp2_crypto_create_nonce(uint8_t * dest,const uint8_t * iv,size_t ivlen,int64_t pkt_num)89 void ngtcp2_crypto_create_nonce(uint8_t *dest, const uint8_t *iv, size_t ivlen,
90                                 int64_t pkt_num) {
91   size_t i;
92   uint64_t n;
93 
94   assert(ivlen >= 8);
95 
96   memcpy(dest, iv, ivlen);
97   n = ngtcp2_htonl64((uint64_t)pkt_num);
98 
99   for (i = 0; i < 8; ++i) {
100     dest[ivlen - 8 + i] ^= ((uint8_t *)&n)[i];
101   }
102 }
103 
104 /*
105  * varint_paramlen returns the length of a single transport parameter
106  * which has variable integer in its parameter.
107  */
varint_paramlen(ngtcp2_transport_param_id id,uint64_t param)108 static size_t varint_paramlen(ngtcp2_transport_param_id id, uint64_t param) {
109   size_t valuelen = ngtcp2_put_varint_len(param);
110   return ngtcp2_put_varint_len(id) + ngtcp2_put_varint_len(valuelen) + valuelen;
111 }
112 
113 /*
114  * write_varint_param writes parameter |id| of the given |value| in
115  * varint encoding.  It returns p + the number of bytes written.
116  */
write_varint_param(uint8_t * p,ngtcp2_transport_param_id id,uint64_t value)117 static uint8_t *write_varint_param(uint8_t *p, ngtcp2_transport_param_id id,
118                                    uint64_t value) {
119   p = ngtcp2_put_varint(p, id);
120   p = ngtcp2_put_varint(p, ngtcp2_put_varint_len(value));
121   return ngtcp2_put_varint(p, value);
122 }
123 
124 /*
125  * cid_paramlen returns the length of a single transport parameter
126  * which has |cid| as value.
127  */
cid_paramlen(ngtcp2_transport_param_id id,const ngtcp2_cid * cid)128 static size_t cid_paramlen(ngtcp2_transport_param_id id,
129                            const ngtcp2_cid *cid) {
130   return ngtcp2_put_varint_len(id) + ngtcp2_put_varint_len(cid->datalen) +
131          cid->datalen;
132 }
133 
134 /*
135  * write_cid_param writes parameter |id| of the given |cid|.  It
136  * returns p + the number of bytes written.
137  */
write_cid_param(uint8_t * p,ngtcp2_transport_param_id id,const ngtcp2_cid * cid)138 static uint8_t *write_cid_param(uint8_t *p, ngtcp2_transport_param_id id,
139                                 const ngtcp2_cid *cid) {
140   assert(cid->datalen == 0 || cid->datalen >= NGTCP2_MIN_CIDLEN);
141   assert(cid->datalen <= NGTCP2_MAX_CIDLEN);
142 
143   p = ngtcp2_put_varint(p, id);
144   p = ngtcp2_put_varint(p, cid->datalen);
145   if (cid->datalen) {
146     p = ngtcp2_cpymem(p, cid->data, cid->datalen);
147   }
148   return p;
149 }
150 
151 static const uint8_t empty_address[16];
152 
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)153 ngtcp2_ssize ngtcp2_encode_transport_params_versioned(
154     uint8_t *dest, size_t destlen, ngtcp2_transport_params_type exttype,
155     int transport_params_version, const ngtcp2_transport_params *params) {
156   uint8_t *p;
157   size_t len = 0;
158   /* For some reason, gcc 7.3.0 requires this initialization. */
159   size_t preferred_addrlen = 0;
160   (void)transport_params_version;
161 
162   switch (exttype) {
163   case NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO:
164     break;
165   case NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS:
166     len +=
167         cid_paramlen(NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID,
168                      &params->original_dcid);
169 
170     if (params->stateless_reset_token_present) {
171       len +=
172           ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN) +
173           ngtcp2_put_varint_len(NGTCP2_STATELESS_RESET_TOKENLEN) +
174           NGTCP2_STATELESS_RESET_TOKENLEN;
175     }
176     if (params->preferred_address_present) {
177       assert(params->preferred_address.cid.datalen >= NGTCP2_MIN_CIDLEN);
178       assert(params->preferred_address.cid.datalen <= NGTCP2_MAX_CIDLEN);
179       preferred_addrlen = 4 /* ipv4Address */ + 2 /* ipv4Port */ +
180                           16 /* ipv6Address */ + 2 /* ipv6Port */
181                           + 1 +
182                           params->preferred_address.cid.datalen /* CID */ +
183                           NGTCP2_STATELESS_RESET_TOKENLEN;
184       len += ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS) +
185              ngtcp2_put_varint_len(preferred_addrlen) + preferred_addrlen;
186     }
187     if (params->retry_scid_present) {
188       len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID,
189                           &params->retry_scid);
190     }
191     break;
192   default:
193     return NGTCP2_ERR_INVALID_ARGUMENT;
194   }
195 
196   len += cid_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID,
197                       &params->initial_scid);
198 
199   if (params->initial_max_stream_data_bidi_local) {
200     len += varint_paramlen(
201         NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
202         params->initial_max_stream_data_bidi_local);
203   }
204   if (params->initial_max_stream_data_bidi_remote) {
205     len += varint_paramlen(
206         NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
207         params->initial_max_stream_data_bidi_remote);
208   }
209   if (params->initial_max_stream_data_uni) {
210     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI,
211                            params->initial_max_stream_data_uni);
212   }
213   if (params->initial_max_data) {
214     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA,
215                            params->initial_max_data);
216   }
217   if (params->initial_max_streams_bidi) {
218     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI,
219                            params->initial_max_streams_bidi);
220   }
221   if (params->initial_max_streams_uni) {
222     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI,
223                            params->initial_max_streams_uni);
224   }
225   if (params->max_udp_payload_size !=
226       NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE) {
227     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE,
228                            params->max_udp_payload_size);
229   }
230   if (params->ack_delay_exponent != NGTCP2_DEFAULT_ACK_DELAY_EXPONENT) {
231     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT,
232                            params->ack_delay_exponent);
233   }
234   if (params->disable_active_migration) {
235     len +=
236         ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION) +
237         ngtcp2_put_varint_len(0);
238   }
239   if (params->max_ack_delay != NGTCP2_DEFAULT_MAX_ACK_DELAY) {
240     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY,
241                            params->max_ack_delay / NGTCP2_MILLISECONDS);
242   }
243   if (params->max_idle_timeout) {
244     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT,
245                            params->max_idle_timeout / NGTCP2_MILLISECONDS);
246   }
247   if (params->active_connection_id_limit &&
248       params->active_connection_id_limit !=
249           NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT) {
250     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT,
251                            params->active_connection_id_limit);
252   }
253   if (params->max_datagram_frame_size) {
254     len += varint_paramlen(NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE,
255                            params->max_datagram_frame_size);
256   }
257   if (params->grease_quic_bit) {
258     len += ngtcp2_put_varint_len(NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT) +
259            ngtcp2_put_varint_len(0);
260   }
261 
262   if (destlen < len) {
263     return NGTCP2_ERR_NOBUF;
264   }
265 
266   p = dest;
267 
268   if (exttype == NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
269     p = write_cid_param(
270         p, NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID,
271         &params->original_dcid);
272 
273     if (params->stateless_reset_token_present) {
274       p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN);
275       p = ngtcp2_put_varint(p, sizeof(params->stateless_reset_token));
276       p = ngtcp2_cpymem(p, params->stateless_reset_token,
277                         sizeof(params->stateless_reset_token));
278     }
279     if (params->preferred_address_present) {
280       p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS);
281       p = ngtcp2_put_varint(p, preferred_addrlen);
282 
283       if (params->preferred_address.ipv4_present) {
284         p = ngtcp2_cpymem(p, params->preferred_address.ipv4_addr,
285                           sizeof(params->preferred_address.ipv4_addr));
286         p = ngtcp2_put_uint16be(p, params->preferred_address.ipv4_port);
287       } else {
288         p = ngtcp2_cpymem(p, empty_address,
289                           sizeof(params->preferred_address.ipv4_addr));
290         p = ngtcp2_put_uint16be(p, 0);
291       }
292 
293       if (params->preferred_address.ipv6_present) {
294         p = ngtcp2_cpymem(p, params->preferred_address.ipv6_addr,
295                           sizeof(params->preferred_address.ipv6_addr));
296         p = ngtcp2_put_uint16be(p, params->preferred_address.ipv6_port);
297       } else {
298         p = ngtcp2_cpymem(p, empty_address,
299                           sizeof(params->preferred_address.ipv6_addr));
300         p = ngtcp2_put_uint16be(p, 0);
301       }
302 
303       *p++ = (uint8_t)params->preferred_address.cid.datalen;
304       if (params->preferred_address.cid.datalen) {
305         p = ngtcp2_cpymem(p, params->preferred_address.cid.data,
306                           params->preferred_address.cid.datalen);
307       }
308       p = ngtcp2_cpymem(
309           p, params->preferred_address.stateless_reset_token,
310           sizeof(params->preferred_address.stateless_reset_token));
311     }
312     if (params->retry_scid_present) {
313       p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID,
314                           &params->retry_scid);
315     }
316   }
317 
318   p = write_cid_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID,
319                       &params->initial_scid);
320 
321   if (params->initial_max_stream_data_bidi_local) {
322     p = write_varint_param(
323         p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
324         params->initial_max_stream_data_bidi_local);
325   }
326 
327   if (params->initial_max_stream_data_bidi_remote) {
328     p = write_varint_param(
329         p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
330         params->initial_max_stream_data_bidi_remote);
331   }
332 
333   if (params->initial_max_stream_data_uni) {
334     p = write_varint_param(p,
335                            NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI,
336                            params->initial_max_stream_data_uni);
337   }
338 
339   if (params->initial_max_data) {
340     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA,
341                            params->initial_max_data);
342   }
343 
344   if (params->initial_max_streams_bidi) {
345     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI,
346                            params->initial_max_streams_bidi);
347   }
348 
349   if (params->initial_max_streams_uni) {
350     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI,
351                            params->initial_max_streams_uni);
352   }
353 
354   if (params->max_udp_payload_size !=
355       NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE) {
356     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE,
357                            params->max_udp_payload_size);
358   }
359 
360   if (params->ack_delay_exponent != NGTCP2_DEFAULT_ACK_DELAY_EXPONENT) {
361     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT,
362                            params->ack_delay_exponent);
363   }
364 
365   if (params->disable_active_migration) {
366     p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION);
367     p = ngtcp2_put_varint(p, 0);
368   }
369 
370   if (params->max_ack_delay != NGTCP2_DEFAULT_MAX_ACK_DELAY) {
371     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY,
372                            params->max_ack_delay / NGTCP2_MILLISECONDS);
373   }
374 
375   if (params->max_idle_timeout) {
376     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT,
377                            params->max_idle_timeout / NGTCP2_MILLISECONDS);
378   }
379 
380   if (params->active_connection_id_limit &&
381       params->active_connection_id_limit !=
382           NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT) {
383     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT,
384                            params->active_connection_id_limit);
385   }
386 
387   if (params->max_datagram_frame_size) {
388     p = write_varint_param(p, NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE,
389                            params->max_datagram_frame_size);
390   }
391 
392   if (params->grease_quic_bit) {
393     p = ngtcp2_put_varint(p, NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT);
394     p = ngtcp2_put_varint(p, 0);
395   }
396 
397   assert((size_t)(p - dest) == len);
398 
399   return (ngtcp2_ssize)len;
400 }
401 
402 /*
403  * decode_varint decodes a single varint from the buffer pointed by
404  * |p| of length |end - p|.  If it decodes an integer successfully, it
405  * stores the integer in |*pdest| and returns 0.  Otherwise it returns
406  * -1.
407  */
decode_varint(uint64_t * pdest,const uint8_t * p,const uint8_t * end)408 static ngtcp2_ssize decode_varint(uint64_t *pdest, const uint8_t *p,
409                                   const uint8_t *end) {
410   size_t len;
411 
412   if (p == end) {
413     return -1;
414   }
415 
416   len = ngtcp2_get_varint_len(p);
417   if ((uint64_t)(end - p) < len) {
418     return -1;
419   }
420 
421   *pdest = ngtcp2_get_varint(&len, p);
422 
423   return (ngtcp2_ssize)len;
424 }
425 
426 /*
427  * decode_varint_param decodes length prefixed value from the buffer
428  * pointed by |p| of length |end - p|.  The length and value are
429  * encoded in varint form.  If it decodes a value successfully, it
430  * stores the value in |*pdest| and returns 0.  Otherwise it returns
431  * -1.
432  */
decode_varint_param(uint64_t * pdest,const uint8_t * p,const uint8_t * end)433 static ngtcp2_ssize decode_varint_param(uint64_t *pdest, const uint8_t *p,
434                                         const uint8_t *end) {
435   const uint8_t *begin = p;
436   ngtcp2_ssize nread;
437   uint64_t valuelen;
438   size_t n;
439 
440   nread = decode_varint(&valuelen, p, end);
441   if (nread < 0) {
442     return -1;
443   }
444 
445   p += nread;
446 
447   if (p == end) {
448     return -1;
449   }
450 
451   if ((uint64_t)(end - p) < valuelen) {
452     return -1;
453   }
454 
455   if (ngtcp2_get_varint_len(p) != valuelen) {
456     return -1;
457   }
458 
459   *pdest = ngtcp2_get_varint(&n, p);
460 
461   p += valuelen;
462 
463   return (ngtcp2_ssize)(p - begin);
464 }
465 
466 /*
467  * decode_cid_param decodes length prefixed ngtcp2_cid from the buffer
468  * pointed by |p| of length |end - p|.  The length is encoded in
469  * varint form.  If it decodes a value successfully, it stores the
470  * value in |*pdest| and returns the number of bytes read.  Otherwise
471  * it returns -1.
472  */
decode_cid_param(ngtcp2_cid * pdest,const uint8_t * p,const uint8_t * end)473 static ngtcp2_ssize decode_cid_param(ngtcp2_cid *pdest, const uint8_t *p,
474                                      const uint8_t *end) {
475   const uint8_t *begin = p;
476   uint64_t valuelen;
477   ngtcp2_ssize nread = decode_varint(&valuelen, p, end);
478 
479   if (nread < 0) {
480     return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
481   }
482 
483   p += nread;
484 
485   if ((valuelen != 0 && valuelen < NGTCP2_MIN_CIDLEN) ||
486       valuelen > NGTCP2_MAX_CIDLEN || (size_t)(end - p) < valuelen) {
487     return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
488   }
489 
490   ngtcp2_cid_init(pdest, p, (size_t)valuelen);
491 
492   p += valuelen;
493 
494   return (ngtcp2_ssize)(p - begin);
495 }
496 
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)497 int ngtcp2_decode_transport_params_versioned(
498     int transport_params_version, ngtcp2_transport_params *params,
499     ngtcp2_transport_params_type exttype, const uint8_t *data, size_t datalen) {
500   const uint8_t *p, *end;
501   size_t len;
502   uint64_t param_type;
503   uint64_t valuelen;
504   ngtcp2_ssize nread;
505   int initial_scid_present = 0;
506   int original_dcid_present = 0;
507   (void)transport_params_version;
508 
509   if (datalen == 0) {
510     return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM;
511   }
512 
513   /* Set default values */
514   memset(params, 0, sizeof(*params));
515   params->initial_max_streams_bidi = 0;
516   params->initial_max_streams_uni = 0;
517   params->initial_max_stream_data_bidi_local = 0;
518   params->initial_max_stream_data_bidi_remote = 0;
519   params->initial_max_stream_data_uni = 0;
520   params->max_udp_payload_size = NGTCP2_DEFAULT_MAX_RECV_UDP_PAYLOAD_SIZE;
521   params->ack_delay_exponent = NGTCP2_DEFAULT_ACK_DELAY_EXPONENT;
522   params->stateless_reset_token_present = 0;
523   params->preferred_address_present = 0;
524   params->disable_active_migration = 0;
525   params->max_ack_delay = NGTCP2_DEFAULT_MAX_ACK_DELAY;
526   params->max_idle_timeout = 0;
527   params->active_connection_id_limit =
528       NGTCP2_DEFAULT_ACTIVE_CONNECTION_ID_LIMIT;
529   params->retry_scid_present = 0;
530   params->max_datagram_frame_size = 0;
531   memset(&params->retry_scid, 0, sizeof(params->retry_scid));
532   memset(&params->initial_scid, 0, sizeof(params->initial_scid));
533   memset(&params->original_dcid, 0, sizeof(params->original_dcid));
534 
535   p = data;
536   end = data + datalen;
537 
538   for (; (size_t)(end - p) >= 2;) {
539     nread = decode_varint(&param_type, p, end);
540     if (nread < 0) {
541       return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
542     }
543     p += nread;
544 
545     switch (param_type) {
546     case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
547       nread = decode_varint_param(&params->initial_max_stream_data_bidi_local,
548                                   p, end);
549       if (nread < 0) {
550         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
551       }
552       p += nread;
553       break;
554     case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
555       nread = decode_varint_param(&params->initial_max_stream_data_bidi_remote,
556                                   p, end);
557       if (nread < 0) {
558         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
559       }
560       p += nread;
561       break;
562     case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAM_DATA_UNI:
563       nread = decode_varint_param(&params->initial_max_stream_data_uni, p, end);
564       if (nread < 0) {
565         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
566       }
567       p += nread;
568       break;
569     case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_DATA:
570       nread = decode_varint_param(&params->initial_max_data, p, end);
571       if (nread < 0) {
572         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
573       }
574       p += nread;
575       break;
576     case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_BIDI:
577       nread = decode_varint_param(&params->initial_max_streams_bidi, p, end);
578       if (nread < 0) {
579         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
580       }
581       if (params->initial_max_streams_bidi > NGTCP2_MAX_STREAMS) {
582         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
583       }
584       p += nread;
585       break;
586     case NGTCP2_TRANSPORT_PARAM_INITIAL_MAX_STREAMS_UNI:
587       nread = decode_varint_param(&params->initial_max_streams_uni, p, end);
588       if (nread < 0) {
589         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
590       }
591       if (params->initial_max_streams_uni > NGTCP2_MAX_STREAMS) {
592         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
593       }
594       p += nread;
595       break;
596     case NGTCP2_TRANSPORT_PARAM_MAX_IDLE_TIMEOUT:
597       nread = decode_varint_param(&params->max_idle_timeout, p, end);
598       if (nread < 0) {
599         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
600       }
601       params->max_idle_timeout *= NGTCP2_MILLISECONDS;
602       p += nread;
603       break;
604     case NGTCP2_TRANSPORT_PARAM_MAX_UDP_PAYLOAD_SIZE:
605       nread = decode_varint_param(&params->max_udp_payload_size, p, end);
606       if (nread < 0) {
607         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
608       }
609       p += nread;
610       break;
611     case NGTCP2_TRANSPORT_PARAM_STATELESS_RESET_TOKEN:
612       if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
613         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
614       }
615       nread = decode_varint(&valuelen, p, end);
616       if (nread < 0) {
617         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
618       }
619       p += nread;
620       if ((size_t)valuelen != sizeof(params->stateless_reset_token)) {
621         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
622       }
623       if ((size_t)(end - p) < sizeof(params->stateless_reset_token)) {
624         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
625       }
626 
627       memcpy(params->stateless_reset_token, p,
628              sizeof(params->stateless_reset_token));
629       params->stateless_reset_token_present = 1;
630 
631       p += sizeof(params->stateless_reset_token);
632       break;
633     case NGTCP2_TRANSPORT_PARAM_ACK_DELAY_EXPONENT:
634       nread = decode_varint_param(&params->ack_delay_exponent, p, end);
635       if (nread < 0 || params->ack_delay_exponent > 20) {
636         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
637       }
638       p += nread;
639       break;
640     case NGTCP2_TRANSPORT_PARAM_PREFERRED_ADDRESS:
641       if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
642         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
643       }
644       nread = decode_varint(&valuelen, p, end);
645       if (nread < 0) {
646         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
647       }
648       p += nread;
649       if ((size_t)(end - p) < valuelen) {
650         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
651       }
652       len = 4 /* ipv4Address */ + 2 /* ipv4Port */ + 16 /* ipv6Address */ +
653             2 /* ipv6Port */
654             + 1 /* cid length */ + NGTCP2_STATELESS_RESET_TOKENLEN;
655       if (valuelen < len) {
656         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
657       }
658 
659       memcpy(params->preferred_address.ipv4_addr, p,
660              sizeof(params->preferred_address.ipv4_addr));
661       p += sizeof(params->preferred_address.ipv4_addr);
662       params->preferred_address.ipv4_port = ngtcp2_get_uint16(p);
663       p += sizeof(uint16_t);
664 
665       if (params->preferred_address.ipv4_port ||
666           memcmp(empty_address, params->preferred_address.ipv4_addr,
667                  sizeof(params->preferred_address.ipv4_addr)) != 0) {
668         params->preferred_address.ipv4_present = 1;
669       }
670 
671       memcpy(params->preferred_address.ipv6_addr, p,
672              sizeof(params->preferred_address.ipv6_addr));
673       p += sizeof(params->preferred_address.ipv6_addr);
674       params->preferred_address.ipv6_port = ngtcp2_get_uint16(p);
675       p += sizeof(uint16_t);
676 
677       if (params->preferred_address.ipv6_port ||
678           memcmp(empty_address, params->preferred_address.ipv6_addr,
679                  sizeof(params->preferred_address.ipv6_addr)) != 0) {
680         params->preferred_address.ipv6_present = 1;
681       }
682 
683       /* cid */
684       params->preferred_address.cid.datalen = *p++;
685       len += params->preferred_address.cid.datalen;
686       if (valuelen != len ||
687           params->preferred_address.cid.datalen > NGTCP2_MAX_CIDLEN ||
688           params->preferred_address.cid.datalen < NGTCP2_MIN_CIDLEN) {
689         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
690       }
691       if (params->preferred_address.cid.datalen) {
692         memcpy(params->preferred_address.cid.data, p,
693                params->preferred_address.cid.datalen);
694         p += params->preferred_address.cid.datalen;
695       }
696 
697       /* stateless reset token */
698       memcpy(params->preferred_address.stateless_reset_token, p,
699              sizeof(params->preferred_address.stateless_reset_token));
700       p += sizeof(params->preferred_address.stateless_reset_token);
701       params->preferred_address_present = 1;
702       break;
703     case NGTCP2_TRANSPORT_PARAM_DISABLE_ACTIVE_MIGRATION:
704       nread = decode_varint(&valuelen, p, end);
705       if (nread < 0 || valuelen != 0) {
706         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
707       }
708       p += nread;
709       params->disable_active_migration = 1;
710       break;
711     case NGTCP2_TRANSPORT_PARAM_ORIGINAL_DESTINATION_CONNECTION_ID:
712       if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
713         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
714       }
715       nread = decode_cid_param(&params->original_dcid, p, end);
716       if (nread < 0) {
717         return (int)nread;
718       }
719       original_dcid_present = 1;
720       p += nread;
721       break;
722     case NGTCP2_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID:
723       if (exttype != NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS) {
724         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
725       }
726       nread = decode_cid_param(&params->retry_scid, p, end);
727       if (nread < 0) {
728         return (int)nread;
729       }
730       params->retry_scid_present = 1;
731       p += nread;
732       break;
733     case NGTCP2_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID:
734       nread = decode_cid_param(&params->initial_scid, p, end);
735       if (nread < 0) {
736         return (int)nread;
737       }
738       initial_scid_present = 1;
739       p += nread;
740       break;
741     case NGTCP2_TRANSPORT_PARAM_MAX_ACK_DELAY:
742       nread = decode_varint_param(&params->max_ack_delay, p, end);
743       if (nread < 0 || params->max_ack_delay >= 16384) {
744         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
745       }
746       params->max_ack_delay *= NGTCP2_MILLISECONDS;
747       p += nread;
748       break;
749     case NGTCP2_TRANSPORT_PARAM_ACTIVE_CONNECTION_ID_LIMIT:
750       nread = decode_varint_param(&params->active_connection_id_limit, p, end);
751       if (nread < 0) {
752         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
753       }
754       p += nread;
755       break;
756     case NGTCP2_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE:
757       nread = decode_varint_param(&params->max_datagram_frame_size, p, end);
758       if (nread < 0) {
759         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
760       }
761       p += nread;
762       break;
763     case NGTCP2_TRANSPORT_PARAM_GREASE_QUIC_BIT:
764       nread = decode_varint(&valuelen, p, end);
765       if (nread < 0 || valuelen != 0) {
766         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
767       }
768       p += nread;
769       params->grease_quic_bit = 1;
770       break;
771     default:
772       /* Ignore unknown parameter */
773       nread = decode_varint(&valuelen, p, end);
774       if (nread < 0) {
775         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
776       }
777       p += nread;
778       if ((size_t)(end - p) < valuelen) {
779         return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
780       }
781       p += valuelen;
782       break;
783     }
784   }
785 
786   if (end - p != 0) {
787     return NGTCP2_ERR_MALFORMED_TRANSPORT_PARAM;
788   }
789 
790   if (!initial_scid_present ||
791       (exttype == NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS &&
792        !original_dcid_present)) {
793     return NGTCP2_ERR_REQUIRED_TRANSPORT_PARAM;
794   }
795 
796   return 0;
797 }
798