/src/hostap/src/tls/asn1.c
Line | Count | Source (jump to first uncovered line) |
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 "utils/wpabuf.h" |
13 | | #include "asn1.h" |
14 | | |
15 | | const struct asn1_oid asn1_sha1_oid = { |
16 | | .oid = { 1, 3, 14, 3, 2, 26 }, |
17 | | .len = 6 |
18 | | }; |
19 | | |
20 | | const struct asn1_oid asn1_sha256_oid = { |
21 | | .oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 }, |
22 | | .len = 9 |
23 | | }; |
24 | | |
25 | | const struct asn1_oid asn1_ec_public_key_oid = { |
26 | | .oid = { 1, 2, 840, 10045, 2, 1 }, |
27 | | .len = 6 |
28 | | }; |
29 | | |
30 | | const struct asn1_oid asn1_prime256v1_oid = { |
31 | | .oid = { 1, 2, 840, 10045, 3, 1, 7 }, |
32 | | .len = 7 |
33 | | }; |
34 | | |
35 | | const struct asn1_oid asn1_secp384r1_oid = { |
36 | | .oid = { 1, 3, 132, 0, 34 }, |
37 | | .len = 5 |
38 | | }; |
39 | | |
40 | | const struct asn1_oid asn1_secp521r1_oid = { |
41 | | .oid = { 1, 3, 132, 0, 35 }, |
42 | | .len = 5 |
43 | | }; |
44 | | |
45 | | const struct asn1_oid asn1_brainpoolP256r1_oid = { |
46 | | .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 7 }, |
47 | | .len = 10 |
48 | | }; |
49 | | |
50 | | const struct asn1_oid asn1_brainpoolP384r1_oid = { |
51 | | .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 11 }, |
52 | | .len = 10 |
53 | | }; |
54 | | |
55 | | const struct asn1_oid asn1_brainpoolP512r1_oid = { |
56 | | .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 13 }, |
57 | | .len = 10 |
58 | | }; |
59 | | |
60 | | const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid = { |
61 | | .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 22 }, |
62 | | .len = 9 |
63 | | }; |
64 | | |
65 | | const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid = { |
66 | | .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 23 }, |
67 | | .len = 9 |
68 | | }; |
69 | | |
70 | | const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid = { |
71 | | .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 24 }, |
72 | | .len = 9 |
73 | | }; |
74 | | |
75 | | const struct asn1_oid asn1_pbkdf2_oid = { |
76 | | .oid = { 1, 2, 840, 113549, 1, 5, 12 }, |
77 | | .len = 7 |
78 | | }; |
79 | | |
80 | | const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid = { |
81 | | .oid = { 1, 2, 840, 113549, 2, 9 }, |
82 | | .len = 6 |
83 | | }; |
84 | | |
85 | | const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid = { |
86 | | .oid = { 1, 2, 840, 113549, 2, 10 }, |
87 | | .len = 6 |
88 | | }; |
89 | | |
90 | | const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid = { |
91 | | .oid = { 1, 2, 840, 113549, 2, 11 }, |
92 | | .len = 6 |
93 | | }; |
94 | | |
95 | | const struct asn1_oid asn1_dpp_config_params_oid = { |
96 | | .oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 1 }, |
97 | | .len = 10 |
98 | | }; |
99 | | |
100 | | const struct asn1_oid asn1_dpp_asymmetric_key_package_oid = { |
101 | | .oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 2 }, |
102 | | .len = 10 |
103 | | }; |
104 | | |
105 | | |
106 | | static int asn1_valid_der_boolean(struct asn1_hdr *hdr) |
107 | 0 | { |
108 | | /* Enforce DER requirements for a single way of encoding a BOOLEAN */ |
109 | 0 | if (hdr->length != 1) { |
110 | 0 | wpa_printf(MSG_DEBUG, "ASN.1: Unexpected BOOLEAN length (%u)", |
111 | 0 | hdr->length); |
112 | 0 | return 0; |
113 | 0 | } |
114 | | |
115 | 0 | if (hdr->payload[0] != 0 && hdr->payload[0] != 0xff) { |
116 | 0 | wpa_printf(MSG_DEBUG, |
117 | 0 | "ASN.1: Invalid BOOLEAN value 0x%x (DER requires 0 or 0xff)", |
118 | 0 | hdr->payload[0]); |
119 | 0 | return 0; |
120 | 0 | } |
121 | | |
122 | 0 | return 1; |
123 | 0 | } |
124 | | |
125 | | |
126 | | static int asn1_valid_der(struct asn1_hdr *hdr) |
127 | 0 | { |
128 | 0 | if (hdr->class != ASN1_CLASS_UNIVERSAL) |
129 | 0 | return 1; |
130 | 0 | if (hdr->tag == ASN1_TAG_BOOLEAN && !asn1_valid_der_boolean(hdr)) |
131 | 0 | return 0; |
132 | 0 | if (hdr->tag == ASN1_TAG_NULL && hdr->length != 0) |
133 | 0 | return 0; |
134 | | |
135 | | /* Check for allowed primitive/constructed values */ |
136 | 0 | if (hdr->constructed && |
137 | 0 | (hdr->tag == ASN1_TAG_BOOLEAN || |
138 | 0 | hdr->tag == ASN1_TAG_INTEGER || |
139 | 0 | hdr->tag == ASN1_TAG_NULL || |
140 | 0 | hdr->tag == ASN1_TAG_OID || |
141 | 0 | hdr->tag == ANS1_TAG_RELATIVE_OID || |
142 | 0 | hdr->tag == ASN1_TAG_REAL || |
143 | 0 | hdr->tag == ASN1_TAG_ENUMERATED || |
144 | 0 | hdr->tag == ASN1_TAG_BITSTRING || |
145 | 0 | hdr->tag == ASN1_TAG_OCTETSTRING || |
146 | 0 | hdr->tag == ASN1_TAG_NUMERICSTRING || |
147 | 0 | hdr->tag == ASN1_TAG_PRINTABLESTRING || |
148 | 0 | hdr->tag == ASN1_TAG_T61STRING || |
149 | 0 | hdr->tag == ASN1_TAG_VIDEOTEXSTRING || |
150 | 0 | hdr->tag == ASN1_TAG_VISIBLESTRING || |
151 | 0 | hdr->tag == ASN1_TAG_IA5STRING || |
152 | 0 | hdr->tag == ASN1_TAG_GRAPHICSTRING || |
153 | 0 | hdr->tag == ASN1_TAG_GENERALSTRING || |
154 | 0 | hdr->tag == ASN1_TAG_UNIVERSALSTRING || |
155 | 0 | hdr->tag == ASN1_TAG_UTF8STRING || |
156 | 0 | hdr->tag == ASN1_TAG_BMPSTRING || |
157 | 0 | hdr->tag == ASN1_TAG_CHARACTERSTRING || |
158 | 0 | hdr->tag == ASN1_TAG_UTCTIME || |
159 | 0 | hdr->tag == ASN1_TAG_GENERALIZEDTIME || |
160 | 0 | hdr->tag == ASN1_TAG_TIME)) |
161 | 0 | return 0; |
162 | 0 | if (!hdr->constructed && |
163 | 0 | (hdr->tag == ASN1_TAG_SEQUENCE || |
164 | 0 | hdr->tag == ASN1_TAG_SET)) |
165 | 0 | return 0; |
166 | | |
167 | 0 | return 1; |
168 | 0 | } |
169 | | |
170 | | |
171 | | int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr) |
172 | 0 | { |
173 | 0 | const u8 *pos, *end; |
174 | 0 | u8 tmp; |
175 | |
|
176 | 0 | os_memset(hdr, 0, sizeof(*hdr)); |
177 | 0 | pos = buf; |
178 | 0 | end = buf + len; |
179 | |
|
180 | 0 | if (pos >= end) { |
181 | 0 | wpa_printf(MSG_DEBUG, "ASN.1: No room for Identifier"); |
182 | 0 | return -1; |
183 | 0 | } |
184 | 0 | hdr->identifier = *pos++; |
185 | 0 | hdr->class = hdr->identifier >> 6; |
186 | 0 | hdr->constructed = !!(hdr->identifier & (1 << 5)); |
187 | |
|
188 | 0 | if ((hdr->identifier & 0x1f) == 0x1f) { |
189 | 0 | size_t ext_len = 0; |
190 | |
|
191 | 0 | hdr->tag = 0; |
192 | 0 | if (pos == end || (*pos & 0x7f) == 0) { |
193 | 0 | wpa_printf(MSG_DEBUG, |
194 | 0 | "ASN.1: Invalid extended tag (first octet has to be included with at least one nonzero bit for the tag value)"); |
195 | 0 | return -1; |
196 | 0 | } |
197 | 0 | do { |
198 | 0 | if (pos >= end) { |
199 | 0 | wpa_printf(MSG_DEBUG, "ASN.1: Identifier " |
200 | 0 | "underflow"); |
201 | 0 | return -1; |
202 | 0 | } |
203 | 0 | ext_len++; |
204 | 0 | tmp = *pos++; |
205 | 0 | wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: " |
206 | 0 | "0x%02x", tmp); |
207 | 0 | hdr->tag = (hdr->tag << 7) | (tmp & 0x7f); |
208 | 0 | } while (tmp & 0x80); |
209 | 0 | wpa_printf(MSG_MSGDUMP, "ASN.1: Extended Tag: 0x%x (len=%zu)", |
210 | 0 | hdr->tag, ext_len); |
211 | 0 | if ((hdr->class != ASN1_CLASS_PRIVATE && hdr->tag < 31) || |
212 | 0 | ext_len * 7 > sizeof(hdr->tag) * 8) { |
213 | 0 | wpa_printf(MSG_DEBUG, |
214 | 0 | "ASN.1: Invalid or unsupported (too large) extended Tag: 0x%x (len=%zu)", |
215 | 0 | hdr->tag, ext_len); |
216 | 0 | return -1; |
217 | 0 | } |
218 | 0 | } else |
219 | 0 | hdr->tag = hdr->identifier & 0x1f; |
220 | | |
221 | 0 | if (pos >= end) { |
222 | 0 | wpa_printf(MSG_DEBUG, "ASN.1: No room for Length"); |
223 | 0 | return -1; |
224 | 0 | } |
225 | 0 | tmp = *pos++; |
226 | 0 | if (tmp & 0x80) { |
227 | 0 | if (tmp == 0xff) { |
228 | 0 | wpa_printf(MSG_DEBUG, "ASN.1: Reserved length " |
229 | 0 | "value 0xff used"); |
230 | 0 | return -1; |
231 | 0 | } |
232 | 0 | tmp &= 0x7f; /* number of subsequent octets */ |
233 | 0 | hdr->length = 0; |
234 | 0 | if (tmp == 0 || pos == end || *pos == 0) { |
235 | 0 | wpa_printf(MSG_DEBUG, |
236 | 0 | "ASN.1: Definite long form of the length does not start with a nonzero value"); |
237 | 0 | return -1; |
238 | 0 | } |
239 | 0 | if (tmp > 4) { |
240 | 0 | wpa_printf(MSG_DEBUG, "ASN.1: Too long length field"); |
241 | 0 | return -1; |
242 | 0 | } |
243 | 0 | while (tmp--) { |
244 | 0 | if (pos >= end) { |
245 | 0 | wpa_printf(MSG_DEBUG, "ASN.1: Length " |
246 | 0 | "underflow"); |
247 | 0 | return -1; |
248 | 0 | } |
249 | 0 | hdr->length = (hdr->length << 8) | *pos++; |
250 | 0 | } |
251 | 0 | if (hdr->length < 128) { |
252 | 0 | wpa_printf(MSG_DEBUG, |
253 | 0 | "ASN.1: Definite long form of the length used with too short length"); |
254 | 0 | return -1; |
255 | 0 | } |
256 | 0 | } else { |
257 | | /* Short form - length 0..127 in one octet */ |
258 | 0 | hdr->length = tmp; |
259 | 0 | } |
260 | | |
261 | 0 | if (end < pos || hdr->length > (unsigned int) (end - pos)) { |
262 | 0 | wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow"); |
263 | 0 | return -1; |
264 | 0 | } |
265 | | |
266 | 0 | hdr->payload = pos; |
267 | |
|
268 | 0 | if (!asn1_valid_der(hdr)) { |
269 | 0 | asn1_print_hdr(hdr, "ASN.1: Invalid DER encoding: "); |
270 | 0 | return -1; |
271 | 0 | } |
272 | 0 | return 0; |
273 | 0 | } |
274 | | |
275 | | |
276 | | void asn1_print_hdr(const struct asn1_hdr *hdr, const char *title) |
277 | 0 | { |
278 | 0 | wpa_printf(MSG_DEBUG, "%sclass %d constructed %d tag 0x%x", |
279 | 0 | title, hdr->class, hdr->constructed, hdr->tag); |
280 | 0 | } |
281 | | |
282 | | |
283 | | void asn1_unexpected(const struct asn1_hdr *hdr, const char *title) |
284 | 0 | { |
285 | 0 | wpa_printf(MSG_DEBUG, "%s - found class %d constructed %d tag 0x%x", |
286 | 0 | title, hdr->class, hdr->constructed, hdr->tag); |
287 | 0 | } |
288 | | |
289 | | |
290 | | int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid) |
291 | 0 | { |
292 | 0 | const u8 *pos, *end; |
293 | 0 | unsigned long val; |
294 | 0 | u8 tmp; |
295 | |
|
296 | 0 | os_memset(oid, 0, sizeof(*oid)); |
297 | |
|
298 | 0 | pos = buf; |
299 | 0 | end = buf + len; |
300 | |
|
301 | 0 | while (pos < end) { |
302 | 0 | val = 0; |
303 | |
|
304 | 0 | do { |
305 | 0 | if (pos >= end) |
306 | 0 | return -1; |
307 | 0 | tmp = *pos++; |
308 | 0 | val = (val << 7) | (tmp & 0x7f); |
309 | 0 | } while (tmp & 0x80); |
310 | | |
311 | 0 | if (oid->len >= ASN1_MAX_OID_LEN) { |
312 | 0 | wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value"); |
313 | 0 | return -1; |
314 | 0 | } |
315 | 0 | if (oid->len == 0) { |
316 | | /* |
317 | | * The first octet encodes the first two object |
318 | | * identifier components in (X*40) + Y formula. |
319 | | * X = 0..2. |
320 | | */ |
321 | 0 | oid->oid[0] = val / 40; |
322 | 0 | if (oid->oid[0] > 2) |
323 | 0 | oid->oid[0] = 2; |
324 | 0 | oid->oid[1] = val - oid->oid[0] * 40; |
325 | 0 | oid->len = 2; |
326 | 0 | } else |
327 | 0 | oid->oid[oid->len++] = val; |
328 | 0 | } |
329 | | |
330 | 0 | return 0; |
331 | 0 | } |
332 | | |
333 | | |
334 | | int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, |
335 | | const u8 **next) |
336 | 0 | { |
337 | 0 | struct asn1_hdr hdr; |
338 | |
|
339 | 0 | if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0 || |
340 | 0 | !asn1_is_oid(&hdr)) { |
341 | 0 | asn1_unexpected(&hdr, "ASN.1: Expected OID"); |
342 | 0 | return -1; |
343 | 0 | } |
344 | | |
345 | 0 | *next = hdr.payload + hdr.length; |
346 | |
|
347 | 0 | return asn1_parse_oid(hdr.payload, hdr.length, oid); |
348 | 0 | } |
349 | | |
350 | | |
351 | | void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len) |
352 | 0 | { |
353 | 0 | char *pos = buf; |
354 | 0 | size_t i; |
355 | 0 | int ret; |
356 | |
|
357 | 0 | if (len == 0) |
358 | 0 | return; |
359 | | |
360 | 0 | buf[0] = '\0'; |
361 | |
|
362 | 0 | for (i = 0; i < oid->len; i++) { |
363 | 0 | ret = os_snprintf(pos, buf + len - pos, |
364 | 0 | "%s%lu", |
365 | 0 | i == 0 ? "" : ".", oid->oid[i]); |
366 | 0 | if (os_snprintf_error(buf + len - pos, ret)) |
367 | 0 | break; |
368 | 0 | pos += ret; |
369 | 0 | } |
370 | 0 | buf[len - 1] = '\0'; |
371 | 0 | } |
372 | | |
373 | | |
374 | | static u8 rotate_bits(u8 octet) |
375 | 0 | { |
376 | 0 | int i; |
377 | 0 | u8 res; |
378 | |
|
379 | 0 | res = 0; |
380 | 0 | for (i = 0; i < 8; i++) { |
381 | 0 | res <<= 1; |
382 | 0 | if (octet & 1) |
383 | 0 | res |= 1; |
384 | 0 | octet >>= 1; |
385 | 0 | } |
386 | |
|
387 | 0 | return res; |
388 | 0 | } |
389 | | |
390 | | |
391 | | unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len) |
392 | 0 | { |
393 | 0 | unsigned long val = 0; |
394 | 0 | const u8 *pos = buf; |
395 | | |
396 | | /* BER requires that unused bits are zero, so we can ignore the number |
397 | | * of unused bits */ |
398 | 0 | pos++; |
399 | |
|
400 | 0 | if (len >= 2) |
401 | 0 | val |= rotate_bits(*pos++); |
402 | 0 | if (len >= 3) |
403 | 0 | val |= ((unsigned long) rotate_bits(*pos++)) << 8; |
404 | 0 | if (len >= 4) |
405 | 0 | val |= ((unsigned long) rotate_bits(*pos++)) << 16; |
406 | 0 | if (len >= 5) |
407 | 0 | val |= ((unsigned long) rotate_bits(*pos++)) << 24; |
408 | 0 | if (len >= 6) |
409 | 0 | wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored " |
410 | 0 | "(BIT STRING length %lu)", |
411 | 0 | __func__, (unsigned long) len); |
412 | |
|
413 | 0 | return val; |
414 | 0 | } |
415 | | |
416 | | |
417 | | int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b) |
418 | 0 | { |
419 | 0 | size_t i; |
420 | |
|
421 | 0 | if (a->len != b->len) |
422 | 0 | return 0; |
423 | | |
424 | 0 | for (i = 0; i < a->len; i++) { |
425 | 0 | if (a->oid[i] != b->oid[i]) |
426 | 0 | return 0; |
427 | 0 | } |
428 | | |
429 | 0 | return 1; |
430 | 0 | } |
431 | | |
432 | | |
433 | | int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next) |
434 | 0 | { |
435 | 0 | struct asn1_hdr hdr; |
436 | 0 | size_t left; |
437 | 0 | const u8 *pos; |
438 | 0 | int value; |
439 | |
|
440 | 0 | if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0 || |
441 | 0 | !asn1_is_integer(&hdr)) { |
442 | 0 | asn1_unexpected(&hdr, "ASN.1: Expected INTEGER"); |
443 | 0 | return -1; |
444 | 0 | } |
445 | | |
446 | 0 | *next = hdr.payload + hdr.length; |
447 | 0 | pos = hdr.payload; |
448 | 0 | left = hdr.length; |
449 | 0 | if (left > sizeof(value)) { |
450 | 0 | wpa_printf(MSG_DEBUG, "ASN.1: Too large INTEGER (len %u)", |
451 | 0 | hdr.length); |
452 | 0 | return -1; |
453 | 0 | } |
454 | 0 | value = 0; |
455 | 0 | while (left) { |
456 | 0 | value <<= 8; |
457 | 0 | value |= *pos++; |
458 | 0 | left--; |
459 | 0 | } |
460 | |
|
461 | 0 | *integer = value; |
462 | 0 | return 0; |
463 | 0 | } |
464 | | |
465 | | |
466 | | int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr, |
467 | | const u8 **next) |
468 | 0 | { |
469 | 0 | if (asn1_get_next(buf, len, hdr) < 0 || !asn1_is_sequence(hdr)) { |
470 | 0 | asn1_unexpected(hdr, "ASN.1: Expected SEQUENCE"); |
471 | 0 | return -1; |
472 | 0 | } |
473 | | |
474 | 0 | if (next) |
475 | 0 | *next = hdr->payload + hdr->length; |
476 | 0 | return 0; |
477 | 0 | } |
478 | | |
479 | | |
480 | | int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid, |
481 | | const u8 **params, size_t *params_len, const u8 **next) |
482 | 0 | { |
483 | 0 | const u8 *pos = buf, *end = buf + len; |
484 | 0 | struct asn1_hdr hdr; |
485 | | |
486 | | /* |
487 | | * AlgorithmIdentifier ::= SEQUENCE { |
488 | | * algorithm OBJECT IDENTIFIER, |
489 | | * parameters ANY DEFINED BY algorithm OPTIONAL} |
490 | | */ |
491 | 0 | if (asn1_get_sequence(pos, end - pos, &hdr, next) < 0 || |
492 | 0 | asn1_get_oid(hdr.payload, hdr.length, oid, &pos) < 0) |
493 | 0 | return -1; |
494 | | |
495 | 0 | if (params && params_len) { |
496 | 0 | *params = pos; |
497 | 0 | *params_len = hdr.payload + hdr.length - pos; |
498 | 0 | } |
499 | |
|
500 | 0 | return 0; |
501 | 0 | } |
502 | | |
503 | | |
504 | | void asn1_put_integer(struct wpabuf *buf, int val) |
505 | 0 | { |
506 | 0 | u8 bin[4]; |
507 | 0 | int zeros; |
508 | |
|
509 | 0 | WPA_PUT_BE32(bin, val); |
510 | 0 | zeros = 0; |
511 | 0 | while (zeros < 3 && bin[zeros] == 0) |
512 | 0 | zeros++; |
513 | 0 | wpabuf_put_u8(buf, ASN1_TAG_INTEGER); |
514 | 0 | wpabuf_put_u8(buf, 4 - zeros); |
515 | 0 | wpabuf_put_data(buf, &bin[zeros], 4 - zeros); |
516 | 0 | } |
517 | | |
518 | | |
519 | | static void asn1_put_len(struct wpabuf *buf, size_t len) |
520 | 0 | { |
521 | 0 | if (len <= 0x7f) { |
522 | 0 | wpabuf_put_u8(buf, len); |
523 | 0 | } else if (len <= 0xff) { |
524 | 0 | wpabuf_put_u8(buf, 0x80 | 1); |
525 | 0 | wpabuf_put_u8(buf, len); |
526 | 0 | } else if (len <= 0xffff) { |
527 | 0 | wpabuf_put_u8(buf, 0x80 | 2); |
528 | 0 | wpabuf_put_be16(buf, len); |
529 | 0 | } else if (len <= 0xffffff) { |
530 | 0 | wpabuf_put_u8(buf, 0x80 | 3); |
531 | 0 | wpabuf_put_be24(buf, len); |
532 | 0 | } else { |
533 | 0 | wpabuf_put_u8(buf, 0x80 | 4); |
534 | 0 | wpabuf_put_be32(buf, len); |
535 | 0 | } |
536 | 0 | } |
537 | | |
538 | | |
539 | | void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val) |
540 | 0 | { |
541 | 0 | wpabuf_put_u8(buf, ASN1_TAG_OCTETSTRING); |
542 | 0 | asn1_put_len(buf, wpabuf_len(val)); |
543 | 0 | wpabuf_put_buf(buf, val); |
544 | 0 | } |
545 | | |
546 | | |
547 | | void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid) |
548 | 0 | { |
549 | 0 | u8 *len; |
550 | 0 | size_t i; |
551 | |
|
552 | 0 | if (oid->len < 2) |
553 | 0 | return; |
554 | 0 | wpabuf_put_u8(buf, ASN1_TAG_OID); |
555 | 0 | len = wpabuf_put(buf, 1); |
556 | 0 | wpabuf_put_u8(buf, 40 * oid->oid[0] + oid->oid[1]); |
557 | 0 | for (i = 2; i < oid->len; i++) { |
558 | 0 | unsigned long val = oid->oid[i]; |
559 | 0 | u8 bytes[8]; |
560 | 0 | int idx = 0; |
561 | |
|
562 | 0 | while (val) { |
563 | 0 | bytes[idx] = (idx ? 0x80 : 0x00) | (val & 0x7f); |
564 | 0 | idx++; |
565 | 0 | val >>= 7; |
566 | 0 | } |
567 | 0 | if (idx == 0) { |
568 | 0 | bytes[idx] = 0; |
569 | 0 | idx = 1; |
570 | 0 | } |
571 | 0 | while (idx > 0) { |
572 | 0 | idx--; |
573 | 0 | wpabuf_put_u8(buf, bytes[idx]); |
574 | 0 | } |
575 | 0 | } |
576 | 0 | *len = (u8 *) wpabuf_put(buf, 0) - len - 1; |
577 | 0 | } |
578 | | |
579 | | |
580 | | void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag, |
581 | | size_t len) |
582 | 0 | { |
583 | 0 | wpabuf_put_u8(buf, class << 6 | (constructed ? 0x20 : 0x00) | tag); |
584 | 0 | asn1_put_len(buf, len); |
585 | 0 | } |
586 | | |
587 | | |
588 | | void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload) |
589 | 0 | { |
590 | 0 | asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SEQUENCE, |
591 | 0 | wpabuf_len(payload)); |
592 | 0 | wpabuf_put_buf(buf, payload); |
593 | 0 | } |
594 | | |
595 | | |
596 | | void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload) |
597 | 0 | { |
598 | 0 | asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SET, |
599 | 0 | wpabuf_len(payload)); |
600 | 0 | wpabuf_put_buf(buf, payload); |
601 | 0 | } |
602 | | |
603 | | |
604 | | void asn1_put_utf8string(struct wpabuf *buf, const char *val) |
605 | 0 | { |
606 | 0 | asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 0, ASN1_TAG_UTF8STRING, |
607 | 0 | os_strlen(val)); |
608 | 0 | wpabuf_put_str(buf, val); |
609 | 0 | } |
610 | | |
611 | | |
612 | | struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid, |
613 | | const struct wpabuf *params) |
614 | 0 | { |
615 | 0 | struct wpabuf *buf; |
616 | 0 | size_t len; |
617 | | |
618 | | /* |
619 | | * AlgorithmIdentifier ::= SEQUENCE { |
620 | | * algorithm OBJECT IDENTIFIER, |
621 | | * parameters ANY DEFINED BY algorithm OPTIONAL} |
622 | | */ |
623 | |
|
624 | 0 | len = 100; |
625 | 0 | if (params) |
626 | 0 | len += wpabuf_len(params); |
627 | 0 | buf = wpabuf_alloc(len); |
628 | 0 | if (!buf) |
629 | 0 | return NULL; |
630 | 0 | asn1_put_oid(buf, oid); |
631 | 0 | if (params) |
632 | 0 | wpabuf_put_buf(buf, params); |
633 | 0 | return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE); |
634 | 0 | } |
635 | | |
636 | | |
637 | | struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag) |
638 | 0 | { |
639 | 0 | struct wpabuf *res; |
640 | |
|
641 | 0 | if (!buf) |
642 | 0 | return NULL; |
643 | 0 | res = wpabuf_alloc(10 + wpabuf_len(buf)); |
644 | 0 | if (res) { |
645 | 0 | asn1_put_hdr(res, class, 1, tag, wpabuf_len(buf)); |
646 | 0 | wpabuf_put_buf(res, buf); |
647 | 0 | } |
648 | 0 | wpabuf_clear_free(buf); |
649 | 0 | return res; |
650 | 0 | } |