1/* 2 * Copyright (c) 2011 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2011 - 2013 Apple Inc. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 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. 18 * 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. 22 * 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 33 * SUCH DAMAGE. 34 */ 35 36#include <sys/types.h> 37#include <inttypes.h> 38#include <roken.h> 39#include "asn1-common.h" 40#include "der.h" 41 42#define HEIM_FUZZER_INTERNALS 1 43#include "fuzzer.h" 44 45/* 46 */ 47 48struct context { 49 char *interesting; 50 size_t size; 51 unsigned long permutation; 52 unsigned long iteration; 53 size_t current; 54}; 55 56typedef int (*ap)(struct context *, unsigned char *, size_t); 57 58/* 59 * 60 */ 61 62static int 63tag_permutate(struct context *context, unsigned char *data, size_t len) 64{ 65 return 1; 66} 67 68static int 69size_permutate(struct context *context, unsigned char *data, size_t len) 70{ 71 return 1; 72} 73static int 74integer_permutate(struct context *context, unsigned char *data, size_t len) 75{ 76 return 1; 77} 78static int 79os_permutate(struct context *context, unsigned char *data, size_t len) 80{ 81 return 1; 82} 83static int 84string_permutate(struct context *context, unsigned char *data, size_t len) 85{ 86 return 1; 87} 88static int 89oid_permutate(struct context *context, unsigned char *data, size_t len) 90{ 91 return 1; 92} 93 94struct perm { 95 char type; 96 const char *name; 97 ap perm; 98} permuntations[] = { 99 { 'T', "tag", tag_permutate }, 100 { 'S', "size", size_permutate }, 101 { 'd', "integer", integer_permutate }, 102 { 'o', "octet string", os_permutate }, 103 { 's', "string", string_permutate }, 104 { 'd', "oid", oid_permutate } 105}; 106 107static unsigned long indefinite_form_loop; 108static unsigned long indefinite_form_loop_max = 20; 109 110static void 111find_interesting(unsigned char *buf, size_t len, char *interesting) 112{ 113 unsigned char *start_buf = buf; 114 115 memset(interesting, 0, len); 116 117 while (len > 0) { 118 int ret; 119 Der_class cls; 120 Der_type type; 121 unsigned int tag; 122 size_t sz; 123 size_t length; 124 int end_tag = 0; 125 126 ret = der_get_tag (buf, len, &cls, &type, &tag, &sz); 127 if (ret) { 128 warn("der_get_tag failed at offset %lu: %d", (unsigned long)(buf - start_buf), ret); 129 return; 130 } 131 if (sz > len) { 132 warn("unreasonable length (%u) > %u", 133 (unsigned)sz, (unsigned)len); 134 return; 135 } 136 137 memset(interesting, 'T', sz); 138 interesting += sz; 139 buf += sz; 140 len -= sz; 141 142 ret = der_get_length (buf, len, &length, &sz); 143 if (ret) { 144 warnx("der_get_tag: %d", ret); 145 return; 146 } 147 if (sz > len) { 148 warnx("unreasonable tag length (%u) > %u", 149 (unsigned)sz, (unsigned)len); 150 return; 151 } 152 153 memset(interesting, 'S', sz); 154 interesting += sz; 155 buf += sz; 156 len -= sz; 157 158 if (length == ASN1_INDEFINITE) { 159 if ((cls == ASN1_C_UNIV && type == PRIM && tag == UT_OctetString) || 160 (cls == ASN1_C_CONTEXT && type == CONS) || 161 (cls == ASN1_C_UNIV && type == CONS && tag == UT_Sequence) || 162 (cls == ASN1_C_UNIV && type == CONS && tag == UT_Set)) { 163 164 } else { 165 fflush(stdout); 166 warnx("indef form used on unsupported object"); 167 return; 168 } 169 end_tag = 1; 170 if (indefinite_form_loop > indefinite_form_loop_max) { 171 warnx("indefinite form used recursively more then %lu " 172 "times, aborting", indefinite_form_loop_max); 173 } 174 indefinite_form_loop++; 175 length = len; 176 } else if (length > len) { 177 printf("\n"); 178 fflush(stdout); 179 warnx("unreasonable inner length (%u) > %u", 180 (unsigned)length, (unsigned)len); 181 return; 182 } 183 if (cls == ASN1_C_CONTEXT || cls == ASN1_C_APPL) { 184 185 if (type == CONS) { 186 size_t offset = buf - start_buf; 187 find_interesting(buf, length, interesting + offset); 188 } 189 } else if (cls == ASN1_C_UNIV) { 190 switch (tag) { 191 case UT_EndOfContent: 192 break; 193 case UT_Set : 194 case UT_Sequence : { 195 find_interesting(buf, length, interesting); 196 break; 197 } 198 case UT_Integer : 199 memset(interesting, 'i', length); 200 break; 201 case UT_OctetString : { 202 heim_octet_string str; 203 Der_class cls2; 204 Der_type type2; 205 unsigned int tag2; 206 207 ret = der_get_octet_string (buf, length, &str, NULL); 208 if (ret) { 209 warnx( "der_get_octet_string: %d", ret); 210 return; 211 } 212 213 ret = der_get_tag(str.data, str.length, 214 &cls2, &type2, &tag2, &sz); 215 if (ret || sz > str.length || type2 != CONS || tag2 != UT_Sequence) { 216 memset(interesting, 'o', length); 217 } else { 218 find_interesting(str.data, str.length, interesting); 219 } 220 break; 221 } 222 case UT_IA5String : 223 case UT_PrintableString : 224 case UT_GeneralizedTime : 225 case UT_GeneralString : 226 case UT_VisibleString : 227 case UT_UTF8String : { 228 memset(interesting, 's', length); 229 break; 230 } 231 case UT_OID: 232 memset(interesting, 'd', length); 233 break; 234 case UT_Enumerated: 235 memset(interesting, 'i', length); 236 break; 237 default : 238 break; 239 } 240 } 241 if (end_tag) { 242 if (indefinite_form_loop == 0) 243 errx(1, "internal error in indefinite form loop detection"); 244 indefinite_form_loop--; 245 } 246 interesting += length; 247 buf += length; 248 len -= length; 249 } 250} 251 252 253/* 254 * 255 */ 256 257static unsigned long 258asn1_tries(size_t length) 259{ 260 return length * 12; 261} 262 263static int 264asn1_fuzz(void **ctx, unsigned long iteration, uint8_t *data, size_t length) 265{ 266 struct context *context; 267 int ret; 268 269 if (*ctx == NULL) { 270 context = calloc(1, sizeof(*context)); 271 272 context->interesting = calloc(1, length + 1); 273 if (context->interesting == NULL) 274 abort(); 275 context->size = length; 276 277 context->interesting[length] = 'e'; 278 279 find_interesting(data, length, context->interesting); 280 281 if (context->interesting[length] != 'e') { 282 printf("find_interesting corrupted interesting buffer\n"); 283 return 1; 284 } 285 286 if (ctx) 287 *ctx = context; 288 289#if 1 290 size_t s; 291 for (s = 0; s < length; s++) { 292 if (context->interesting[s]) { 293 printf("%c", context->interesting[s]); 294 } else { 295 printf("."); 296 } 297 } 298 printf("\n"); 299#endif 300 301 } else { 302 context = *ctx; 303 } 304 305 context->iteration = iteration; 306 307 do { 308 ret = permuntations[context->permutation].perm(context, data, length); 309 if (ret) 310 context->permutation++; 311 312 } while (ret != 0 && context->permutation < sizeof(permuntations)/sizeof(permuntations[0])); 313 314 return ret; 315} 316 317static void 318asn1_fuzz_free(void *ctx) 319{ 320 struct context *context = (struct context *)ctx; 321 free(context->interesting); 322 free(context); 323} 324 325 326const struct heim_fuzz_type_data __heim_fuzz_asn1 = { 327 "asn1", 328 asn1_tries, 329 asn1_fuzz, 330 asn1_fuzz_free 331}; 332 333