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#include <stdio.h>
16#include <stdlib.h>
17
18#include <openssl/crypto.h>
19#include <openssl/bytestring.h>
20
21#include "internal.h"
22
23
24static int test_skip(void) {
25  static const uint8_t kData[] = {1, 2, 3};
26  CBS data;
27
28  CBS_init(&data, kData, sizeof(kData));
29  return CBS_len(&data) == 3 &&
30      CBS_skip(&data, 1) &&
31      CBS_len(&data) == 2 &&
32      CBS_skip(&data, 2) &&
33      CBS_len(&data) == 0 &&
34      !CBS_skip(&data, 1);
35}
36
37static int test_get_u(void) {
38  static const uint8_t kData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
39  uint8_t u8;
40  uint16_t u16;
41  uint32_t u32;
42  CBS data;
43
44  CBS_init(&data, kData, sizeof(kData));
45  return CBS_get_u8(&data, &u8) &&
46    u8 == 1 &&
47    CBS_get_u16(&data, &u16) &&
48    u16 == 0x203 &&
49    CBS_get_u24(&data, &u32) &&
50    u32 == 0x40506 &&
51    CBS_get_u32(&data, &u32) &&
52    u32 == 0x708090a &&
53    !CBS_get_u8(&data, &u8);
54}
55
56static int test_get_prefixed(void) {
57  static const uint8_t kData[] = {1, 2, 0, 2, 3, 4, 0, 0, 3, 3, 2, 1};
58  uint8_t u8;
59  uint16_t u16;
60  uint32_t u32;
61  CBS data, prefixed;
62
63  CBS_init(&data, kData, sizeof(kData));
64  return CBS_get_u8_length_prefixed(&data, &prefixed) &&
65    CBS_len(&prefixed) == 1 &&
66    CBS_get_u8(&prefixed, &u8) &&
67    u8 == 2 &&
68    CBS_get_u16_length_prefixed(&data, &prefixed) &&
69    CBS_len(&prefixed) == 2 &&
70    CBS_get_u16(&prefixed, &u16) &&
71    u16 == 0x304 &&
72    CBS_get_u24_length_prefixed(&data, &prefixed) &&
73    CBS_len(&prefixed) == 3 &&
74    CBS_get_u24(&prefixed, &u32) &&
75    u32 == 0x30201;
76}
77
78static int test_get_prefixed_bad(void) {
79  static const uint8_t kData1[] = {2, 1};
80  static const uint8_t kData2[] = {0, 2, 1};
81  static const uint8_t kData3[] = {0, 0, 2, 1};
82  CBS data, prefixed;
83
84  CBS_init(&data, kData1, sizeof(kData1));
85  if (CBS_get_u8_length_prefixed(&data, &prefixed)) {
86    return 0;
87  }
88
89  CBS_init(&data, kData2, sizeof(kData2));
90  if (CBS_get_u16_length_prefixed(&data, &prefixed)) {
91    return 0;
92  }
93
94  CBS_init(&data, kData3, sizeof(kData3));
95  if (CBS_get_u24_length_prefixed(&data, &prefixed)) {
96    return 0;
97  }
98
99  return 1;
100}
101
102static int test_get_asn1(void) {
103  static const uint8_t kData1[] = {0x30, 2, 1, 2};
104  static const uint8_t kData2[] = {0x30, 3, 1, 2};
105  static const uint8_t kData3[] = {0x30, 0x80};
106  static const uint8_t kData4[] = {0x30, 0x81, 1, 1};
107  static const uint8_t kData5[] = {0x30, 0x82, 0, 1, 1};
108
109  CBS data, contents;
110
111  CBS_init(&data, kData1, sizeof(kData1));
112  if (!CBS_get_asn1(&data, &contents, 0x30) ||
113      CBS_len(&contents) != 2 ||
114      memcmp(CBS_data(&contents), "\x01\x02", 2) != 0) {
115    return 0;
116  }
117
118  CBS_init(&data, kData2, sizeof(kData2));
119  /* data is truncated */
120  if (CBS_get_asn1(&data, &contents, 0x30)) {
121    return 0;
122  }
123
124  CBS_init(&data, kData3, sizeof(kData3));
125  /* zero byte length of length */
126  if (CBS_get_asn1(&data, &contents, 0x30)) {
127    return 0;
128  }
129
130  CBS_init(&data, kData4, sizeof(kData4));
131  /* long form mistakenly used. */
132  if (CBS_get_asn1(&data, &contents, 0x30)) {
133    return 0;
134  }
135
136  CBS_init(&data, kData5, sizeof(kData5));
137  /* length takes too many bytes. */
138  if (CBS_get_asn1(&data, &contents, 0x30)) {
139    return 0;
140  }
141
142  CBS_init(&data, kData1, sizeof(kData1));
143  /* wrong tag. */
144  if (CBS_get_asn1(&data, &contents, 0x31)) {
145    return 0;
146  }
147
148  return 1;
149}
150
151static int test_cbb_basic(void) {
152  static const uint8_t kExpected[] = {1, 2, 3, 4, 5, 6, 7, 8};
153  uint8_t *buf;
154  size_t buf_len;
155  int ok;
156  CBB cbb;
157
158  if (!CBB_init(&cbb, 100)) {
159    return 0;
160  }
161  CBB_cleanup(&cbb);
162
163  if (!CBB_init(&cbb, 0) ||
164      !CBB_add_u8(&cbb, 1) ||
165      !CBB_add_u16(&cbb, 0x203) ||
166      !CBB_add_u24(&cbb, 0x40506) ||
167      !CBB_add_bytes(&cbb, (const uint8_t*) "\x07\x08", 2) ||
168      !CBB_finish(&cbb, &buf, &buf_len)) {
169    return 0;
170  }
171
172  ok = buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) == 0;
173  free(buf);
174  return ok;
175}
176
177static int test_cbb_fixed(void) {
178  CBB cbb;
179  uint8_t buf[1];
180  uint8_t *out_buf;
181  size_t out_size;
182
183  if (!CBB_init_fixed(&cbb, NULL, 0) ||
184      CBB_add_u8(&cbb, 1) ||
185      !CBB_finish(&cbb, &out_buf, &out_size) ||
186      out_buf != NULL ||
187      out_size != 0) {
188    return 0;
189  }
190
191  if (!CBB_init_fixed(&cbb, buf, 1) ||
192      !CBB_add_u8(&cbb, 1) ||
193      CBB_add_u8(&cbb, 2) ||
194      !CBB_finish(&cbb, &out_buf, &out_size) ||
195      out_buf != buf ||
196      out_size != 1 ||
197      buf[0] != 1) {
198    return 0;
199  }
200
201  return 1;
202}
203
204static int test_cbb_finish_child(void) {
205  CBB cbb, child;
206  uint8_t *out_buf;
207  size_t out_size;
208
209  if (!CBB_init(&cbb, 16) ||
210      !CBB_add_u8_length_prefixed(&cbb, &child) ||
211      CBB_finish(&child, &out_buf, &out_size) ||
212      !CBB_finish(&cbb, &out_buf, &out_size) ||
213      out_size != 1 ||
214      out_buf[0] != 0) {
215    return 0;
216  }
217
218  free(out_buf);
219  return 1;
220}
221
222static int test_cbb_prefixed(void) {
223  static const uint8_t kExpected[] = {0, 1, 1, 0, 2, 2, 3, 0, 0, 3,
224                                      4, 5, 6, 5, 4, 1, 0, 1, 2};
225  uint8_t *buf;
226  size_t buf_len;
227  CBB cbb, contents, inner_contents, inner_inner_contents;
228  int ok;
229
230  if (!CBB_init(&cbb, 0) ||
231      !CBB_add_u8_length_prefixed(&cbb, &contents) ||
232      !CBB_add_u8_length_prefixed(&cbb, &contents) ||
233      !CBB_add_u8(&contents, 1) ||
234      !CBB_add_u16_length_prefixed(&cbb, &contents) ||
235      !CBB_add_u16(&contents, 0x203) ||
236      !CBB_add_u24_length_prefixed(&cbb, &contents) ||
237      !CBB_add_u24(&contents, 0x40506) ||
238      !CBB_add_u8_length_prefixed(&cbb, &contents) ||
239      !CBB_add_u8_length_prefixed(&contents, &inner_contents) ||
240      !CBB_add_u8(&inner_contents, 1) ||
241      !CBB_add_u16_length_prefixed(&inner_contents, &inner_inner_contents) ||
242      !CBB_add_u8(&inner_inner_contents, 2) ||
243      !CBB_finish(&cbb, &buf, &buf_len)) {
244    return 0;
245  }
246
247  ok = buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) == 0;
248  free(buf);
249  return ok;
250}
251
252static int test_cbb_misuse(void) {
253  CBB cbb, child, contents;
254  uint8_t *buf;
255  size_t buf_len;
256
257  if (!CBB_init(&cbb, 0) ||
258      !CBB_add_u8_length_prefixed(&cbb, &child) ||
259      !CBB_add_u8(&child, 1) ||
260      !CBB_add_u8(&cbb, 2)) {
261    return 0;
262  }
263
264  /* Since we wrote to |cbb|, |child| is now invalid and attempts to write to
265   * it should fail. */
266  if (CBB_add_u8(&child, 1) ||
267      CBB_add_u16(&child, 1) ||
268      CBB_add_u24(&child, 1) ||
269      CBB_add_u8_length_prefixed(&child, &contents) ||
270      CBB_add_u16_length_prefixed(&child, &contents) ||
271      CBB_add_asn1(&child, &contents, 1) ||
272      CBB_add_bytes(&child, (const uint8_t*) "a", 1)) {
273    fprintf(stderr, "CBB operation on invalid CBB did not fail.\n");
274    return 0;
275  }
276
277  if (!CBB_finish(&cbb, &buf, &buf_len) ||
278      buf_len != 3 ||
279      memcmp(buf, "\x01\x01\x02", 3) != 0) {
280    return 0;
281  }
282
283  free(buf);
284
285  return 1;
286}
287
288static int test_cbb_asn1(void) {
289  static const uint8_t kExpected[] = {0x30, 3, 1, 2, 3};
290  uint8_t *buf, *test_data;
291  size_t buf_len;
292  CBB cbb, contents, inner_contents;
293
294  if (!CBB_init(&cbb, 0) ||
295      !CBB_add_asn1(&cbb, &contents, 0x30) ||
296      !CBB_add_bytes(&contents, (const uint8_t*) "\x01\x02\x03", 3) ||
297      !CBB_finish(&cbb, &buf, &buf_len)) {
298    return 0;
299  }
300
301  if (buf_len != sizeof(kExpected) || memcmp(buf, kExpected, buf_len) != 0) {
302    return 0;
303  }
304  free(buf);
305
306  test_data = malloc(100000);
307  memset(test_data, 0x42, 100000);
308
309  if (!CBB_init(&cbb, 0) ||
310      !CBB_add_asn1(&cbb, &contents, 0x30) ||
311      !CBB_add_bytes(&contents, test_data, 130) ||
312      !CBB_finish(&cbb, &buf, &buf_len)) {
313    return 0;
314  }
315
316  if (buf_len != 3 + 130 ||
317      memcmp(buf, "\x30\x81\x82", 3) != 0 ||
318      memcmp(buf + 3, test_data, 130) != 0) {
319    return 0;
320  }
321  free(buf);
322
323  if (!CBB_init(&cbb, 0) ||
324      !CBB_add_asn1(&cbb, &contents, 0x30) ||
325      !CBB_add_bytes(&contents, test_data, 1000) ||
326      !CBB_finish(&cbb, &buf, &buf_len)) {
327    return 0;
328  }
329
330  if (buf_len != 4 + 1000 ||
331      memcmp(buf, "\x30\x82\x03\xe8", 4) != 0 ||
332      memcmp(buf + 4, test_data, 1000)) {
333    return 0;
334  }
335  free(buf);
336
337  if (!CBB_init(&cbb, 0) ||
338      !CBB_add_asn1(&cbb, &contents, 0x30) ||
339      !CBB_add_asn1(&contents, &inner_contents, 0x30) ||
340      !CBB_add_bytes(&inner_contents, test_data, 100000) ||
341      !CBB_finish(&cbb, &buf, &buf_len)) {
342    return 0;
343  }
344
345  if (buf_len != 5 + 5 + 100000 ||
346      memcmp(buf, "\x30\x83\x01\x86\xa5\x30\x83\x01\x86\xa0", 10) != 0 ||
347      memcmp(buf + 10, test_data, 100000)) {
348    return 0;
349  }
350  free(buf);
351
352  free(test_data);
353  return 1;
354}
355
356static int do_ber_convert(const char *name,
357                          const uint8_t *der_expected, size_t der_len,
358                          const uint8_t *ber, size_t ber_len) {
359  CBS in;
360  uint8_t *out;
361  size_t out_len;
362
363  CBS_init(&in, ber, ber_len);
364  if (!CBS_asn1_ber_to_der(&in, &out, &out_len)) {
365    fprintf(stderr, "%s: CBS_asn1_ber_to_der failed.\n", name);
366    return 0;
367  }
368
369  if (out == NULL) {
370    if (ber_len != der_len ||
371        memcmp(der_expected, ber, ber_len) != 0) {
372      fprintf(stderr, "%s: incorrect unconverted result.\n", name);
373      return 0;
374    }
375
376    return 1;
377  }
378
379  if (out_len != der_len ||
380      memcmp(out, der_expected, der_len) != 0) {
381    fprintf(stderr, "%s: incorrect converted result.\n", name);
382    return 0;
383  }
384
385  free(out);
386  return 1;
387}
388
389static int test_ber_convert(void) {
390  static const uint8_t kSimpleBER[] = {0x01, 0x01, 0x00};
391
392  /* kIndefBER contains a SEQUENCE with an indefinite length. */
393  static const uint8_t kIndefBER[] = {0x30, 0x80, 0x01, 0x01, 0x02, 0x00, 0x00};
394  static const uint8_t kIndefDER[] = {0x30, 0x03, 0x01, 0x01, 0x02};
395
396  /* kOctetStringBER contains an indefinite length OCTETSTRING with two parts.
397   * These parts need to be concatenated in DER form. */
398  static const uint8_t kOctetStringBER[] = {0x24, 0x80, 0x04, 0x02, 0,    1,
399                                            0x04, 0x02, 2,    3,    0x00, 0x00};
400  static const uint8_t kOctetStringDER[] = {0x04, 0x04, 0, 1, 2, 3};
401
402  /* kNSSBER is part of a PKCS#12 message generated by NSS that uses indefinite
403   * length elements extensively. */
404  static const uint8_t kNSSBER[] = {
405      0x30, 0x80, 0x02, 0x01, 0x03, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48,
406      0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x80, 0x24, 0x80, 0x04, 0x04,
407      0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x39,
408      0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
409      0x00, 0x04, 0x14, 0x84, 0x98, 0xfc, 0x66, 0x33, 0xee, 0xba, 0xe7, 0x90,
410      0xc1, 0xb6, 0xe8, 0x8f, 0xfe, 0x1d, 0xc5, 0xa5, 0x97, 0x93, 0x3e, 0x04,
411      0x10, 0x38, 0x62, 0xc6, 0x44, 0x12, 0xd5, 0x30, 0x00, 0xf8, 0xf2, 0x1b,
412      0xf0, 0x6e, 0x10, 0x9b, 0xb8, 0x02, 0x02, 0x07, 0xd0, 0x00, 0x00,
413  };
414
415  static const uint8_t kNSSDER[] = {
416      0x30, 0x53, 0x02, 0x01, 0x03, 0x30, 0x13, 0x06, 0x09, 0x2a, 0x86,
417      0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x06, 0x04, 0x04,
418      0x01, 0x02, 0x03, 0x04, 0x30, 0x39, 0x30, 0x21, 0x30, 0x09, 0x06,
419      0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x84,
420      0x98, 0xfc, 0x66, 0x33, 0xee, 0xba, 0xe7, 0x90, 0xc1, 0xb6, 0xe8,
421      0x8f, 0xfe, 0x1d, 0xc5, 0xa5, 0x97, 0x93, 0x3e, 0x04, 0x10, 0x38,
422      0x62, 0xc6, 0x44, 0x12, 0xd5, 0x30, 0x00, 0xf8, 0xf2, 0x1b, 0xf0,
423      0x6e, 0x10, 0x9b, 0xb8, 0x02, 0x02, 0x07, 0xd0,
424  };
425
426  return do_ber_convert("kSimpleBER", kSimpleBER, sizeof(kSimpleBER),
427                        kSimpleBER, sizeof(kSimpleBER)) &&
428         do_ber_convert("kIndefBER", kIndefDER, sizeof(kIndefDER), kIndefBER,
429                        sizeof(kIndefBER)) &&
430         do_ber_convert("kOctetStringBER", kOctetStringDER,
431                        sizeof(kOctetStringDER), kOctetStringBER,
432                        sizeof(kOctetStringBER)) &&
433         do_ber_convert("kNSSBER", kNSSDER, sizeof(kNSSDER), kNSSBER,
434                        sizeof(kNSSBER));
435}
436
437int main(void) {
438  CRYPTO_library_init();
439
440  if (!test_skip() ||
441      !test_get_u() ||
442      !test_get_prefixed() ||
443      !test_get_prefixed_bad() ||
444      !test_get_asn1() ||
445      !test_cbb_basic() ||
446      !test_cbb_fixed() ||
447      !test_cbb_finish_child() ||
448      !test_cbb_misuse() ||
449      !test_cbb_prefixed() ||
450      !test_cbb_asn1() ||
451      !test_ber_convert()) {
452    return 1;
453  }
454
455  printf("PASS\n");
456  return 0;
457}
458