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