18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ASN.1 DER parsing
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "asn1.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos, *end;
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 tmp;
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(hdr, 0, sizeof(*hdr));
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = buf;
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = buf + len;
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->identifier = *pos++;
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->class = hdr->identifier >> 6;
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->constructed = !!(hdr->identifier & (1 << 5));
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((hdr->identifier & 0x1f) == 0x1f) {
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hdr->tag = 0;
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		do {
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (pos >= end) {
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "underflow");
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tmp = *pos++;
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: "
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "0x%02x", tmp);
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} while (tmp & 0x80);
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hdr->tag = hdr->identifier & 0x1f;
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tmp = *pos++;
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tmp & 0x80) {
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tmp == 0xff) {
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "ASN.1: Reserved length "
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "value 0xff used");
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tmp &= 0x7f; /* number of subsequent octets */
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hdr->length = 0;
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tmp > 4) {
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		while (tmp--) {
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (pos >= end) {
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "ASN.1: Length "
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "underflow");
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			hdr->length = (hdr->length << 8) | *pos++;
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Short form - length 0..127 in one octet */
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hdr->length = tmp;
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (end < pos || hdr->length > (unsigned int) (end - pos)) {
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow");
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->payload = pos;
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid)
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos, *end;
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned long val;
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 tmp;
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(oid, 0, sizeof(*oid));
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = buf;
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = buf + len;
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos < end) {
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = 0;
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		do {
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (pos >= end)
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tmp = *pos++;
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			val = (val << 7) | (tmp & 0x7f);
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} while (tmp & 0x80);
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (oid->len >= ASN1_MAX_OID_LEN) {
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value");
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (oid->len == 0) {
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/*
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * The first octet encodes the first two object
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * identifier components in (X*40) + Y formula.
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * X = 0..2.
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 */
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			oid->oid[0] = val / 40;
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (oid->oid[0] > 2)
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				oid->oid[0] = 2;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			oid->oid[1] = val - oid->oid[0] * 40;
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			oid->len = 2;
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			oid->oid[oid->len++] = val;
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 const u8 **next)
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct asn1_hdr hdr;
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) {
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d "
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "tag 0x%x", hdr.class, hdr.tag);
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*next = hdr.payload + hdr.length;
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return asn1_parse_oid(hdr.payload, hdr.length, oid);
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *pos = buf;
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len == 0)
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf[0] = '\0';
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < oid->len; i++) {
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = os_snprintf(pos, buf + len - pos,
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  "%s%lu",
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  i == 0 ? "" : ".", oid->oid[i]);
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0 || ret >= buf + len - pos)
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += ret;
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf[len - 1] = '\0';
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 rotate_bits(u8 octet)
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 res;
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = 0;
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < 8; i++) {
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		res <<= 1;
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (octet & 1)
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			res |= 1;
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		octet >>= 1;
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return res;
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned long val = 0;
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pos = buf;
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* BER requires that unused bits are zero, so we can ignore the number
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * of unused bits */
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos++;
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len >= 2)
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val |= rotate_bits(*pos++);
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len >= 3)
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val |= ((unsigned long) rotate_bits(*pos++)) << 8;
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len >= 4)
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val |= ((unsigned long) rotate_bits(*pos++)) << 16;
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len >= 5)
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val |= ((unsigned long) rotate_bits(*pos++)) << 24;
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len >= 6)
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored "
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(BIT STRING length %lu)",
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__, (unsigned long) len);
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return val;
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
207