Home | History | Annotate | Line # | Download | only in tls
      1 /*
      2  * ASN.1 DER parsing
      3  * Copyright (c) 2006-2014, Jouni Malinen <j (at) 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 
    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 
    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 	if (hdr->tag == ASN1_TAG_NULL && hdr->length != 0)
    133 		return 0;
    134 
    135 	/* Check for allowed primitive/constructed values */
    136 	if (hdr->constructed &&
    137 	    (hdr->tag == ASN1_TAG_BOOLEAN ||
    138 	     hdr->tag == ASN1_TAG_INTEGER ||
    139 	     hdr->tag == ASN1_TAG_NULL ||
    140 	     hdr->tag == ASN1_TAG_OID ||
    141 	     hdr->tag == ANS1_TAG_RELATIVE_OID ||
    142 	     hdr->tag == ASN1_TAG_REAL ||
    143 	     hdr->tag == ASN1_TAG_ENUMERATED ||
    144 	     hdr->tag == ASN1_TAG_BITSTRING ||
    145 	     hdr->tag == ASN1_TAG_OCTETSTRING ||
    146 	     hdr->tag == ASN1_TAG_NUMERICSTRING ||
    147 	     hdr->tag == ASN1_TAG_PRINTABLESTRING ||
    148 	     hdr->tag == ASN1_TAG_T61STRING ||
    149 	     hdr->tag == ASN1_TAG_VIDEOTEXSTRING ||
    150 	     hdr->tag == ASN1_TAG_VISIBLESTRING ||
    151 	     hdr->tag == ASN1_TAG_IA5STRING ||
    152 	     hdr->tag == ASN1_TAG_GRAPHICSTRING ||
    153 	     hdr->tag == ASN1_TAG_GENERALSTRING ||
    154 	     hdr->tag == ASN1_TAG_UNIVERSALSTRING ||
    155 	     hdr->tag == ASN1_TAG_UTF8STRING ||
    156 	     hdr->tag == ASN1_TAG_BMPSTRING ||
    157 	     hdr->tag == ASN1_TAG_CHARACTERSTRING ||
    158 	     hdr->tag == ASN1_TAG_UTCTIME ||
    159 	     hdr->tag == ASN1_TAG_GENERALIZEDTIME ||
    160 	     hdr->tag == ASN1_TAG_TIME))
    161 		return 0;
    162 	if (!hdr->constructed &&
    163 	    (hdr->tag == ASN1_TAG_SEQUENCE ||
    164 	     hdr->tag == ASN1_TAG_SET))
    165 		return 0;
    166 
    167 	return 1;
    168 }
    169 
    170 
    171 int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
    172 {
    173 	const u8 *pos, *end;
    174 	u8 tmp;
    175 
    176 	os_memset(hdr, 0, sizeof(*hdr));
    177 	pos = buf;
    178 	end = buf + len;
    179 
    180 	if (pos >= end) {
    181 		wpa_printf(MSG_DEBUG, "ASN.1: No room for Identifier");
    182 		return -1;
    183 	}
    184 	hdr->identifier = *pos++;
    185 	hdr->class = hdr->identifier >> 6;
    186 	hdr->constructed = !!(hdr->identifier & (1 << 5));
    187 
    188 	if ((hdr->identifier & 0x1f) == 0x1f) {
    189 		size_t ext_len = 0;
    190 
    191 		hdr->tag = 0;
    192 		if (pos == end || (*pos & 0x7f) == 0) {
    193 			wpa_printf(MSG_DEBUG,
    194 				   "ASN.1: Invalid extended tag (first octet has to be included with at least one nonzero bit for the tag value)");
    195 			return -1;
    196 		}
    197 		do {
    198 			if (pos >= end) {
    199 				wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
    200 					   "underflow");
    201 				return -1;
    202 			}
    203 			ext_len++;
    204 			tmp = *pos++;
    205 			wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: "
    206 				   "0x%02x", tmp);
    207 			hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
    208 		} while (tmp & 0x80);
    209 		wpa_printf(MSG_MSGDUMP, "ASN.1: Extended Tag: 0x%x (len=%zu)",
    210 			   hdr->tag, ext_len);
    211 		if ((hdr->class != ASN1_CLASS_PRIVATE && hdr->tag < 31) ||
    212 		    ext_len * 7 > sizeof(hdr->tag) * 8) {
    213 			wpa_printf(MSG_DEBUG,
    214 				   "ASN.1: Invalid or unsupported (too large) extended Tag: 0x%x (len=%zu)",
    215 				   hdr->tag, ext_len);
    216 			return -1;
    217 		}
    218 	} else
    219 		hdr->tag = hdr->identifier & 0x1f;
    220 
    221 	if (pos >= end) {
    222 		wpa_printf(MSG_DEBUG, "ASN.1: No room for Length");
    223 		return -1;
    224 	}
    225 	tmp = *pos++;
    226 	if (tmp & 0x80) {
    227 		if (tmp == 0xff) {
    228 			wpa_printf(MSG_DEBUG, "ASN.1: Reserved length "
    229 				   "value 0xff used");
    230 			return -1;
    231 		}
    232 		tmp &= 0x7f; /* number of subsequent octets */
    233 		hdr->length = 0;
    234 		if (tmp == 0 || pos == end || *pos == 0) {
    235 			wpa_printf(MSG_DEBUG,
    236 				   "ASN.1: Definite long form of the length does not start with a nonzero value");
    237 			return -1;
    238 		}
    239 		if (tmp > 4) {
    240 			wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
    241 			return -1;
    242 		}
    243 		while (tmp--) {
    244 			if (pos >= end) {
    245 				wpa_printf(MSG_DEBUG, "ASN.1: Length "
    246 					   "underflow");
    247 				return -1;
    248 			}
    249 			hdr->length = (hdr->length << 8) | *pos++;
    250 		}
    251 		if (hdr->length < 128) {
    252 			wpa_printf(MSG_DEBUG,
    253 				   "ASN.1: Definite long form of the length used with too short length");
    254 			return -1;
    255 		}
    256 	} else {
    257 		/* Short form - length 0..127 in one octet */
    258 		hdr->length = tmp;
    259 	}
    260 
    261 	if (end < pos || hdr->length > (unsigned int) (end - pos)) {
    262 		wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow");
    263 		return -1;
    264 	}
    265 
    266 	hdr->payload = pos;
    267 
    268 	if (!asn1_valid_der(hdr)) {
    269 		asn1_print_hdr(hdr, "ASN.1: Invalid DER encoding: ");
    270 		return -1;
    271 	}
    272 	return 0;
    273 }
    274 
    275 
    276 void asn1_print_hdr(const struct asn1_hdr *hdr, const char *title)
    277 {
    278 	wpa_printf(MSG_DEBUG, "%sclass %d constructed %d tag 0x%x",
    279 		   title, hdr->class, hdr->constructed, hdr->tag);
    280 }
    281 
    282 
    283 void asn1_unexpected(const struct asn1_hdr *hdr, const char *title)
    284 {
    285 	wpa_printf(MSG_DEBUG, "%s - found class %d constructed %d tag 0x%x",
    286 		   title, hdr->class, hdr->constructed, hdr->tag);
    287 }
    288 
    289 
    290 int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid)
    291 {
    292 	const u8 *pos, *end;
    293 	unsigned long val;
    294 	u8 tmp;
    295 
    296 	os_memset(oid, 0, sizeof(*oid));
    297 
    298 	pos = buf;
    299 	end = buf + len;
    300 
    301 	while (pos < end) {
    302 		val = 0;
    303 
    304 		do {
    305 			if (pos >= end)
    306 				return -1;
    307 			tmp = *pos++;
    308 			val = (val << 7) | (tmp & 0x7f);
    309 		} while (tmp & 0x80);
    310 
    311 		if (oid->len >= ASN1_MAX_OID_LEN) {
    312 			wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value");
    313 			return -1;
    314 		}
    315 		if (oid->len == 0) {
    316 			/*
    317 			 * The first octet encodes the first two object
    318 			 * identifier components in (X*40) + Y formula.
    319 			 * X = 0..2.
    320 			 */
    321 			oid->oid[0] = val / 40;
    322 			if (oid->oid[0] > 2)
    323 				oid->oid[0] = 2;
    324 			oid->oid[1] = val - oid->oid[0] * 40;
    325 			oid->len = 2;
    326 		} else
    327 			oid->oid[oid->len++] = val;
    328 	}
    329 
    330 	return 0;
    331 }
    332 
    333 
    334 int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
    335 		 const u8 **next)
    336 {
    337 	struct asn1_hdr hdr;
    338 
    339 	if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0 ||
    340 	    !asn1_is_oid(&hdr)) {
    341 		asn1_unexpected(&hdr, "ASN.1: Expected OID");
    342 		return -1;
    343 	}
    344 
    345 	*next = hdr.payload + hdr.length;
    346 
    347 	return asn1_parse_oid(hdr.payload, hdr.length, oid);
    348 }
    349 
    350 
    351 void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len)
    352 {
    353 	char *pos = buf;
    354 	size_t i;
    355 	int ret;
    356 
    357 	if (len == 0)
    358 		return;
    359 
    360 	buf[0] = '\0';
    361 
    362 	for (i = 0; i < oid->len; i++) {
    363 		ret = os_snprintf(pos, buf + len - pos,
    364 				  "%s%lu",
    365 				  i == 0 ? "" : ".", oid->oid[i]);
    366 		if (os_snprintf_error(buf + len - pos, ret))
    367 			break;
    368 		pos += ret;
    369 	}
    370 	buf[len - 1] = '\0';
    371 }
    372 
    373 
    374 static u8 rotate_bits(u8 octet)
    375 {
    376 	int i;
    377 	u8 res;
    378 
    379 	res = 0;
    380 	for (i = 0; i < 8; i++) {
    381 		res <<= 1;
    382 		if (octet & 1)
    383 			res |= 1;
    384 		octet >>= 1;
    385 	}
    386 
    387 	return res;
    388 }
    389 
    390 
    391 unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
    392 {
    393 	unsigned long val = 0;
    394 	const u8 *pos = buf;
    395 
    396 	/* BER requires that unused bits are zero, so we can ignore the number
    397 	 * of unused bits */
    398 	pos++;
    399 
    400 	if (len >= 2)
    401 		val |= rotate_bits(*pos++);
    402 	if (len >= 3)
    403 		val |= ((unsigned long) rotate_bits(*pos++)) << 8;
    404 	if (len >= 4)
    405 		val |= ((unsigned long) rotate_bits(*pos++)) << 16;
    406 	if (len >= 5)
    407 		val |= ((unsigned long) rotate_bits(*pos++)) << 24;
    408 	if (len >= 6)
    409 		wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored "
    410 			   "(BIT STRING length %lu)",
    411 			   __func__, (unsigned long) len);
    412 
    413 	return val;
    414 }
    415 
    416 
    417 int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b)
    418 {
    419 	size_t i;
    420 
    421 	if (a->len != b->len)
    422 		return 0;
    423 
    424 	for (i = 0; i < a->len; i++) {
    425 		if (a->oid[i] != b->oid[i])
    426 			return 0;
    427 	}
    428 
    429 	return 1;
    430 }
    431 
    432 
    433 int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next)
    434 {
    435 	struct asn1_hdr hdr;
    436 	size_t left;
    437 	const u8 *pos;
    438 	int value;
    439 
    440 	if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0 ||
    441 	    !asn1_is_integer(&hdr)) {
    442 		asn1_unexpected(&hdr, "ASN.1: Expected INTEGER");
    443 		return -1;
    444 	}
    445 
    446 	*next = hdr.payload + hdr.length;
    447 	pos = hdr.payload;
    448 	left = hdr.length;
    449 	if (left > sizeof(value)) {
    450 		wpa_printf(MSG_DEBUG, "ASN.1: Too large INTEGER (len %u)",
    451 			   hdr.length);
    452 		return -1;
    453 	}
    454 	value = 0;
    455 	while (left) {
    456 		value <<= 8;
    457 		value |= *pos++;
    458 		left--;
    459 	}
    460 
    461 	*integer = value;
    462 	return 0;
    463 }
    464 
    465 
    466 int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr,
    467 		      const u8 **next)
    468 {
    469 	if (asn1_get_next(buf, len, hdr) < 0 || !asn1_is_sequence(hdr)) {
    470 		asn1_unexpected(hdr, "ASN.1: Expected SEQUENCE");
    471 		return -1;
    472 	}
    473 
    474 	if (next)
    475 		*next = hdr->payload + hdr->length;
    476 	return 0;
    477 }
    478 
    479 
    480 int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid,
    481 		    const u8 **params, size_t *params_len, const u8 **next)
    482 {
    483 	const u8 *pos = buf, *end = buf + len;
    484 	struct asn1_hdr hdr;
    485 
    486 	/*
    487 	 * AlgorithmIdentifier ::= SEQUENCE {
    488 	 *     algorithm            OBJECT IDENTIFIER,
    489 	 *     parameters           ANY DEFINED BY algorithm OPTIONAL}
    490 	 */
    491 	if (asn1_get_sequence(pos, end - pos, &hdr, next) < 0 ||
    492 	    asn1_get_oid(hdr.payload, hdr.length, oid, &pos) < 0)
    493 		return -1;
    494 
    495 	if (params && params_len) {
    496 		*params = pos;
    497 		*params_len = hdr.payload + hdr.length - pos;
    498 	}
    499 
    500 	return 0;
    501 }
    502 
    503 
    504 void asn1_put_integer(struct wpabuf *buf, int val)
    505 {
    506 	u8 bin[4];
    507 	int zeros;
    508 
    509 	WPA_PUT_BE32(bin, val);
    510 	zeros = 0;
    511 	while (zeros < 3 && bin[zeros] == 0)
    512 		zeros++;
    513 	wpabuf_put_u8(buf, ASN1_TAG_INTEGER);
    514 	wpabuf_put_u8(buf, 4 - zeros);
    515 	wpabuf_put_data(buf, &bin[zeros], 4 - zeros);
    516 }
    517 
    518 
    519 static void asn1_put_len(struct wpabuf *buf, size_t len)
    520 {
    521 	if (len <= 0x7f) {
    522 		wpabuf_put_u8(buf, len);
    523 	} else if (len <= 0xff) {
    524 		wpabuf_put_u8(buf, 0x80 | 1);
    525 		wpabuf_put_u8(buf, len);
    526 	} else if (len <= 0xffff) {
    527 		wpabuf_put_u8(buf, 0x80 | 2);
    528 		wpabuf_put_be16(buf, len);
    529 	} else if (len <= 0xffffff) {
    530 		wpabuf_put_u8(buf, 0x80 | 3);
    531 		wpabuf_put_be24(buf, len);
    532 	} else {
    533 		wpabuf_put_u8(buf, 0x80 | 4);
    534 		wpabuf_put_be32(buf, len);
    535 	}
    536 }
    537 
    538 
    539 void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val)
    540 {
    541 	wpabuf_put_u8(buf, ASN1_TAG_OCTETSTRING);
    542 	asn1_put_len(buf, wpabuf_len(val));
    543 	wpabuf_put_buf(buf, val);
    544 }
    545 
    546 
    547 void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid)
    548 {
    549 	u8 *len;
    550 	size_t i;
    551 
    552 	if (oid->len < 2)
    553 		return;
    554 	wpabuf_put_u8(buf, ASN1_TAG_OID);
    555 	len = wpabuf_put(buf, 1);
    556 	wpabuf_put_u8(buf, 40 * oid->oid[0] + oid->oid[1]);
    557 	for (i = 2; i < oid->len; i++) {
    558 		unsigned long val = oid->oid[i];
    559 		u8 bytes[8];
    560 		int idx = 0;
    561 
    562 		while (val) {
    563 			bytes[idx] = (idx ? 0x80 : 0x00) | (val & 0x7f);
    564 			idx++;
    565 			val >>= 7;
    566 		}
    567 		if (idx == 0) {
    568 			bytes[idx] = 0;
    569 			idx = 1;
    570 		}
    571 		while (idx > 0) {
    572 			idx--;
    573 			wpabuf_put_u8(buf, bytes[idx]);
    574 		}
    575 	}
    576 	*len = (u8 *) wpabuf_put(buf, 0) - len - 1;
    577 }
    578 
    579 
    580 void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag,
    581 		  size_t len)
    582 {
    583 	wpabuf_put_u8(buf, class << 6 | (constructed ? 0x20 : 0x00) | tag);
    584 	asn1_put_len(buf, len);
    585 }
    586 
    587 
    588 void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload)
    589 {
    590 	asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SEQUENCE,
    591 		     wpabuf_len(payload));
    592 	wpabuf_put_buf(buf, payload);
    593 }
    594 
    595 
    596 void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload)
    597 {
    598 	asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SET,
    599 		     wpabuf_len(payload));
    600 	wpabuf_put_buf(buf, payload);
    601 }
    602 
    603 
    604 void asn1_put_utf8string(struct wpabuf *buf, const char *val)
    605 {
    606 	asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 0, ASN1_TAG_UTF8STRING,
    607 		     os_strlen(val));
    608 	wpabuf_put_str(buf, val);
    609 }
    610 
    611 
    612 struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid,
    613 				  const struct wpabuf *params)
    614 {
    615 	struct wpabuf *buf;
    616 	size_t len;
    617 
    618 	/*
    619 	 * AlgorithmIdentifier ::= SEQUENCE {
    620 	 *    algorithm		OBJECT IDENTIFIER,
    621 	 *    parameters	ANY DEFINED BY algorithm OPTIONAL}
    622 	 */
    623 
    624 	len = 100;
    625 	if (params)
    626 		len += wpabuf_len(params);
    627 	buf = wpabuf_alloc(len);
    628 	if (!buf)
    629 		return NULL;
    630 	asn1_put_oid(buf, oid);
    631 	if (params)
    632 		wpabuf_put_buf(buf, params);
    633 	return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
    634 }
    635 
    636 
    637 struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag)
    638 {
    639 	struct wpabuf *res;
    640 
    641 	if (!buf)
    642 		return NULL;
    643 	res = wpabuf_alloc(10 + wpabuf_len(buf));
    644 	if (res) {
    645 		asn1_put_hdr(res, class, 1, tag, wpabuf_len(buf));
    646 		wpabuf_put_buf(res, buf);
    647 	}
    648 	wpabuf_clear_free(buf);
    649 	return res;
    650 }
    651