1 /*
2  * Fuzzing tool for ASN.1 routines
3  * Copyright (c) 2006-2019, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 
11 #include "common.h"
12 #include "tls/asn1.h"
13 #include "../fuzzer-common.h"
14 
15 
asn1_class_str(int class)16 static const char * asn1_class_str(int class)
17 {
18 	switch (class) {
19 	case ASN1_CLASS_UNIVERSAL:
20 		return "Universal";
21 	case ASN1_CLASS_APPLICATION:
22 		return "Application";
23 	case ASN1_CLASS_CONTEXT_SPECIFIC:
24 		return "Context-specific";
25 	case ASN1_CLASS_PRIVATE:
26 		return "Private";
27 	default:
28 		return "?";
29 	}
30 }
31 
32 
asn1_parse(const u8 * buf,size_t len,int level)33 static int asn1_parse(const u8 *buf, size_t len, int level)
34 {
35 	const u8 *pos, *prev, *end;
36 	char prefix[10], str[100];
37 	int _level;
38 	struct asn1_hdr hdr;
39 	struct asn1_oid oid;
40 	u8 tmp;
41 
42 	_level = level;
43 	if ((size_t) _level > sizeof(prefix) - 1)
44 		_level = sizeof(prefix) - 1;
45 	memset(prefix, ' ', _level);
46 	prefix[_level] = '\0';
47 
48 	pos = buf;
49 	end = buf + len;
50 
51 	while (pos < end) {
52 		if (asn1_get_next(pos, end - pos, &hdr) < 0)
53 			return -1;
54 
55 		prev = pos;
56 		pos = hdr.payload;
57 
58 		wpa_printf(MSG_MSGDUMP, "ASN.1:%s Class %d(%s) P/C %d(%s) "
59 			   "Tag %u Length %u",
60 			   prefix, hdr.class, asn1_class_str(hdr.class),
61 			   hdr.constructed,
62 			   hdr.constructed ? "Constructed" : "Primitive",
63 			   hdr.tag, hdr.length);
64 
65 		if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC &&
66 		    hdr.constructed) {
67 			if (asn1_parse(pos, hdr.length, level + 1) < 0)
68 				return -1;
69 			pos += hdr.length;
70 		}
71 
72 		if (hdr.class != ASN1_CLASS_UNIVERSAL)
73 			continue;
74 
75 		switch (hdr.tag) {
76 		case ASN1_TAG_EOC:
77 			if (hdr.length) {
78 				wpa_printf(MSG_DEBUG, "ASN.1: Non-zero "
79 					   "end-of-contents length (%u)",
80 					   hdr.length);
81 				return -1;
82 			}
83 			wpa_printf(MSG_MSGDUMP, "ASN.1:%s EOC", prefix);
84 			break;
85 		case ASN1_TAG_BOOLEAN:
86 			if (hdr.length != 1) {
87 				wpa_printf(MSG_DEBUG, "ASN.1: Unexpected "
88 					   "Boolean length (%u)", hdr.length);
89 				return -1;
90 			}
91 			tmp = *pos++;
92 			wpa_printf(MSG_MSGDUMP, "ASN.1:%s Boolean %s",
93 				   prefix, tmp ? "TRUE" : "FALSE");
94 			break;
95 		case ASN1_TAG_INTEGER:
96 			wpa_hexdump(MSG_MSGDUMP, "ASN.1: INTEGER",
97 				    pos, hdr.length);
98 			pos += hdr.length;
99 			break;
100 		case ASN1_TAG_BITSTRING:
101 			wpa_hexdump(MSG_MSGDUMP, "ASN.1: BitString",
102 				    pos, hdr.length);
103 			pos += hdr.length;
104 			break;
105 		case ASN1_TAG_OCTETSTRING:
106 			wpa_hexdump(MSG_MSGDUMP, "ASN.1: OctetString",
107 				    pos, hdr.length);
108 			pos += hdr.length;
109 			break;
110 		case ASN1_TAG_NULL:
111 			if (hdr.length) {
112 				wpa_printf(MSG_DEBUG, "ASN.1: Non-zero Null "
113 					   "length (%u)", hdr.length);
114 				return -1;
115 			}
116 			wpa_printf(MSG_MSGDUMP, "ASN.1:%s Null", prefix);
117 			break;
118 		case ASN1_TAG_OID:
119 			if (asn1_get_oid(prev, end - prev, &oid, &prev) < 0) {
120 				wpa_printf(MSG_DEBUG, "ASN.1: Invalid OID");
121 				return -1;
122 			}
123 			asn1_oid_to_str(&oid, str, sizeof(str));
124 			wpa_printf(MSG_DEBUG, "ASN.1:%s OID %s", prefix, str);
125 			pos += hdr.length;
126 			break;
127 		case ANS1_TAG_RELATIVE_OID:
128 			wpa_hexdump(MSG_MSGDUMP, "ASN.1: Relative OID",
129 				    pos, hdr.length);
130 			pos += hdr.length;
131 			break;
132 		case ASN1_TAG_SEQUENCE:
133 			wpa_printf(MSG_MSGDUMP, "ASN.1:%s SEQUENCE", prefix);
134 			if (asn1_parse(pos, hdr.length, level + 1) < 0)
135 				return -1;
136 			pos += hdr.length;
137 			break;
138 		case ASN1_TAG_SET:
139 			wpa_printf(MSG_MSGDUMP, "ASN.1:%s SET", prefix);
140 			if (asn1_parse(pos, hdr.length, level + 1) < 0)
141 				return -1;
142 			pos += hdr.length;
143 			break;
144 		case ASN1_TAG_PRINTABLESTRING:
145 			wpa_hexdump_ascii(MSG_MSGDUMP,
146 					  "ASN.1: PrintableString",
147 					  pos, hdr.length);
148 			pos += hdr.length;
149 			break;
150 		case ASN1_TAG_IA5STRING:
151 			wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: IA5String",
152 					  pos, hdr.length);
153 			pos += hdr.length;
154 			break;
155 		case ASN1_TAG_UTCTIME:
156 			wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: UTCTIME",
157 					  pos, hdr.length);
158 			pos += hdr.length;
159 			break;
160 		case ASN1_TAG_VISIBLESTRING:
161 			wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: VisibleString",
162 					  pos, hdr.length);
163 			pos += hdr.length;
164 			break;
165 		default:
166 			wpa_printf(MSG_DEBUG, "ASN.1: Unknown tag %d",
167 				   hdr.tag);
168 			return -1;
169 		}
170 	}
171 
172 	return 0;
173 }
174 
175 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)176 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
177 {
178 	wpa_fuzzer_set_debug_level();
179 
180 	if (asn1_parse(data, size, 0) < 0)
181 		wpa_printf(MSG_DEBUG, "Failed to parse DER ASN.1");
182 
183 	return 0;
184 }
185