1/* Copyright (c) 2014, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15#if !defined(__STDC_CONSTANT_MACROS)
16#define __STDC_CONSTANT_MACROS
17#endif
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include <vector>
24
25#include <openssl/crypto.h>
26#include <openssl/bytestring.h>
27
28#include "internal.h"
29#include "../test/scoped_types.h"
30
31
32static bool TestSkip() {
33  static const uint8_t kData[] = {1, 2, 3};
34  CBS data;
35
36  CBS_init(&data, kData, sizeof(kData));
37  return CBS_len(&data) == 3 &&
38      CBS_skip(&data, 1) &&
39      CBS_len(&data) == 2 &&
40      CBS_skip(&data, 2) &&
41      CBS_len(&data) == 0 &&
42      !CBS_skip(&data, 1);
43}
44
45static bool TestGetUint() {
46  static const uint8_t kData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
47  uint8_t u8;
48  uint16_t u16;
49  uint32_t u32;
50  CBS data;
51
52  CBS_init(&data, kData, sizeof(kData));
53  return CBS_get_u8(&data, &u8) &&
54    u8 == 1 &&
55    CBS_get_u16(&data, &u16) &&
56    u16 == 0x203 &&
57    CBS_get_u24(&data, &u32) &&
58    u32 == 0x40506 &&
59    CBS_get_u32(&data, &u32) &&
60    u32 == 0x708090a &&
61    !CBS_get_u8(&data, &u8);
62}
63
64static bool TestGetPrefixed() {
65  static const uint8_t kData[] = {1, 2, 0, 2, 3, 4, 0, 0, 3, 3, 2, 1};
66  uint8_t u8;
67  uint16_t u16;
68  uint32_t u32;
69  CBS data, prefixed;
70
71  CBS_init(&data, kData, sizeof(kData));
72  return CBS_get_u8_length_prefixed(&data, &prefixed) &&
73    CBS_len(&prefixed) == 1 &&
74    CBS_get_u8(&prefixed, &u8) &&
75    u8 == 2 &&
76    CBS_get_u16_length_prefixed(&data, &prefixed) &&
77    CBS_len(&prefixed) == 2 &&
78    CBS_get_u16(&prefixed, &u16) &&
79    u16 == 0x304 &&
80    CBS_get_u24_length_prefixed(&data, &prefixed) &&
81    CBS_len(&prefixed) == 3 &&
82    CBS_get_u24(&prefixed, &u32) &&
83    u32 == 0x30201;
84}
85
86static bool TestGetPrefixedBad() {
87  static const uint8_t kData1[] = {2, 1};
88  static const uint8_t kData2[] = {0, 2, 1};
89  static const uint8_t kData3[] = {0, 0, 2, 1};
90  CBS data, prefixed;
91
92  CBS_init(&data, kData1, sizeof(kData1));
93  if (CBS_get_u8_length_prefixed(&data, &prefixed)) {
94    return false;
95  }
96
97  CBS_init(&data, kData2, sizeof(kData2));
98  if (CBS_get_u16_length_prefixed(&data, &prefixed)) {
99    return false;
100  }
101
102  CBS_init(&data, kData3, sizeof(kData3));
103  if (CBS_get_u24_length_prefixed(&data, &prefixed)) {
104    return false;
105  }
106
107  return true;
108}
109
110static bool TestGetASN1() {
111  static const uint8_t kData1[] = {0x30, 2, 1, 2};
112  static const uint8_t kData2[] = {0x30, 3, 1, 2};
113  static const uint8_t kData3[] = {0x30, 0x80};
114  static const uint8_t kData4[] = {0x30, 0x81, 1, 1};
115  static const uint8_t kData5[4 + 0x80] = {0x30, 0x82, 0, 0x80};
116  static const uint8_t kData6[] = {0xa1, 3, 0x4, 1, 1};
117  static const uint8_t kData7[] = {0xa1, 3, 0x4, 2, 1};
118  static const uint8_t kData8[] = {0xa1, 3, 0x2, 1, 1};
119  static const uint8_t kData9[] = {0xa1, 3, 0x2, 1, 0xff};
120
121  CBS data, contents;
122  int present;
123  uint64_t value;
124
125  CBS_init(&data, kData1, sizeof(kData1));
126  if (CBS_peek_asn1_tag(&data, 0x1) ||
127      !CBS_peek_asn1_tag(&data, 0x30)) {
128    return false;
129  }
130  if (!CBS_get_asn1(&data, &contents, 0x30) ||
131      CBS_len(&contents) != 2 ||
132      memcmp(CBS_data(&contents), "\x01\x02", 2) != 0) {
133    return false;
134  }
135
136  CBS_init(&data, kData2, sizeof(kData2));
137  // data is truncated
138  if (CBS_get_asn1(&data, &contents, 0x30)) {
139    return false;
140  }
141
142  CBS_init(&data, kData3, sizeof(kData3));
143  // zero byte length of length
144  if (CBS_get_asn1(&data, &contents, 0x30)) {
145    return false;
146  }
147
148  CBS_init(&data, kData4, sizeof(kData4));
149  // long form mistakenly used.
150  if (CBS_get_asn1(&data, &contents, 0x30)) {
151    return false;
152  }
153
154  CBS_init(&data, kData5, sizeof(kData5));
155  // length takes too many bytes.
156  if (CBS_get_asn1(&data, &contents, 0x30)) {
157    return false;
158  }
159
160  CBS_init(&data, kData1, sizeof(kData1));
161  // wrong tag.
162  if (CBS_get_asn1(&data, &contents, 0x31)) {
163    return false;
164  }
165
166  CBS_init(&data, NULL, 0);
167  // peek at empty data.
168  if (CBS_peek_asn1_tag(&data, 0x30)) {
169    return false;
170  }
171
172  CBS_init(&data, NULL, 0);
173  // optional elements at empty data.
174  if (!CBS_get_optional_asn1(&data, &contents, &present, 0xa0) ||
175      present ||
176      !CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0) ||
177      present ||
178      CBS_len(&contents) != 0 ||
179      !CBS_get_optional_asn1_octet_string(&data, &contents, NULL, 0xa0) ||
180      CBS_len(&contents) != 0 ||
181      !CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42) ||
182      value != 42) {
183    return false;
184  }
185
186  CBS_init(&data, kData6, sizeof(kData6));
187  // optional element.
188  if (!CBS_get_optional_asn1(&data, &contents, &present, 0xa0) ||
189      present ||
190      !CBS_get_optional_asn1(&data, &contents, &present, 0xa1) ||
191      !present ||
192      CBS_len(&contents) != 3 ||
193      memcmp(CBS_data(&contents), "\x04\x01\x01", 3) != 0) {
194    return false;
195  }
196
197  CBS_init(&data, kData6, sizeof(kData6));
198  // optional octet string.
199  if (!CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0) ||
200      present ||
201      CBS_len(&contents) != 0 ||
202      !CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1) ||
203      !present ||
204      CBS_len(&contents) != 1 ||
205      CBS_data(&contents)[0] != 1) {
206    return false;
207  }
208
209  CBS_init(&data, kData7, sizeof(kData7));
210  // invalid optional octet string.
211  if (CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1)) {
212    return false;
213  }
214
215  CBS_init(&data, kData8, sizeof(kData8));
216  // optional octet string.
217  if (!CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42) ||
218      value != 42 ||
219      !CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42) ||
220      value != 1) {
221    return false;
222  }
223
224  CBS_init(&data, kData9, sizeof(kData9));
225  // invalid optional integer.
226  if (CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42)) {
227    return false;
228  }
229
230  return true;
231}
232
233static bool TestGetOptionalASN1Bool() {
234  static const uint8_t kTrue[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0xff};
235  static const uint8_t kFalse[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x00};
236  static const uint8_t kInvalid[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x01};
237
238  CBS data;
239  CBS_init(&data, NULL, 0);
240  int val = 2;
241  if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 0) ||
242      val != 0) {
243    return false;
244  }
245
246  CBS_init(&data, kTrue, sizeof(kTrue));
247  val = 2;
248  if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 0) ||
249      val != 1) {
250    return false;
251  }
252
253  CBS_init(&data, kFalse, sizeof(kFalse));
254  val = 2;
255  if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 1) ||
256      val != 0) {
257    return false;
258  }
259
260  CBS_init(&data, kInvalid, sizeof(kInvalid));
261  if (CBS_get_optional_asn1_bool(&data, &val, 0x0a, 1)) {
262    return false;
263  }
264
265  return true;
266}
267
268static bool TestCBBBasic() {
269  static const uint8_t kExpected[] = {1, 2, 3, 4, 5, 6, 7, 8};
270  uint8_t *buf;
271  size_t buf_len;
272  CBB cbb;
273
274  if (!CBB_init(&cbb, 100)) {
275    return false;
276  }
277  CBB_cleanup(&cbb);
278
279  if (!CBB_init(&cbb, 0)) {
280    return false;
281  }
282  if (!CBB_add_u8(&cbb, 1) ||
283      !CBB_add_u16(&cbb, 0x203) ||
284      !CBB_add_u24(&cbb, 0x40506) ||
285      !CBB_add_bytes(&cbb, (const uint8_t*) "\x07\x08", 2) ||
286      !CBB_finish(&cbb, &buf, &buf_len)) {
287    CBB_cleanup(&cbb);
288    return false;
289  }
290
291  ScopedOpenSSLBytes scoper(buf);
292  return buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) == 0;
293}
294
295static bool TestCBBFixed() {
296  CBB cbb;
297  uint8_t buf[1];
298  uint8_t *out_buf;
299  size_t out_size;
300
301  if (!CBB_init_fixed(&cbb, NULL, 0) ||
302      CBB_add_u8(&cbb, 1) ||
303      !CBB_finish(&cbb, &out_buf, &out_size) ||
304      out_buf != NULL ||
305      out_size != 0) {
306    return false;
307  }
308
309  if (!CBB_init_fixed(&cbb, buf, 1) ||
310      !CBB_add_u8(&cbb, 1) ||
311      CBB_add_u8(&cbb, 2) ||
312      !CBB_finish(&cbb, &out_buf, &out_size) ||
313      out_buf != buf ||
314      out_size != 1 ||
315      buf[0] != 1) {
316    return false;
317  }
318
319  return true;
320}
321
322static bool TestCBBFinishChild() {
323  CBB cbb, child;
324  uint8_t *out_buf;
325  size_t out_size;
326
327  if (!CBB_init(&cbb, 16)) {
328    return false;
329  }
330  if (!CBB_add_u8_length_prefixed(&cbb, &child) ||
331      CBB_finish(&child, &out_buf, &out_size) ||
332      !CBB_finish(&cbb, &out_buf, &out_size)) {
333    CBB_cleanup(&cbb);
334    return false;
335  }
336  ScopedOpenSSLBytes scoper(out_buf);
337  return out_size == 1 && out_buf[0] == 0;
338}
339
340static bool TestCBBPrefixed() {
341  static const uint8_t kExpected[] = {0, 1, 1, 0, 2, 2, 3, 0, 0, 3,
342                                      4, 5, 6, 5, 4, 1, 0, 1, 2};
343  uint8_t *buf;
344  size_t buf_len;
345  CBB cbb, contents, inner_contents, inner_inner_contents;
346
347  if (!CBB_init(&cbb, 0) ||
348      CBB_len(&cbb) != 0 ||
349      !CBB_add_u8_length_prefixed(&cbb, &contents) ||
350      !CBB_add_u8_length_prefixed(&cbb, &contents) ||
351      !CBB_add_u8(&contents, 1) ||
352      CBB_len(&contents) != 1 ||
353      !CBB_flush(&cbb) ||
354      CBB_len(&cbb) != 3 ||
355      !CBB_add_u16_length_prefixed(&cbb, &contents) ||
356      !CBB_add_u16(&contents, 0x203) ||
357      !CBB_add_u24_length_prefixed(&cbb, &contents) ||
358      !CBB_add_u24(&contents, 0x40506) ||
359      !CBB_add_u8_length_prefixed(&cbb, &contents) ||
360      !CBB_add_u8_length_prefixed(&contents, &inner_contents) ||
361      !CBB_add_u8(&inner_contents, 1) ||
362      !CBB_add_u16_length_prefixed(&inner_contents, &inner_inner_contents) ||
363      !CBB_add_u8(&inner_inner_contents, 2) ||
364      !CBB_finish(&cbb, &buf, &buf_len)) {
365    CBB_cleanup(&cbb);
366    return false;
367  }
368
369  ScopedOpenSSLBytes scoper(buf);
370  return buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) == 0;
371}
372
373static bool TestCBBDiscardChild() {
374  ScopedCBB cbb;
375  CBB contents, inner_contents, inner_inner_contents;
376
377  if (!CBB_init(cbb.get(), 0) ||
378      !CBB_add_u8(cbb.get(), 0xaa)) {
379    return false;
380  }
381
382  // Discarding |cbb|'s children preserves the byte written.
383  CBB_discard_child(cbb.get());
384
385  if (!CBB_add_u8_length_prefixed(cbb.get(), &contents) ||
386      !CBB_add_u8_length_prefixed(cbb.get(), &contents) ||
387      !CBB_add_u8(&contents, 0xbb) ||
388      !CBB_add_u16_length_prefixed(cbb.get(), &contents) ||
389      !CBB_add_u16(&contents, 0xcccc) ||
390      !CBB_add_u24_length_prefixed(cbb.get(), &contents) ||
391      !CBB_add_u24(&contents, 0xdddddd) ||
392      !CBB_add_u8_length_prefixed(cbb.get(), &contents) ||
393      !CBB_add_u8(&contents, 0xff) ||
394      !CBB_add_u8_length_prefixed(&contents, &inner_contents) ||
395      !CBB_add_u8(&inner_contents, 0x42) ||
396      !CBB_add_u16_length_prefixed(&inner_contents, &inner_inner_contents) ||
397      !CBB_add_u8(&inner_inner_contents, 0x99)) {
398    return false;
399  }
400
401  // Discard everything from |inner_contents| down.
402  CBB_discard_child(&contents);
403
404  uint8_t *buf;
405  size_t buf_len;
406  if (!CBB_finish(cbb.get(), &buf, &buf_len)) {
407    return false;
408  }
409  ScopedOpenSSLBytes scoper(buf);
410
411  static const uint8_t kExpected[] = {
412        0xaa,
413        0,
414        1, 0xbb,
415        0, 2, 0xcc, 0xcc,
416        0, 0, 3, 0xdd, 0xdd, 0xdd,
417        1, 0xff,
418  };
419  return buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) == 0;
420}
421
422static bool TestCBBMisuse() {
423  CBB cbb, child, contents;
424  uint8_t *buf;
425  size_t buf_len;
426
427  if (!CBB_init(&cbb, 0)) {
428    return false;
429  }
430  if (!CBB_add_u8_length_prefixed(&cbb, &child) ||
431      !CBB_add_u8(&child, 1) ||
432      !CBB_add_u8(&cbb, 2)) {
433    CBB_cleanup(&cbb);
434    return false;
435  }
436
437  // Since we wrote to |cbb|, |child| is now invalid and attempts to write to
438  // it should fail.
439  if (CBB_add_u8(&child, 1) ||
440      CBB_add_u16(&child, 1) ||
441      CBB_add_u24(&child, 1) ||
442      CBB_add_u8_length_prefixed(&child, &contents) ||
443      CBB_add_u16_length_prefixed(&child, &contents) ||
444      CBB_add_asn1(&child, &contents, 1) ||
445      CBB_add_bytes(&child, (const uint8_t*) "a", 1)) {
446    fprintf(stderr, "CBB operation on invalid CBB did not fail.\n");
447    CBB_cleanup(&cbb);
448    return false;
449  }
450
451  if (!CBB_finish(&cbb, &buf, &buf_len)) {
452    CBB_cleanup(&cbb);
453    return false;
454  }
455  ScopedOpenSSLBytes scoper(buf);
456
457  if (buf_len != 3 ||
458      memcmp(buf, "\x01\x01\x02", 3) != 0) {
459    return false;
460  }
461  return true;
462}
463
464static bool TestCBBASN1() {
465  static const uint8_t kExpected[] = {0x30, 3, 1, 2, 3};
466  uint8_t *buf;
467  size_t buf_len;
468  CBB cbb, contents, inner_contents;
469
470  if (!CBB_init(&cbb, 0)) {
471    return false;
472  }
473  if (!CBB_add_asn1(&cbb, &contents, 0x30) ||
474      !CBB_add_bytes(&contents, (const uint8_t*) "\x01\x02\x03", 3) ||
475      !CBB_finish(&cbb, &buf, &buf_len)) {
476    CBB_cleanup(&cbb);
477    return false;
478  }
479  ScopedOpenSSLBytes scoper(buf);
480
481  if (buf_len != sizeof(kExpected) || memcmp(buf, kExpected, buf_len) != 0) {
482    return false;
483  }
484
485  std::vector<uint8_t> test_data(100000, 0x42);
486
487  if (!CBB_init(&cbb, 0)) {
488    return false;
489  }
490  if (!CBB_add_asn1(&cbb, &contents, 0x30) ||
491      !CBB_add_bytes(&contents, test_data.data(), 130) ||
492      !CBB_finish(&cbb, &buf, &buf_len)) {
493    CBB_cleanup(&cbb);
494    return false;
495  }
496  scoper.reset(buf);
497
498  if (buf_len != 3 + 130 ||
499      memcmp(buf, "\x30\x81\x82", 3) != 0 ||
500      memcmp(buf + 3, test_data.data(), 130) != 0) {
501    return false;
502  }
503
504  if (!CBB_init(&cbb, 0)) {
505    return false;
506  }
507  if (!CBB_add_asn1(&cbb, &contents, 0x30) ||
508      !CBB_add_bytes(&contents, test_data.data(), 1000) ||
509      !CBB_finish(&cbb, &buf, &buf_len)) {
510    CBB_cleanup(&cbb);
511    return false;
512  }
513  scoper.reset(buf);
514
515  if (buf_len != 4 + 1000 ||
516      memcmp(buf, "\x30\x82\x03\xe8", 4) != 0 ||
517      memcmp(buf + 4, test_data.data(), 1000)) {
518    return false;
519  }
520
521  if (!CBB_init(&cbb, 0)) {
522    return false;
523  }
524  if (!CBB_add_asn1(&cbb, &contents, 0x30) ||
525      !CBB_add_asn1(&contents, &inner_contents, 0x30) ||
526      !CBB_add_bytes(&inner_contents, test_data.data(), 100000) ||
527      !CBB_finish(&cbb, &buf, &buf_len)) {
528    CBB_cleanup(&cbb);
529    return false;
530  }
531  scoper.reset(buf);
532
533  if (buf_len != 5 + 5 + 100000 ||
534      memcmp(buf, "\x30\x83\x01\x86\xa5\x30\x83\x01\x86\xa0", 10) != 0 ||
535      memcmp(buf + 10, test_data.data(), 100000)) {
536    return false;
537  }
538
539  return true;
540}
541
542static bool DoBerConvert(const char *name,
543                         const uint8_t *der_expected, size_t der_len,
544                         const uint8_t *ber, size_t ber_len) {
545  CBS in;
546  uint8_t *out;
547  size_t out_len;
548
549  CBS_init(&in, ber, ber_len);
550  if (!CBS_asn1_ber_to_der(&in, &out, &out_len)) {
551    fprintf(stderr, "%s: CBS_asn1_ber_to_der failed.\n", name);
552    return false;
553  }
554  ScopedOpenSSLBytes scoper(out);
555
556  if (out == NULL) {
557    if (ber_len != der_len ||
558        memcmp(der_expected, ber, ber_len) != 0) {
559      fprintf(stderr, "%s: incorrect unconverted result.\n", name);
560      return false;
561    }
562
563    return true;
564  }
565
566  if (out_len != der_len ||
567      memcmp(out, der_expected, der_len) != 0) {
568    fprintf(stderr, "%s: incorrect converted result.\n", name);
569    return false;
570  }
571
572  return true;
573}
574
575static bool TestBerConvert() {
576  static const uint8_t kSimpleBER[] = {0x01, 0x01, 0x00};
577
578  // kIndefBER contains a SEQUENCE with an indefinite length.
579  static const uint8_t kIndefBER[] = {0x30, 0x80, 0x01, 0x01, 0x02, 0x00, 0x00};
580  static const uint8_t kIndefDER[] = {0x30, 0x03, 0x01, 0x01, 0x02};
581
582  // kOctetStringBER contains an indefinite length OCTETSTRING with two parts.
583  // These parts need to be concatenated in DER form.
584  static const uint8_t kOctetStringBER[] = {0x24, 0x80, 0x04, 0x02, 0,    1,
585                                            0x04, 0x02, 2,    3,    0x00, 0x00};
586  static const uint8_t kOctetStringDER[] = {0x04, 0x04, 0, 1, 2, 3};
587
588  // kNSSBER is part of a PKCS#12 message generated by NSS that uses indefinite
589  // length elements extensively.
590  static const uint8_t kNSSBER[] = {
591      0x30, 0x80, 0x02, 0x01, 0x03, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48,
592      0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x80, 0x24, 0x80, 0x04, 0x04,
593      0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x39,
594      0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
595      0x00, 0x04, 0x14, 0x84, 0x98, 0xfc, 0x66, 0x33, 0xee, 0xba, 0xe7, 0x90,
596      0xc1, 0xb6, 0xe8, 0x8f, 0xfe, 0x1d, 0xc5, 0xa5, 0x97, 0x93, 0x3e, 0x04,
597      0x10, 0x38, 0x62, 0xc6, 0x44, 0x12, 0xd5, 0x30, 0x00, 0xf8, 0xf2, 0x1b,
598      0xf0, 0x6e, 0x10, 0x9b, 0xb8, 0x02, 0x02, 0x07, 0xd0, 0x00, 0x00,
599  };
600
601  static const uint8_t kNSSDER[] = {
602      0x30, 0x53, 0x02, 0x01, 0x03, 0x30, 0x13, 0x06, 0x09, 0x2a, 0x86,
603      0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x06, 0x04, 0x04,
604      0x01, 0x02, 0x03, 0x04, 0x30, 0x39, 0x30, 0x21, 0x30, 0x09, 0x06,
605      0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x84,
606      0x98, 0xfc, 0x66, 0x33, 0xee, 0xba, 0xe7, 0x90, 0xc1, 0xb6, 0xe8,
607      0x8f, 0xfe, 0x1d, 0xc5, 0xa5, 0x97, 0x93, 0x3e, 0x04, 0x10, 0x38,
608      0x62, 0xc6, 0x44, 0x12, 0xd5, 0x30, 0x00, 0xf8, 0xf2, 0x1b, 0xf0,
609      0x6e, 0x10, 0x9b, 0xb8, 0x02, 0x02, 0x07, 0xd0,
610  };
611
612  return DoBerConvert("kSimpleBER", kSimpleBER, sizeof(kSimpleBER),
613                      kSimpleBER, sizeof(kSimpleBER)) &&
614         DoBerConvert("kIndefBER", kIndefDER, sizeof(kIndefDER), kIndefBER,
615                      sizeof(kIndefBER)) &&
616         DoBerConvert("kOctetStringBER", kOctetStringDER,
617                      sizeof(kOctetStringDER), kOctetStringBER,
618                      sizeof(kOctetStringBER)) &&
619         DoBerConvert("kNSSBER", kNSSDER, sizeof(kNSSDER), kNSSBER,
620                      sizeof(kNSSBER));
621}
622
623struct ASN1Uint64Test {
624  uint64_t value;
625  const char *encoding;
626  size_t encoding_len;
627};
628
629static const ASN1Uint64Test kASN1Uint64Tests[] = {
630    {0, "\x02\x01\x00", 3},
631    {1, "\x02\x01\x01", 3},
632    {127, "\x02\x01\x7f", 3},
633    {128, "\x02\x02\x00\x80", 4},
634    {0xdeadbeef, "\x02\x05\x00\xde\xad\xbe\xef", 7},
635    {UINT64_C(0x0102030405060708),
636     "\x02\x08\x01\x02\x03\x04\x05\x06\x07\x08", 10},
637    {UINT64_C(0xffffffffffffffff),
638      "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff", 11},
639};
640
641struct ASN1InvalidUint64Test {
642  const char *encoding;
643  size_t encoding_len;
644};
645
646static const ASN1InvalidUint64Test kASN1InvalidUint64Tests[] = {
647    // Bad tag.
648    {"\x03\x01\x00", 3},
649    // Empty contents.
650    {"\x02\x00", 2},
651    // Negative number.
652    {"\x02\x01\x80", 3},
653    // Overflow.
654    {"\x02\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00", 11},
655    // Leading zeros.
656    {"\x02\x02\x00\x01", 4},
657};
658
659static bool TestASN1Uint64() {
660  for (size_t i = 0; i < sizeof(kASN1Uint64Tests) / sizeof(kASN1Uint64Tests[0]);
661       i++) {
662    const ASN1Uint64Test *test = &kASN1Uint64Tests[i];
663    CBS cbs;
664    uint64_t value;
665    CBB cbb;
666    uint8_t *out;
667    size_t len;
668
669    CBS_init(&cbs, (const uint8_t *)test->encoding, test->encoding_len);
670    if (!CBS_get_asn1_uint64(&cbs, &value) ||
671        CBS_len(&cbs) != 0 ||
672        value != test->value) {
673      return false;
674    }
675
676    if (!CBB_init(&cbb, 0)) {
677      return false;
678    }
679    if (!CBB_add_asn1_uint64(&cbb, test->value) ||
680        !CBB_finish(&cbb, &out, &len)) {
681      CBB_cleanup(&cbb);
682      return false;
683    }
684    ScopedOpenSSLBytes scoper(out);
685    if (len != test->encoding_len || memcmp(out, test->encoding, len) != 0) {
686      return false;
687    }
688  }
689
690  for (size_t i = 0;
691       i < sizeof(kASN1InvalidUint64Tests) / sizeof(kASN1InvalidUint64Tests[0]);
692       i++) {
693    const ASN1InvalidUint64Test *test = &kASN1InvalidUint64Tests[i];
694    CBS cbs;
695    uint64_t value;
696
697    CBS_init(&cbs, (const uint8_t *)test->encoding, test->encoding_len);
698    if (CBS_get_asn1_uint64(&cbs, &value)) {
699      return false;
700    }
701  }
702
703  return true;
704}
705
706static bool TestZero() {
707  CBB cbb;
708  CBB_zero(&cbb);
709  // Calling |CBB_cleanup| on a zero-state |CBB| must not crash.
710  CBB_cleanup(&cbb);
711  return true;
712}
713
714static bool TestCBBReserve() {
715  uint8_t buf[10];
716  uint8_t *ptr;
717  size_t len;
718  ScopedCBB cbb;
719  if (!CBB_init_fixed(cbb.get(), buf, sizeof(buf)) ||
720      // Too large.
721      CBB_reserve(cbb.get(), &ptr, 11) ||
722      // Successfully reserve the entire space.
723      !CBB_reserve(cbb.get(), &ptr, 10) ||
724      ptr != buf ||
725      // Advancing under the maximum bytes is legal.
726      !CBB_did_write(cbb.get(), 5) ||
727      !CBB_finish(cbb.get(), NULL, &len) ||
728      len != 5) {
729    return false;
730  }
731  return true;
732}
733
734int main(void) {
735  CRYPTO_library_init();
736
737  if (!TestSkip() ||
738      !TestGetUint() ||
739      !TestGetPrefixed() ||
740      !TestGetPrefixedBad() ||
741      !TestGetASN1() ||
742      !TestCBBBasic() ||
743      !TestCBBFixed() ||
744      !TestCBBFinishChild() ||
745      !TestCBBMisuse() ||
746      !TestCBBPrefixed() ||
747      !TestCBBDiscardChild() ||
748      !TestCBBASN1() ||
749      !TestBerConvert() ||
750      !TestASN1Uint64() ||
751      !TestGetOptionalASN1Bool() ||
752      !TestZero() ||
753      !TestCBBReserve()) {
754    return 1;
755  }
756
757  printf("PASS\n");
758  return 0;
759}
760