• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ASN.1 DER parsing
3  * Copyright (c) 2006-2014, 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 "utils/wpabuf.h"
13 #include "asn1.h"
14 
15 const struct asn1_oid asn1_sha1_oid = {
16 	.oid = { 1, 3, 14, 3, 2, 26 },
17 	.len = 6
18 };
19 
20 const struct asn1_oid asn1_sha256_oid = {
21 	.oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 },
22 	.len = 9
23 };
24 
25 const struct asn1_oid asn1_ec_public_key_oid = {
26 	.oid = { 1, 2, 840, 10045, 2, 1 },
27 	.len = 6
28 };
29 
30 const struct asn1_oid asn1_prime256v1_oid = {
31 	.oid = { 1, 2, 840, 10045, 3, 1, 7 },
32 	.len = 7
33 };
34 
35 const struct asn1_oid asn1_secp384r1_oid = {
36 	.oid = { 1, 3, 132, 0, 34 },
37 	.len = 5
38 };
39 
40 const struct asn1_oid asn1_secp521r1_oid = {
41 	.oid = { 1, 3, 132, 0, 35 },
42 	.len = 5
43 };
44 
45 const struct asn1_oid asn1_brainpoolP256r1_oid = {
46 	.oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 7 },
47 	.len = 10
48 };
49 
50 const struct asn1_oid asn1_brainpoolP384r1_oid = {
51 	.oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 11 },
52 	.len = 10
53 };
54 
55 const struct asn1_oid asn1_brainpoolP512r1_oid = {
56 	.oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 13 },
57 	.len = 10
58 };
59 
60 const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid = {
61 	.oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 22 },
62 	.len = 9
63 };
64 
65 const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid = {
66 	.oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 23 },
67 	.len = 9
68 };
69 
70 const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid = {
71 	.oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 24 },
72 	.len = 9
73 };
74 
75 const struct asn1_oid asn1_pbkdf2_oid = {
76 	.oid = { 1, 2, 840, 113549, 1, 5, 12 },
77 	.len = 7
78 };
79 
80 const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid = {
81 	.oid = { 1, 2, 840, 113549, 2, 9 },
82 	.len = 6
83 };
84 
85 const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid = {
86 	.oid = { 1, 2, 840, 113549, 2, 10 },
87 	.len = 6
88 };
89 
90 const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid = {
91 	.oid = { 1, 2, 840, 113549, 2, 11 },
92 	.len = 6
93 };
94 
95 const struct asn1_oid asn1_dpp_config_params_oid = {
96 	.oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 1 },
97 	.len = 10
98 };
99 
100 const struct asn1_oid asn1_dpp_asymmetric_key_package_oid = {
101 	.oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 2 },
102 	.len = 10
103 };
104 
105 
asn1_valid_der_boolean(struct asn1_hdr * hdr)106 static int asn1_valid_der_boolean(struct asn1_hdr *hdr)
107 {
108 	/* Enforce DER requirements for a single way of encoding a BOOLEAN */
109 	if (hdr->length != 1) {
110 		wpa_printf(MSG_DEBUG, "ASN.1: Unexpected BOOLEAN length (%u)",
111 			   hdr->length);
112 		return 0;
113 	}
114 
115 	if (hdr->payload[0] != 0 && hdr->payload[0] != 0xff) {
116 		wpa_printf(MSG_DEBUG,
117 			   "ASN.1: Invalid BOOLEAN value 0x%x (DER requires 0 or 0xff)",
118 			   hdr->payload[0]);
119 		return 0;
120 	}
121 
122 	return 1;
123 }
124 
125 
asn1_valid_der(struct asn1_hdr * hdr)126 static int asn1_valid_der(struct asn1_hdr *hdr)
127 {
128 	if (hdr->class != ASN1_CLASS_UNIVERSAL)
129 		return 1;
130 	if (hdr->tag == ASN1_TAG_BOOLEAN && !asn1_valid_der_boolean(hdr))
131 		return 0;
132 	return 1;
133 }
134 
135 
asn1_get_next(const u8 * buf,size_t len,struct asn1_hdr * hdr)136 int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
137 {
138 	const u8 *pos, *end;
139 	u8 tmp;
140 
141 	os_memset(hdr, 0, sizeof(*hdr));
142 	pos = buf;
143 	end = buf + len;
144 
145 	if (pos >= end) {
146 		wpa_printf(MSG_DEBUG, "ASN.1: No room for Identifier");
147 		return -1;
148 	}
149 	hdr->identifier = *pos++;
150 	hdr->class = hdr->identifier >> 6;
151 	hdr->constructed = !!(hdr->identifier & (1 << 5));
152 
153 	if ((hdr->identifier & 0x1f) == 0x1f) {
154 		hdr->tag = 0;
155 		do {
156 			if (pos >= end) {
157 				wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
158 					   "underflow");
159 				return -1;
160 			}
161 			tmp = *pos++;
162 			wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: "
163 				   "0x%02x", tmp);
164 			hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
165 		} while (tmp & 0x80);
166 	} else
167 		hdr->tag = hdr->identifier & 0x1f;
168 
169 	if (pos >= end) {
170 		wpa_printf(MSG_DEBUG, "ASN.1: No room for Length");
171 		return -1;
172 	}
173 	tmp = *pos++;
174 	if (tmp & 0x80) {
175 		if (tmp == 0xff) {
176 			wpa_printf(MSG_DEBUG, "ASN.1: Reserved length "
177 				   "value 0xff used");
178 			return -1;
179 		}
180 		tmp &= 0x7f; /* number of subsequent octets */
181 		hdr->length = 0;
182 		if (tmp > 4) {
183 			wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
184 			return -1;
185 		}
186 		while (tmp--) {
187 			if (pos >= end) {
188 				wpa_printf(MSG_DEBUG, "ASN.1: Length "
189 					   "underflow");
190 				return -1;
191 			}
192 			hdr->length = (hdr->length << 8) | *pos++;
193 		}
194 	} else {
195 		/* Short form - length 0..127 in one octet */
196 		hdr->length = tmp;
197 	}
198 
199 	if (end < pos || hdr->length > (unsigned int) (end - pos)) {
200 		wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow");
201 		return -1;
202 	}
203 
204 	hdr->payload = pos;
205 
206 	return asn1_valid_der(hdr) ? 0 : -1;
207 }
208 
209 
asn1_parse_oid(const u8 * buf,size_t len,struct asn1_oid * oid)210 int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid)
211 {
212 	const u8 *pos, *end;
213 	unsigned long val;
214 	u8 tmp;
215 
216 	os_memset(oid, 0, sizeof(*oid));
217 
218 	pos = buf;
219 	end = buf + len;
220 
221 	while (pos < end) {
222 		val = 0;
223 
224 		do {
225 			if (pos >= end)
226 				return -1;
227 			tmp = *pos++;
228 			val = (val << 7) | (tmp & 0x7f);
229 		} while (tmp & 0x80);
230 
231 		if (oid->len >= ASN1_MAX_OID_LEN) {
232 			wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value");
233 			return -1;
234 		}
235 		if (oid->len == 0) {
236 			/*
237 			 * The first octet encodes the first two object
238 			 * identifier components in (X*40) + Y formula.
239 			 * X = 0..2.
240 			 */
241 			oid->oid[0] = val / 40;
242 			if (oid->oid[0] > 2)
243 				oid->oid[0] = 2;
244 			oid->oid[1] = val - oid->oid[0] * 40;
245 			oid->len = 2;
246 		} else
247 			oid->oid[oid->len++] = val;
248 	}
249 
250 	return 0;
251 }
252 
253 
asn1_get_oid(const u8 * buf,size_t len,struct asn1_oid * oid,const u8 ** next)254 int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
255 		 const u8 **next)
256 {
257 	struct asn1_hdr hdr;
258 
259 	if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
260 		return -1;
261 
262 	if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) {
263 		wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d "
264 			   "tag 0x%x", hdr.class, hdr.tag);
265 		return -1;
266 	}
267 
268 	*next = hdr.payload + hdr.length;
269 
270 	return asn1_parse_oid(hdr.payload, hdr.length, oid);
271 }
272 
273 
asn1_oid_to_str(const struct asn1_oid * oid,char * buf,size_t len)274 void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len)
275 {
276 	char *pos = buf;
277 	size_t i;
278 	int ret;
279 
280 	if (len == 0)
281 		return;
282 
283 	buf[0] = '\0';
284 
285 	for (i = 0; i < oid->len; i++) {
286 		ret = os_snprintf(pos, buf + len - pos,
287 				  "%s%lu",
288 				  i == 0 ? "" : ".", oid->oid[i]);
289 		if (os_snprintf_error(buf + len - pos, ret))
290 			break;
291 		pos += ret;
292 	}
293 	buf[len - 1] = '\0';
294 }
295 
296 
rotate_bits(u8 octet)297 static u8 rotate_bits(u8 octet)
298 {
299 	int i;
300 	u8 res;
301 
302 	res = 0;
303 	for (i = 0; i < 8; i++) {
304 		res <<= 1;
305 		if (octet & 1)
306 			res |= 1;
307 		octet >>= 1;
308 	}
309 
310 	return res;
311 }
312 
313 
asn1_bit_string_to_long(const u8 * buf,size_t len)314 unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
315 {
316 	unsigned long val = 0;
317 	const u8 *pos = buf;
318 
319 	/* BER requires that unused bits are zero, so we can ignore the number
320 	 * of unused bits */
321 	pos++;
322 
323 	if (len >= 2)
324 		val |= rotate_bits(*pos++);
325 	if (len >= 3)
326 		val |= ((unsigned long) rotate_bits(*pos++)) << 8;
327 	if (len >= 4)
328 		val |= ((unsigned long) rotate_bits(*pos++)) << 16;
329 	if (len >= 5)
330 		val |= ((unsigned long) rotate_bits(*pos++)) << 24;
331 	if (len >= 6)
332 		wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored "
333 			   "(BIT STRING length %lu)",
334 			   __func__, (unsigned long) len);
335 
336 	return val;
337 }
338 
339 
asn1_oid_equal(const struct asn1_oid * a,const struct asn1_oid * b)340 int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b)
341 {
342 	size_t i;
343 
344 	if (a->len != b->len)
345 		return 0;
346 
347 	for (i = 0; i < a->len; i++) {
348 		if (a->oid[i] != b->oid[i])
349 			return 0;
350 	}
351 
352 	return 1;
353 }
354 
355 
asn1_get_integer(const u8 * buf,size_t len,int * integer,const u8 ** next)356 int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next)
357 {
358 	struct asn1_hdr hdr;
359 	size_t left;
360 	const u8 *pos;
361 	int value;
362 
363 	if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
364 		return -1;
365 
366 	if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
367 		wpa_printf(MSG_DEBUG,
368 			   "ASN.1: Expected INTEGER - found class %d tag 0x%x",
369 			   hdr.class, hdr.tag);
370 		return -1;
371 	}
372 
373 	*next = hdr.payload + hdr.length;
374 	pos = hdr.payload;
375 	left = hdr.length;
376 	if (left > sizeof(value)) {
377 		wpa_printf(MSG_DEBUG, "ASN.1: Too large INTEGER (len %u)",
378 			   hdr.length);
379 		return -1;
380 	}
381 	value = 0;
382 	while (left) {
383 		value <<= 8;
384 		value |= *pos++;
385 		left--;
386 	}
387 
388 	*integer = value;
389 	return 0;
390 }
391 
392 
asn1_get_sequence(const u8 * buf,size_t len,struct asn1_hdr * hdr,const u8 ** next)393 int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr,
394 		      const u8 **next)
395 {
396 	if (asn1_get_next(buf, len, hdr) < 0 ||
397 	    hdr->class != ASN1_CLASS_UNIVERSAL ||
398 	    hdr->tag != ASN1_TAG_SEQUENCE) {
399 		wpa_printf(MSG_DEBUG,
400 			   "ASN.1: Expected SEQUENCE - found class %d tag 0x%x",
401 			   hdr->class, hdr->tag);
402 		return -1;
403 	}
404 
405 	if (next)
406 		*next = hdr->payload + hdr->length;
407 	return 0;
408 }
409 
410 
asn1_get_alg_id(const u8 * buf,size_t len,struct asn1_oid * oid,const u8 ** params,size_t * params_len,const u8 ** next)411 int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid,
412 		    const u8 **params, size_t *params_len, const u8 **next)
413 {
414 	const u8 *pos = buf, *end = buf + len;
415 	struct asn1_hdr hdr;
416 
417 	/*
418 	 * AlgorithmIdentifier ::= SEQUENCE {
419 	 *     algorithm            OBJECT IDENTIFIER,
420 	 *     parameters           ANY DEFINED BY algorithm OPTIONAL}
421 	 */
422 	if (asn1_get_sequence(pos, end - pos, &hdr, next) < 0 ||
423 	    asn1_get_oid(hdr.payload, hdr.length, oid, &pos) < 0)
424 		return -1;
425 
426 	if (params && params_len) {
427 		*params = pos;
428 		*params_len = hdr.payload + hdr.length - pos;
429 	}
430 
431 	return 0;
432 }
433 
434 
asn1_put_integer(struct wpabuf * buf,int val)435 void asn1_put_integer(struct wpabuf *buf, int val)
436 {
437 	u8 bin[4];
438 	int zeros;
439 
440 	WPA_PUT_BE32(bin, val);
441 	zeros = 0;
442 	while (zeros < 3 && bin[zeros] == 0)
443 		zeros++;
444 	wpabuf_put_u8(buf, ASN1_TAG_INTEGER);
445 	wpabuf_put_u8(buf, 4 - zeros);
446 	wpabuf_put_data(buf, &bin[zeros], 4 - zeros);
447 }
448 
449 
asn1_put_len(struct wpabuf * buf,size_t len)450 static void asn1_put_len(struct wpabuf *buf, size_t len)
451 {
452 	if (len <= 0x7f) {
453 		wpabuf_put_u8(buf, len);
454 	} else if (len <= 0xff) {
455 		wpabuf_put_u8(buf, 0x80 | 1);
456 		wpabuf_put_u8(buf, len);
457 	} else if (len <= 0xffff) {
458 		wpabuf_put_u8(buf, 0x80 | 2);
459 		wpabuf_put_be16(buf, len);
460 	} else if (len <= 0xffffff) {
461 		wpabuf_put_u8(buf, 0x80 | 3);
462 		wpabuf_put_be24(buf, len);
463 	} else {
464 		wpabuf_put_u8(buf, 0x80 | 4);
465 		wpabuf_put_be32(buf, len);
466 	}
467 }
468 
469 
asn1_put_octet_string(struct wpabuf * buf,const struct wpabuf * val)470 void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val)
471 {
472 	wpabuf_put_u8(buf, ASN1_TAG_OCTETSTRING);
473 	asn1_put_len(buf, wpabuf_len(val));
474 	wpabuf_put_buf(buf, val);
475 }
476 
477 
asn1_put_oid(struct wpabuf * buf,const struct asn1_oid * oid)478 void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid)
479 {
480 	u8 *len;
481 	size_t i;
482 
483 	if (oid->len < 2)
484 		return;
485 	wpabuf_put_u8(buf, ASN1_TAG_OID);
486 	len = wpabuf_put(buf, 1);
487 	wpabuf_put_u8(buf, 40 * oid->oid[0] + oid->oid[1]);
488 	for (i = 2; i < oid->len; i++) {
489 		unsigned long val = oid->oid[i];
490 		u8 bytes[8];
491 		int idx = 0;
492 
493 		while (val) {
494 			bytes[idx] = (idx ? 0x80 : 0x00) | (val & 0x7f);
495 			idx++;
496 			val >>= 7;
497 		}
498 		if (idx == 0) {
499 			bytes[idx] = 0;
500 			idx = 1;
501 		}
502 		while (idx > 0) {
503 			idx--;
504 			wpabuf_put_u8(buf, bytes[idx]);
505 		}
506 	}
507 	*len = (u8 *) wpabuf_put(buf, 0) - len - 1;
508 }
509 
510 
asn1_put_hdr(struct wpabuf * buf,u8 class,int constructed,u8 tag,size_t len)511 void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag,
512 		  size_t len)
513 {
514 	wpabuf_put_u8(buf, class << 6 | (constructed ? 0x20 : 0x00) | tag);
515 	asn1_put_len(buf, len);
516 }
517 
518 
asn1_put_sequence(struct wpabuf * buf,const struct wpabuf * payload)519 void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload)
520 {
521 	asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SEQUENCE,
522 		     wpabuf_len(payload));
523 	wpabuf_put_buf(buf, payload);
524 }
525 
526 
asn1_put_set(struct wpabuf * buf,const struct wpabuf * payload)527 void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload)
528 {
529 	asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SET,
530 		     wpabuf_len(payload));
531 	wpabuf_put_buf(buf, payload);
532 }
533 
534 
asn1_put_utf8string(struct wpabuf * buf,const char * val)535 void asn1_put_utf8string(struct wpabuf *buf, const char *val)
536 {
537 	asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 0, ASN1_TAG_UTF8STRING,
538 		     os_strlen(val));
539 	wpabuf_put_str(buf, val);
540 }
541 
542 
asn1_build_alg_id(const struct asn1_oid * oid,const struct wpabuf * params)543 struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid,
544 				  const struct wpabuf *params)
545 {
546 	struct wpabuf *buf;
547 	size_t len;
548 
549 	/*
550 	 * AlgorithmIdentifier ::= SEQUENCE {
551 	 *    algorithm		OBJECT IDENTIFIER,
552 	 *    parameters	ANY DEFINED BY algorithm OPTIONAL}
553 	 */
554 
555 	len = 100;
556 	if (params)
557 		len += wpabuf_len(params);
558 	buf = wpabuf_alloc(len);
559 	if (!buf)
560 		return NULL;
561 	asn1_put_oid(buf, oid);
562 	if (params)
563 		wpabuf_put_buf(buf, params);
564 	return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
565 }
566 
567 
asn1_encaps(struct wpabuf * buf,u8 class,u8 tag)568 struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag)
569 {
570 	struct wpabuf *res;
571 
572 	if (!buf)
573 		return NULL;
574 	res = wpabuf_alloc(10 + wpabuf_len(buf));
575 	if (res) {
576 		asn1_put_hdr(res, class, 1, tag, wpabuf_len(buf));
577 		wpabuf_put_buf(res, buf);
578 	}
579 	wpabuf_clear_free(buf);
580 	return res;
581 }
582