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