2 * Copyright (c) 2009 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 enum trigger_method
{ FOFF
, FRANDOM
, FLINEAR
, FLINEAR_SIZE
};
42 static enum trigger_method method
= FOFF
;
45 static unsigned long fnum
, fcur
, fsize
;
49 asn1_fuzzer_method(const char *mode
)
52 if (mode
== NULL
|| strcasecmp(mode
, "off") == 0) {
54 } else if (strcasecmp(mode
, "random") == 0) {
56 } else if (strcasecmp(mode
, "linear") == 0) {
58 } else if (strcasecmp(mode
, "linear-size") == 0) {
59 method
= FLINEAR_SIZE
;
69 asn1_fuzzer_reset(void)
79 asn1_fuzzer_next(void)
89 asn1_fuzzer_done(void)
94 /* since code paths */
95 return (fnum
> 10000);
102 fuzzer_trigger(unsigned int chance
)
108 if ((rk_random() % chance
) != 1)
122 fuzzer_size_trigger(unsigned long *cur
)
124 if (method
!= FLINEAR_SIZE
)
126 if (fnum
== (*cur
)++)
132 fuzzer_length_len (size_t len
)
134 if (fuzzer_size_trigger(&fsize
)) {
136 } else if (fuzzer_size_trigger(&fsize
)) {
138 } else if (fuzzer_size_trigger(&fsize
)) {
155 fuzzer_put_length (unsigned char *p
, size_t len
, size_t val
, size_t *size
)
158 return ASN1_OVERFLOW
;
160 if (fuzzer_size_trigger(&fcur
)) {
162 } else if (fuzzer_size_trigger(&fcur
)) {
164 } else if (fuzzer_size_trigger(&fcur
)) {
176 return ASN1_OVERFLOW
;
190 fuzzer_put_tag (unsigned char *p
, size_t len
, Der_class
class, Der_type type
,
191 unsigned int tag
, size_t *size
)
197 return ASN1_OVERFLOW
;
198 if (fuzzer_trigger(100))
199 *p
= MAKE_TAG(class, type
, 0x1f);
201 *p
= MAKE_TAG(class, type
, tag
);
205 unsigned int continuation
= 0;
209 return ASN1_OVERFLOW
;
210 *p
-- = tag
% 128 | continuation
;
217 return ASN1_OVERFLOW
;
218 if (fuzzer_trigger(100))
219 *p
-- = MAKE_TAG(class, type
, 0);
221 *p
-- = MAKE_TAG(class, type
, 0x1f);
229 fuzzer_put_length_and_tag (unsigned char *p
, size_t len
, size_t len_val
,
230 Der_class
class, Der_type type
,
231 unsigned int tag
, size_t *size
)
237 e
= fuzzer_put_length (p
, len
, len_val
, &l
);
243 e
= fuzzer_put_tag (p
, len
, class, type
, tag
, &l
);
253 fuzzer_put_general_string (unsigned char *p
, size_t len
,
254 const heim_general_string
*str
, size_t *size
)
256 size_t slen
= strlen(*str
);
259 return ASN1_OVERFLOW
;
261 if (slen
>= 2 && fuzzer_trigger(100)) {
262 memcpy(p
+1, *str
, slen
);
263 memcpy(p
+1, "%s", 2);
264 } else if (slen
>= 2 && fuzzer_trigger(100)) {
265 memcpy(p
+1, *str
, slen
);
266 memcpy(p
+1, "%n", 2);
267 } else if (slen
>= 4 && fuzzer_trigger(100)) {
268 memcpy(p
+1, *str
, slen
);
269 memcpy(p
+1, "%10n", 4);
270 } else if (slen
>= 10 && fuzzer_trigger(100)) {
271 memcpy(p
+1, *str
, slen
);
272 memcpy(p
+1, "%n%n%n%n%n", 10);
273 } else if (slen
>= 10 && fuzzer_trigger(100)) {
274 memcpy(p
+1, *str
, slen
);
275 memcpy(p
+1, "%n%p%s%d%x", 10);
276 } else if (slen
>= 7 && fuzzer_trigger(100)) {
277 memcpy(p
+1, *str
, slen
);
278 memcpy(p
+1, "%.1024d", 7);
279 } else if (slen
>= 7 && fuzzer_trigger(100)) {
280 memcpy(p
+1, *str
, slen
);
281 memcpy(p
+1, "%.2049d", 7);
282 } else if (fuzzer_trigger(100)) {
283 memset(p
+1, 0, slen
);
284 } else if (fuzzer_trigger(100)) {
285 memset(p
+1, 0xff, slen
);
286 } else if (fuzzer_trigger(100)) {
287 memset(p
+1, 'A', slen
);
289 memcpy(p
+1, *str
, slen
);
296 struct asn1_type_func fuzzerprim
[A1T_NUM_ENTRY
] = {
297 #define fuzel(name, type) { \
298 (asn1_type_encode)fuzzer_put_##name, \
299 (asn1_type_decode)der_get_##name, \
300 (asn1_type_length)der_length_##name, \
301 (asn1_type_copy)der_copy_##name, \
302 (asn1_type_release)der_free_##name, \
305 #define el(name, type) { \
306 (asn1_type_encode)der_put_##name, \
307 (asn1_type_decode)der_get_##name, \
308 (asn1_type_length)der_length_##name, \
309 (asn1_type_copy)der_copy_##name, \
310 (asn1_type_release)der_free_##name, \
313 #define elber(name, type) { \
314 (asn1_type_encode)der_put_##name, \
315 (asn1_type_decode)der_get_##name##_ber, \
316 (asn1_type_length)der_length_##name, \
317 (asn1_type_copy)der_copy_##name, \
318 (asn1_type_release)der_free_##name, \
322 el(integer64
, int64_t),
323 el(heim_integer
, heim_integer
),
325 el(unsigned, unsigned),
326 el(uninteger64
, uint64_t),
327 fuzel(general_string
, heim_general_string
),
328 el(octet_string
, heim_octet_string
),
329 elber(octet_string
, heim_octet_string
),
330 el(ia5_string
, heim_ia5_string
),
331 el(bmp_string
, heim_bmp_string
),
332 el(universal_string
, heim_universal_string
),
333 el(printable_string
, heim_printable_string
),
334 el(visible_string
, heim_visible_string
),
335 el(utf8string
, heim_utf8_string
),
336 el(generalized_time
, time_t),
338 el(bit_string
, heim_bit_string
),
339 { (asn1_type_encode
)der_put_boolean
, (asn1_type_decode
)der_get_boolean
,
340 (asn1_type_length
)der_length_boolean
, (asn1_type_copy
)der_copy_integer
,
341 (asn1_type_release
)der_free_integer
, sizeof(int)
344 el(general_string
, heim_general_string
),
353 _asn1_encode_fuzzer(const struct asn1_template
*t
,
354 unsigned char *p
, size_t len
,
355 const void *data
, size_t *size
)
357 size_t elements
= A1_HEADER_LEN(t
);
361 t
+= A1_HEADER_LEN(t
);
364 switch (t
->tt
& A1_OP_MASK
) {
366 case A1_OP_TYPE_EXTERN
: {
368 const void *el
= DPOC(data
, t
->offset
);
370 if (t
->tt
& A1_FLAG_OPTIONAL
) {
371 void **pel
= (void **)el
;
377 if ((t
->tt
& A1_OP_MASK
) == A1_OP_TYPE
) {
378 ret
= _asn1_encode_fuzzer(t
->ptr
, p
, len
, el
, &newsize
);
380 const struct asn1_type_func
*f
= t
->ptr
;
381 ret
= (f
->encode
)(p
, len
, el
, &newsize
);
386 p
-= newsize
; len
-= newsize
;
391 const void *olddata
= data
;
394 data
= DPOC(data
, t
->offset
);
396 if (t
->tt
& A1_FLAG_OPTIONAL
) {
397 void **el
= (void **)data
;
405 ret
= _asn1_encode_fuzzer(t
->ptr
, p
, len
, data
, &datalen
);
409 len
-= datalen
; p
-= datalen
;
411 ret
= fuzzer_put_length_and_tag(p
, len
, datalen
,
414 A1_TAG_TAG(t
->tt
), &l
);
425 unsigned int type
= A1_PARSE_TYPE(t
->tt
);
427 const void *el
= DPOC(data
, t
->offset
);
429 if (type
> sizeof(fuzzerprim
)/sizeof(fuzzerprim
[0])) {
431 return ASN1_PARSE_ERROR
;
434 ret
= (fuzzerprim
[type
].encode
)(p
, len
, el
, &newsize
);
437 p
-= newsize
; len
-= newsize
;
442 const struct template_of
*el
= DPOC(data
, t
->offset
);
443 size_t ellen
= _asn1_sizeofType(t
->ptr
);
444 heim_octet_string
*val
;
445 unsigned char *elptr
= el
->val
;
451 if (el
->len
> UINT_MAX
/sizeof(val
[0]))
454 val
= malloc(sizeof(val
[0]) * el
->len
);
458 for(totallen
= 0, i
= 0; i
< el
->len
; i
++) {
462 val
[i
].length
= _asn1_length(t
->ptr
, elptr
);
463 val
[i
].data
= malloc(val
[i
].length
);
465 ret
= _asn1_encode_fuzzer(t
->ptr
, DPO(val
[i
].data
, val
[i
].length
- 1),
466 val
[i
].length
, elptr
, &l
);
470 next
= elptr
+ ellen
;
476 totallen
+= val
[i
].length
;
478 if (ret
== 0 && totallen
> len
)
490 qsort(val
, el
->len
, sizeof(val
[0]), _heim_der_set_sort
);
495 memcpy(p
+ 1, val
[i
].data
, val
[i
].length
);
504 struct template_of
*el
= DPO(data
, t
->offset
);
505 size_t ellen
= _asn1_sizeofType(t
->ptr
);
508 unsigned char *elptr
= el
->val
;
513 elptr
+= ellen
* (el
->len
- 1);
515 for (i
= 0; i
< el
->len
; i
++) {
516 ret
= _asn1_encode_fuzzer(t
->ptr
, p
, len
,
521 p
-= newsize
; len
-= newsize
;
527 case A1_OP_BMEMBER
: {
528 const struct asn1_template
*bmember
= t
->ptr
;
529 size_t size
= bmember
->offset
;
530 size_t elements
= A1_HEADER_LEN(bmember
);
533 unsigned int bitset
= 0;
534 int rfc1510
= (bmember
->tt
& A1_HBF_RFC1510
);
541 pos
= bmember
->offset
;
543 while (elements
&& len
) {
544 while (bmember
->offset
/ 8 < pos
/ 8) {
545 if (rfc1510
|| bitset
|| c
) {
547 return ASN1_OVERFLOW
;
553 _asn1_bmember_put_bit(&c
, data
, bmember
->offset
, size
, &bitset
);
554 elements
--; bmember
--;
556 if (rfc1510
|| bitset
) {
558 return ASN1_OVERFLOW
;
563 return ASN1_OVERFLOW
;
564 if (rfc1510
|| bitset
== 0)
574 const struct asn1_template
*choice
= t
->ptr
;
575 const unsigned int *element
= DPOC(data
, choice
->offset
);
579 if (*element
> A1_HEADER_LEN(choice
)) {
580 printf("element: %d\n", *element
);
581 return ASN1_PARSE_ERROR
;
585 ret
+= der_put_octet_string(p
, len
,
586 DPOC(data
, choice
->tt
), &datalen
);
589 el
= DPOC(data
, choice
->offset
);
590 ret
= _asn1_encode_fuzzer(choice
->ptr
, p
, len
, el
, &datalen
);
594 len
-= datalen
; p
-= datalen
;
605 if (fuzzer_trigger(1000)) {
606 memset(p
+ 1, 0, oldlen
- len
);
607 } else if (fuzzer_trigger(1000)) {
608 memset(p
+ 1, 0x41, oldlen
- len
);
609 } else if (fuzzer_trigger(1000)) {
610 memset(p
+ 1, 0xff, oldlen
- len
);
614 *size
= oldlen
- len
;
620 _asn1_length_fuzzer(const struct asn1_template
*t
, const void *data
)
622 size_t elements
= A1_HEADER_LEN(t
);
625 t
+= A1_HEADER_LEN(t
);
628 switch (t
->tt
& A1_OP_MASK
) {
630 case A1_OP_TYPE_EXTERN
: {
631 const void *el
= DPOC(data
, t
->offset
);
633 if (t
->tt
& A1_FLAG_OPTIONAL
) {
634 void **pel
= (void **)el
;
640 if ((t
->tt
& A1_OP_MASK
) == A1_OP_TYPE
) {
641 ret
+= _asn1_length(t
->ptr
, el
);
643 const struct asn1_type_func
*f
= t
->ptr
;
644 ret
+= (f
->length
)(el
);
650 const void *olddata
= data
;
652 data
= DPO(data
, t
->offset
);
654 if (t
->tt
& A1_FLAG_OPTIONAL
) {
655 void **el
= (void **)data
;
662 datalen
= _asn1_length(t
->ptr
, data
);
663 ret
+= der_length_tag(A1_TAG_TAG(t
->tt
)) + fuzzer_length_len(datalen
);
669 unsigned int type
= A1_PARSE_TYPE(t
->tt
);
670 const void *el
= DPOC(data
, t
->offset
);
672 if (type
>= sizeof(asn1_template_prim
)/sizeof(asn1_template_prim
[0])) {
676 ret
+= (asn1_template_prim
[type
].length
)(el
);
681 const struct template_of
*el
= DPOC(data
, t
->offset
);
682 size_t ellen
= _asn1_sizeofType(t
->ptr
);
683 const unsigned char *element
= el
->val
;
686 for (i
= 0; i
< el
->len
; i
++) {
687 ret
+= _asn1_length(t
->ptr
, element
);
693 case A1_OP_BMEMBER
: {
694 const struct asn1_template
*bmember
= t
->ptr
;
695 size_t size
= bmember
->offset
;
696 size_t elements
= A1_HEADER_LEN(bmember
);
697 int rfc1510
= (bmember
->tt
& A1_HBF_RFC1510
);
708 if (_asn1_bmember_isset_bit(data
, bmember
->offset
, size
)) {
709 ret
+= (bmember
->offset
/ 8) + 1;
712 elements
--; bmember
--;
718 const struct asn1_template
*choice
= t
->ptr
;
719 const unsigned int *element
= DPOC(data
, choice
->offset
);
721 if (*element
> A1_HEADER_LEN(choice
))
725 ret
+= der_length_octet_string(DPOC(data
, choice
->tt
));
728 ret
+= _asn1_length(choice
->ptr
, DPOC(data
, choice
->offset
));
742 #endif /* ASN1_FUZZER */