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