1 /* $NetBSD: fuzzer.c,v 1.2 2017/01/28 21:31:45 christos Exp $ */
2
3 /*
4 * Copyright (c) 2009 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * 3. Neither the name of the Institute nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38 #include "der_locl.h"
39 #include <krb5/com_err.h>
40
41 enum trigger_method { FOFF, FRANDOM, FLINEAR, FLINEAR_SIZE };
42
43 #ifdef ASN1_FUZZER
44 static enum trigger_method method = FOFF;
45
46 /* FLINEAR */
47 static unsigned long fnum, fcur, fsize;
48 #endif
49
50 int
asn1_fuzzer_method(const char * mode)51 asn1_fuzzer_method(const char *mode)
52 {
53 #ifdef ASN1_FUZZER
54 if (mode == NULL || strcasecmp(mode, "off") == 0) {
55 method = FOFF;
56 } else if (strcasecmp(mode, "random") == 0) {
57 method = FRANDOM;
58 } else if (strcasecmp(mode, "linear") == 0) {
59 method = FLINEAR;
60 } else if (strcasecmp(mode, "linear-size") == 0) {
61 method = FLINEAR_SIZE;
62 } else
63 return 1;
64 return 0;
65 #else
66 return 1;
67 #endif
68 }
69
70 void
asn1_fuzzer_reset(void)71 asn1_fuzzer_reset(void)
72 {
73 #ifdef ASN1_FUZZER
74 fcur = 0;
75 fsize = 0;
76 fnum = 0;
77 #endif
78 }
79
80 void
asn1_fuzzer_next(void)81 asn1_fuzzer_next(void)
82 {
83 #ifdef ASN1_FUZZER
84 fcur = 0;
85 fsize = 0;
86 fnum++;
87 #endif
88 }
89
90 int
asn1_fuzzer_done(void)91 asn1_fuzzer_done(void)
92 {
93 #ifndef ASN1_FUZZER
94 abort();
95 #else
96 /* since code paths */
97 return (fnum > 10000);
98 #endif
99 }
100
101 #ifdef ASN1_FUZZER
102
103 static int
fuzzer_trigger(unsigned int chance)104 fuzzer_trigger(unsigned int chance)
105 {
106 switch(method) {
107 case FOFF:
108 return 0;
109 case FRANDOM:
110 if ((rk_random() % chance) != 1)
111 return 0;
112 return 1;
113 case FLINEAR:
114 if (fnum == fcur++)
115 return 1;
116 return 0;
117 case FLINEAR_SIZE:
118 return 0;
119 }
120 return 0;
121 }
122
123 static int
fuzzer_size_trigger(unsigned long * cur)124 fuzzer_size_trigger(unsigned long *cur)
125 {
126 if (method != FLINEAR_SIZE)
127 return 0;
128 if (fnum == (*cur)++)
129 return 1;
130 return 0;
131 }
132
133 static size_t
fuzzer_length_len(size_t len)134 fuzzer_length_len (size_t len)
135 {
136 if (fuzzer_size_trigger(&fsize)) {
137 len = 0;
138 } else if (fuzzer_size_trigger(&fsize)) {
139 len = 129;
140 } else if (fuzzer_size_trigger(&fsize)) {
141 len = 0xffff;
142 }
143
144 if (len < 128)
145 return 1;
146 else {
147 int ret = 0;
148 do {
149 ++ret;
150 len /= 256;
151 } while (len);
152 return ret + 1;
153 }
154 }
155
156 static int
fuzzer_put_length(unsigned char * p,size_t len,size_t val,size_t * size)157 fuzzer_put_length (unsigned char *p, size_t len, size_t val, size_t *size)
158 {
159 if (len < 1)
160 return ASN1_OVERFLOW;
161
162 if (fuzzer_size_trigger(&fcur)) {
163 val = 0;
164 } else if (fuzzer_size_trigger(&fcur)) {
165 val = 129;
166 } else if (fuzzer_size_trigger(&fcur)) {
167 val = 0xffff;
168 }
169
170 if (val < 128) {
171 *p = val;
172 *size = 1;
173 } else {
174 size_t l = 0;
175
176 while(val > 0) {
177 if(len < 2)
178 return ASN1_OVERFLOW;
179 *p-- = val % 256;
180 val /= 256;
181 len--;
182 l++;
183 }
184 *p = 0x80 | l;
185 if(size)
186 *size = l + 1;
187 }
188 return 0;
189 }
190
191 static int
fuzzer_put_tag(unsigned char * p,size_t len,Der_class class,Der_type type,unsigned int tag,size_t * size)192 fuzzer_put_tag (unsigned char *p, size_t len, Der_class class, Der_type type,
193 unsigned int tag, size_t *size)
194 {
195 unsigned fcont = 0;
196
197 if (tag <= 30) {
198 if (len < 1)
199 return ASN1_OVERFLOW;
200 if (fuzzer_trigger(100))
201 *p = MAKE_TAG(class, type, 0x1f);
202 else
203 *p = MAKE_TAG(class, type, tag);
204 *size = 1;
205 } else {
206 size_t ret = 0;
207 unsigned int continuation = 0;
208
209 do {
210 if (len < 1)
211 return ASN1_OVERFLOW;
212 *p-- = tag % 128 | continuation;
213 len--;
214 ret++;
215 tag /= 128;
216 continuation = 0x80;
217 } while(tag > 0);
218 if (len < 1)
219 return ASN1_OVERFLOW;
220 if (fuzzer_trigger(100))
221 *p-- = MAKE_TAG(class, type, 0);
222 else
223 *p-- = MAKE_TAG(class, type, 0x1f);
224 ret++;
225 *size = ret;
226 }
227 return 0;
228 }
229
230 static int
fuzzer_put_length_and_tag(unsigned char * p,size_t len,size_t len_val,Der_class class,Der_type type,unsigned int tag,size_t * size)231 fuzzer_put_length_and_tag (unsigned char *p, size_t len, size_t len_val,
232 Der_class class, Der_type type,
233 unsigned int tag, size_t *size)
234 {
235 size_t ret = 0;
236 size_t l;
237 int e;
238
239 e = fuzzer_put_length (p, len, len_val, &l);
240 if(e)
241 return e;
242 p -= l;
243 len -= l;
244 ret += l;
245 e = fuzzer_put_tag (p, len, class, type, tag, &l);
246 if(e)
247 return e;
248
249 ret += l;
250 *size = ret;
251 return 0;
252 }
253
254 static int
fuzzer_put_general_string(unsigned char * p,size_t len,const heim_general_string * str,size_t * size)255 fuzzer_put_general_string (unsigned char *p, size_t len,
256 const heim_general_string *str, size_t *size)
257 {
258 size_t slen = strlen(*str);
259
260 if (len < slen)
261 return ASN1_OVERFLOW;
262 p -= slen;
263 if (slen >= 2 && fuzzer_trigger(100)) {
264 memcpy(p+1, *str, slen);
265 memcpy(p+1, "%s", 2);
266 } else if (slen >= 2 && fuzzer_trigger(100)) {
267 memcpy(p+1, *str, slen);
268 memcpy(p+1, "%n", 2);
269 } else if (slen >= 4 && fuzzer_trigger(100)) {
270 memcpy(p+1, *str, slen);
271 memcpy(p+1, "%10n", 4);
272 } else if (slen >= 10 && fuzzer_trigger(100)) {
273 memcpy(p+1, *str, slen);
274 memcpy(p+1, "%n%n%n%n%n", 10);
275 } else if (slen >= 10 && fuzzer_trigger(100)) {
276 memcpy(p+1, *str, slen);
277 memcpy(p+1, "%n%p%s%d%x", 10);
278 } else if (slen >= 7 && fuzzer_trigger(100)) {
279 memcpy(p+1, *str, slen);
280 memcpy(p+1, "%.1024d", 7);
281 } else if (slen >= 7 && fuzzer_trigger(100)) {
282 memcpy(p+1, *str, slen);
283 memcpy(p+1, "%.2049d", 7);
284 } else if (fuzzer_trigger(100)) {
285 memset(p+1, 0, slen);
286 } else if (fuzzer_trigger(100)) {
287 memset(p+1, 0xff, slen);
288 } else if (fuzzer_trigger(100)) {
289 memset(p+1, 'A', slen);
290 } else {
291 memcpy(p+1, *str, slen);
292 }
293 *size = slen;
294 return 0;
295 }
296
297
298 struct asn1_type_func fuzzerprim[A1T_NUM_ENTRY] = {
299 #define fuzel(name, type) { \
300 (asn1_type_encode)fuzzer_put_##name, \
301 (asn1_type_decode)der_get_##name, \
302 (asn1_type_length)der_length_##name, \
303 (asn1_type_copy)der_copy_##name, \
304 (asn1_type_release)der_free_##name, \
305 sizeof(type) \
306 }
307 #define el(name, type) { \
308 (asn1_type_encode)der_put_##name, \
309 (asn1_type_decode)der_get_##name, \
310 (asn1_type_length)der_length_##name, \
311 (asn1_type_copy)der_copy_##name, \
312 (asn1_type_release)der_free_##name, \
313 sizeof(type) \
314 }
315 #define elber(name, type) { \
316 (asn1_type_encode)der_put_##name, \
317 (asn1_type_decode)der_get_##name##_ber, \
318 (asn1_type_length)der_length_##name, \
319 (asn1_type_copy)der_copy_##name, \
320 (asn1_type_release)der_free_##name, \
321 sizeof(type) \
322 }
323 el(integer, int),
324 el(integer64, int64_t),
325 el(heim_integer, heim_integer),
326 el(integer, int),
327 el(unsigned, unsigned),
328 el(uninteger64, uint64_t),
329 fuzel(general_string, heim_general_string),
330 el(octet_string, heim_octet_string),
331 elber(octet_string, heim_octet_string),
332 el(ia5_string, heim_ia5_string),
333 el(bmp_string, heim_bmp_string),
334 el(universal_string, heim_universal_string),
335 el(printable_string, heim_printable_string),
336 el(visible_string, heim_visible_string),
337 el(utf8string, heim_utf8_string),
338 el(generalized_time, time_t),
339 el(utctime, time_t),
340 el(bit_string, heim_bit_string),
341 { (asn1_type_encode)der_put_boolean, (asn1_type_decode)der_get_boolean,
342 (asn1_type_length)der_length_boolean, (asn1_type_copy)der_copy_integer,
343 (asn1_type_release)der_free_integer, sizeof(int)
344 },
345 el(oid, heim_oid),
346 el(general_string, heim_general_string),
347 #undef fuzel
348 #undef el
349 #undef elber
350 };
351
352
353
354 int
_asn1_encode_fuzzer(const struct asn1_template * t,unsigned char * p,size_t len,const void * data,size_t * size)355 _asn1_encode_fuzzer(const struct asn1_template *t,
356 unsigned char *p, size_t len,
357 const void *data, size_t *size)
358 {
359 size_t elements = A1_HEADER_LEN(t);
360 int ret = 0;
361 size_t oldlen = len;
362
363 t += A1_HEADER_LEN(t);
364
365 while (elements) {
366 switch (t->tt & A1_OP_MASK) {
367 case A1_OP_TYPE:
368 case A1_OP_TYPE_EXTERN: {
369 size_t newsize;
370 const void *el = DPOC(data, t->offset);
371
372 if (t->tt & A1_FLAG_OPTIONAL) {
373 void **pel = (void **)el;
374 if (*pel == NULL)
375 break;
376 el = *pel;
377 }
378
379 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
380 ret = _asn1_encode_fuzzer(t->ptr, p, len, el, &newsize);
381 } else {
382 const struct asn1_type_func *f = t->ptr;
383 ret = (f->encode)(p, len, el, &newsize);
384 }
385
386 if (ret)
387 return ret;
388 p -= newsize; len -= newsize;
389
390 break;
391 }
392 case A1_OP_TAG: {
393 const void *olddata = data;
394 size_t l, datalen;
395
396 data = DPOC(data, t->offset);
397
398 if (t->tt & A1_FLAG_OPTIONAL) {
399 void **el = (void **)data;
400 if (*el == NULL) {
401 data = olddata;
402 break;
403 }
404 data = *el;
405 }
406
407 ret = _asn1_encode_fuzzer(t->ptr, p, len, data, &datalen);
408 if (ret)
409 return ret;
410
411 len -= datalen; p -= datalen;
412
413 ret = fuzzer_put_length_and_tag(p, len, datalen,
414 A1_TAG_CLASS(t->tt),
415 A1_TAG_TYPE(t->tt),
416 A1_TAG_TAG(t->tt), &l);
417 if (ret)
418 return ret;
419
420 p -= l; len -= l;
421
422 data = olddata;
423
424 break;
425 }
426 case A1_OP_PARSE: {
427 unsigned int type = A1_PARSE_TYPE(t->tt);
428 size_t newsize;
429 const void *el = DPOC(data, t->offset);
430
431 if (type > sizeof(fuzzerprim)/sizeof(fuzzerprim[0])) {
432 ABORT_ON_ERROR();
433 return ASN1_PARSE_ERROR;
434 }
435
436 ret = (fuzzerprim[type].encode)(p, len, el, &newsize);
437 if (ret)
438 return ret;
439 p -= newsize; len -= newsize;
440
441 break;
442 }
443 case A1_OP_SETOF: {
444 const struct template_of *el = DPOC(data, t->offset);
445 size_t ellen = _asn1_sizeofType(t->ptr);
446 heim_octet_string *val;
447 unsigned char *elptr = el->val;
448 size_t i, totallen;
449
450 if (el->len == 0)
451 break;
452
453 if (el->len > UINT_MAX/sizeof(val[0]))
454 return ERANGE;
455
456 val = malloc(sizeof(val[0]) * el->len);
457 if (val == NULL)
458 return ENOMEM;
459
460 for(totallen = 0, i = 0; i < el->len; i++) {
461 unsigned char *next;
462 size_t l;
463
464 val[i].length = _asn1_length(t->ptr, elptr);
465 val[i].data = malloc(val[i].length);
466
467 ret = _asn1_encode_fuzzer(t->ptr, DPO(val[i].data, val[i].length - 1),
468 val[i].length, elptr, &l);
469 if (ret)
470 break;
471
472 next = elptr + ellen;
473 if (next < elptr) {
474 ret = ASN1_OVERFLOW;
475 break;
476 }
477 elptr = next;
478 totallen += val[i].length;
479 }
480 if (ret == 0 && totallen > len)
481 ret = ASN1_OVERFLOW;
482 if (ret) {
483 do {
484 free(val[i].data);
485 } while(i-- > 0);
486 free(val);
487 return ret;
488 }
489
490 len -= totallen;
491
492 qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort);
493
494 i = el->len - 1;
495 do {
496 p -= val[i].length;
497 memcpy(p + 1, val[i].data, val[i].length);
498 free(val[i].data);
499 } while(i-- > 0);
500 free(val);
501
502 break;
503
504 }
505 case A1_OP_SEQOF: {
506 struct template_of *el = DPO(data, t->offset);
507 size_t ellen = _asn1_sizeofType(t->ptr);
508 size_t newsize;
509 unsigned int i;
510 unsigned char *elptr = el->val;
511
512 if (el->len == 0)
513 break;
514
515 elptr += ellen * (el->len - 1);
516
517 for (i = 0; i < el->len; i++) {
518 ret = _asn1_encode_fuzzer(t->ptr, p, len,
519 elptr,
520 &newsize);
521 if (ret)
522 return ret;
523 p -= newsize; len -= newsize;
524 elptr -= ellen;
525 }
526
527 break;
528 }
529 case A1_OP_BMEMBER: {
530 const struct asn1_template *bmember = t->ptr;
531 size_t size = bmember->offset;
532 size_t elements = A1_HEADER_LEN(bmember);
533 size_t pos;
534 unsigned char c = 0;
535 unsigned int bitset = 0;
536 int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
537
538 bmember += elements;
539
540 if (rfc1510)
541 pos = 31;
542 else
543 pos = bmember->offset;
544
545 while (elements && len) {
546 while (bmember->offset / 8 < pos / 8) {
547 if (rfc1510 || bitset || c) {
548 if (len < 1)
549 return ASN1_OVERFLOW;
550 *p-- = c; len--;
551 }
552 c = 0;
553 pos -= 8;
554 }
555 _asn1_bmember_put_bit(&c, data, bmember->offset, size, &bitset);
556 elements--; bmember--;
557 }
558 if (rfc1510 || bitset) {
559 if (len < 1)
560 return ASN1_OVERFLOW;
561 *p-- = c; len--;
562 }
563
564 if (len < 1)
565 return ASN1_OVERFLOW;
566 if (rfc1510 || bitset == 0)
567 *p-- = 0;
568 else
569 *p-- = bitset - 1;
570
571 len--;
572
573 break;
574 }
575 case A1_OP_CHOICE: {
576 const struct asn1_template *choice = t->ptr;
577 const unsigned int *element = DPOC(data, choice->offset);
578 size_t datalen;
579 const void *el;
580
581 if (*element > A1_HEADER_LEN(choice)) {
582 printf("element: %d\n", *element);
583 return ASN1_PARSE_ERROR;
584 }
585
586 if (*element == 0) {
587 ret += der_put_octet_string(p, len,
588 DPOC(data, choice->tt), &datalen);
589 } else {
590 choice += *element;
591 el = DPOC(data, choice->offset);
592 ret = _asn1_encode_fuzzer(choice->ptr, p, len, el, &datalen);
593 if (ret)
594 return ret;
595 }
596 len -= datalen; p -= datalen;
597
598 break;
599 }
600 default:
601 ABORT_ON_ERROR();
602 }
603 t--;
604 elements--;
605 }
606
607 if (fuzzer_trigger(1000)) {
608 memset(p + 1, 0, oldlen - len);
609 } else if (fuzzer_trigger(1000)) {
610 memset(p + 1, 0x41, oldlen - len);
611 } else if (fuzzer_trigger(1000)) {
612 memset(p + 1, 0xff, oldlen - len);
613 }
614
615 if (size)
616 *size = oldlen - len;
617
618 return 0;
619 }
620
621 size_t
_asn1_length_fuzzer(const struct asn1_template * t,const void * data)622 _asn1_length_fuzzer(const struct asn1_template *t, const void *data)
623 {
624 size_t elements = A1_HEADER_LEN(t);
625 size_t ret = 0;
626
627 t += A1_HEADER_LEN(t);
628
629 while (elements) {
630 switch (t->tt & A1_OP_MASK) {
631 case A1_OP_TYPE:
632 case A1_OP_TYPE_EXTERN: {
633 const void *el = DPOC(data, t->offset);
634
635 if (t->tt & A1_FLAG_OPTIONAL) {
636 void **pel = (void **)el;
637 if (*pel == NULL)
638 break;
639 el = *pel;
640 }
641
642 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
643 ret += _asn1_length(t->ptr, el);
644 } else {
645 const struct asn1_type_func *f = t->ptr;
646 ret += (f->length)(el);
647 }
648 break;
649 }
650 case A1_OP_TAG: {
651 size_t datalen;
652 const void *olddata = data;
653
654 data = DPO(data, t->offset);
655
656 if (t->tt & A1_FLAG_OPTIONAL) {
657 void **el = (void **)data;
658 if (*el == NULL) {
659 data = olddata;
660 break;
661 }
662 data = *el;
663 }
664 datalen = _asn1_length(t->ptr, data);
665 ret += der_length_tag(A1_TAG_TAG(t->tt)) + fuzzer_length_len(datalen);
666 ret += datalen;
667 data = olddata;
668 break;
669 }
670 case A1_OP_PARSE: {
671 unsigned int type = A1_PARSE_TYPE(t->tt);
672 const void *el = DPOC(data, t->offset);
673
674 if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) {
675 ABORT_ON_ERROR();
676 break;
677 }
678 ret += (asn1_template_prim[type].length)(el);
679 break;
680 }
681 case A1_OP_SETOF:
682 case A1_OP_SEQOF: {
683 const struct template_of *el = DPOC(data, t->offset);
684 size_t ellen = _asn1_sizeofType(t->ptr);
685 const unsigned char *element = el->val;
686 unsigned int i;
687
688 for (i = 0; i < el->len; i++) {
689 ret += _asn1_length(t->ptr, element);
690 element += ellen;
691 }
692
693 break;
694 }
695 case A1_OP_BMEMBER: {
696 const struct asn1_template *bmember = t->ptr;
697 size_t size = bmember->offset;
698 size_t elements = A1_HEADER_LEN(bmember);
699 int rfc1510 = (bmember->tt & A1_HBF_RFC1510);
700
701 if (rfc1510) {
702 ret += 5;
703 } else {
704
705 ret += 1;
706
707 bmember += elements;
708
709 while (elements) {
710 if (_asn1_bmember_isset_bit(data, bmember->offset, size)) {
711 ret += (bmember->offset / 8) + 1;
712 break;
713 }
714 elements--; bmember--;
715 }
716 }
717 break;
718 }
719 case A1_OP_CHOICE: {
720 const struct asn1_template *choice = t->ptr;
721 const unsigned int *element = DPOC(data, choice->offset);
722
723 if (*element > A1_HEADER_LEN(choice))
724 break;
725
726 if (*element == 0) {
727 ret += der_length_octet_string(DPOC(data, choice->tt));
728 } else {
729 choice += *element;
730 ret += _asn1_length(choice->ptr, DPOC(data, choice->offset));
731 }
732 break;
733 }
734 default:
735 ABORT_ON_ERROR();
736 break;
737 }
738 elements--;
739 t--;
740 }
741 return ret;
742 }
743
744 #endif /* ASN1_FUZZER */
745