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