asn1.c revision 351611
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 "asn1.h"
13
14struct asn1_oid asn1_sha1_oid = {
15	.oid = { 1, 3, 14, 3, 2, 26 },
16	.len = 6
17};
18
19struct asn1_oid asn1_sha256_oid = {
20	.oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 },
21	.len = 9
22};
23
24
25static int asn1_valid_der_boolean(struct asn1_hdr *hdr)
26{
27	/* Enforce DER requirements for a single way of encoding a BOOLEAN */
28	if (hdr->length != 1) {
29		wpa_printf(MSG_DEBUG, "ASN.1: Unexpected BOOLEAN length (%u)",
30			   hdr->length);
31		return 0;
32	}
33
34	if (hdr->payload[0] != 0 && hdr->payload[0] != 0xff) {
35		wpa_printf(MSG_DEBUG,
36			   "ASN.1: Invalid BOOLEAN value 0x%x (DER requires 0 or 0xff)",
37			   hdr->payload[0]);
38		return 0;
39	}
40
41	return 1;
42}
43
44
45static int asn1_valid_der(struct asn1_hdr *hdr)
46{
47	if (hdr->class != ASN1_CLASS_UNIVERSAL)
48		return 1;
49	if (hdr->tag == ASN1_TAG_BOOLEAN && !asn1_valid_der_boolean(hdr))
50		return 0;
51	return 1;
52}
53
54
55int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
56{
57	const u8 *pos, *end;
58	u8 tmp;
59
60	os_memset(hdr, 0, sizeof(*hdr));
61	pos = buf;
62	end = buf + len;
63
64	if (pos >= end) {
65		wpa_printf(MSG_DEBUG, "ASN.1: No room for Identifier");
66		return -1;
67	}
68	hdr->identifier = *pos++;
69	hdr->class = hdr->identifier >> 6;
70	hdr->constructed = !!(hdr->identifier & (1 << 5));
71
72	if ((hdr->identifier & 0x1f) == 0x1f) {
73		hdr->tag = 0;
74		do {
75			if (pos >= end) {
76				wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
77					   "underflow");
78				return -1;
79			}
80			tmp = *pos++;
81			wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: "
82				   "0x%02x", tmp);
83			hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
84		} while (tmp & 0x80);
85	} else
86		hdr->tag = hdr->identifier & 0x1f;
87
88	if (pos >= end) {
89		wpa_printf(MSG_DEBUG, "ASN.1: No room for Length");
90		return -1;
91	}
92	tmp = *pos++;
93	if (tmp & 0x80) {
94		if (tmp == 0xff) {
95			wpa_printf(MSG_DEBUG, "ASN.1: Reserved length "
96				   "value 0xff used");
97			return -1;
98		}
99		tmp &= 0x7f; /* number of subsequent octets */
100		hdr->length = 0;
101		if (tmp > 4) {
102			wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
103			return -1;
104		}
105		while (tmp--) {
106			if (pos >= end) {
107				wpa_printf(MSG_DEBUG, "ASN.1: Length "
108					   "underflow");
109				return -1;
110			}
111			hdr->length = (hdr->length << 8) | *pos++;
112		}
113	} else {
114		/* Short form - length 0..127 in one octet */
115		hdr->length = tmp;
116	}
117
118	if (end < pos || hdr->length > (unsigned int) (end - pos)) {
119		wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow");
120		return -1;
121	}
122
123	hdr->payload = pos;
124
125	return asn1_valid_der(hdr) ? 0 : -1;
126}
127
128
129int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid)
130{
131	const u8 *pos, *end;
132	unsigned long val;
133	u8 tmp;
134
135	os_memset(oid, 0, sizeof(*oid));
136
137	pos = buf;
138	end = buf + len;
139
140	while (pos < end) {
141		val = 0;
142
143		do {
144			if (pos >= end)
145				return -1;
146			tmp = *pos++;
147			val = (val << 7) | (tmp & 0x7f);
148		} while (tmp & 0x80);
149
150		if (oid->len >= ASN1_MAX_OID_LEN) {
151			wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value");
152			return -1;
153		}
154		if (oid->len == 0) {
155			/*
156			 * The first octet encodes the first two object
157			 * identifier components in (X*40) + Y formula.
158			 * X = 0..2.
159			 */
160			oid->oid[0] = val / 40;
161			if (oid->oid[0] > 2)
162				oid->oid[0] = 2;
163			oid->oid[1] = val - oid->oid[0] * 40;
164			oid->len = 2;
165		} else
166			oid->oid[oid->len++] = val;
167	}
168
169	return 0;
170}
171
172
173int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
174		 const u8 **next)
175{
176	struct asn1_hdr hdr;
177
178	if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
179		return -1;
180
181	if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) {
182		wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d "
183			   "tag 0x%x", hdr.class, hdr.tag);
184		return -1;
185	}
186
187	*next = hdr.payload + hdr.length;
188
189	return asn1_parse_oid(hdr.payload, hdr.length, oid);
190}
191
192
193void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len)
194{
195	char *pos = buf;
196	size_t i;
197	int ret;
198
199	if (len == 0)
200		return;
201
202	buf[0] = '\0';
203
204	for (i = 0; i < oid->len; i++) {
205		ret = os_snprintf(pos, buf + len - pos,
206				  "%s%lu",
207				  i == 0 ? "" : ".", oid->oid[i]);
208		if (os_snprintf_error(buf + len - pos, ret))
209			break;
210		pos += ret;
211	}
212	buf[len - 1] = '\0';
213}
214
215
216static u8 rotate_bits(u8 octet)
217{
218	int i;
219	u8 res;
220
221	res = 0;
222	for (i = 0; i < 8; i++) {
223		res <<= 1;
224		if (octet & 1)
225			res |= 1;
226		octet >>= 1;
227	}
228
229	return res;
230}
231
232
233unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
234{
235	unsigned long val = 0;
236	const u8 *pos = buf;
237
238	/* BER requires that unused bits are zero, so we can ignore the number
239	 * of unused bits */
240	pos++;
241
242	if (len >= 2)
243		val |= rotate_bits(*pos++);
244	if (len >= 3)
245		val |= ((unsigned long) rotate_bits(*pos++)) << 8;
246	if (len >= 4)
247		val |= ((unsigned long) rotate_bits(*pos++)) << 16;
248	if (len >= 5)
249		val |= ((unsigned long) rotate_bits(*pos++)) << 24;
250	if (len >= 6)
251		wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored "
252			   "(BIT STRING length %lu)",
253			   __func__, (unsigned long) len);
254
255	return val;
256}
257
258
259int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b)
260{
261	size_t i;
262
263	if (a->len != b->len)
264		return 0;
265
266	for (i = 0; i < a->len; i++) {
267		if (a->oid[i] != b->oid[i])
268			return 0;
269	}
270
271	return 1;
272}
273