]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/tls/asn1.c
FT: Omit RSNXE from FT protocol Reassociation Response when needed
[thirdparty/hostap.git] / src / tls / asn1.c
CommitLineData
6fc6879b
JM
1/*
2 * ASN.1 DER parsing
d3811845 3 * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
6fc6879b 4 *
0f3d578e
JM
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
6fc6879b
JM
7 */
8
9#include "includes.h"
10
11#include "common.h"
31b5950d 12#include "utils/wpabuf.h"
6fc6879b
JM
13#include "asn1.h"
14
ce1f4773 15const struct asn1_oid asn1_sha1_oid = {
d3811845
JM
16 .oid = { 1, 3, 14, 3, 2, 26 },
17 .len = 6
18};
19
ce1f4773 20const struct asn1_oid asn1_sha256_oid = {
d3811845
JM
21 .oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 },
22 .len = 9
23};
24
ce1f4773
JM
25const struct asn1_oid asn1_ec_public_key_oid = {
26 .oid = { 1, 2, 840, 10045, 2, 1 },
27 .len = 6
28};
29
30const struct asn1_oid asn1_prime256v1_oid = {
31 .oid = { 1, 2, 840, 10045, 3, 1, 7 },
32 .len = 7
33};
34
35const struct asn1_oid asn1_secp384r1_oid = {
36 .oid = { 1, 3, 132, 0, 34 },
37 .len = 5
38};
39
40const struct asn1_oid asn1_secp521r1_oid = {
41 .oid = { 1, 3, 132, 0, 35 },
42 .len = 5
43};
44
45const struct asn1_oid asn1_brainpoolP256r1_oid = {
46 .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 7 },
47 .len = 10
48};
49
50const struct asn1_oid asn1_brainpoolP384r1_oid = {
51 .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 11 },
52 .len = 10
53};
54
55const struct asn1_oid asn1_brainpoolP512r1_oid = {
56 .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 13 },
57 .len = 10
58};
59
60const 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
65const 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
70const 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
75const struct asn1_oid asn1_pbkdf2_oid = {
76 .oid = { 1, 2, 840, 113549, 1, 5, 12 },
77 .len = 7
78};
79
80const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid = {
81 .oid = { 1, 2, 840, 113549, 2, 9 },
82 .len = 6
83};
84
85const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid = {
86 .oid = { 1, 2, 840, 113549, 2, 10 },
87 .len = 6
88};
89
90const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid = {
91 .oid = { 1, 2, 840, 113549, 2, 11 },
92 .len = 6
93};
94
95const 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
100const 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
d3811845 105
702cc6da
JM
106static int asn1_valid_der_boolean(struct asn1_hdr *hdr)
107{
108 /* Enforce DER requirements for a single way of encoding a BOOLEAN */
109 if (hdr->length != 1) {
110 wpa_printf(MSG_DEBUG, "ASN.1: Unexpected BOOLEAN length (%u)",
111 hdr->length);
112 return 0;
113 }
114
115 if (hdr->payload[0] != 0 && hdr->payload[0] != 0xff) {
116 wpa_printf(MSG_DEBUG,
117 "ASN.1: Invalid BOOLEAN value 0x%x (DER requires 0 or 0xff)",
118 hdr->payload[0]);
119 return 0;
120 }
121
122 return 1;
123}
124
125
126static int asn1_valid_der(struct asn1_hdr *hdr)
127{
128 if (hdr->class != ASN1_CLASS_UNIVERSAL)
129 return 1;
130 if (hdr->tag == ASN1_TAG_BOOLEAN && !asn1_valid_der_boolean(hdr))
131 return 0;
132 return 1;
133}
134
135
6fc6879b
JM
136int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
137{
138 const u8 *pos, *end;
139 u8 tmp;
140
141 os_memset(hdr, 0, sizeof(*hdr));
142 pos = buf;
143 end = buf + len;
144
3eae9766
JM
145 if (pos >= end) {
146 wpa_printf(MSG_DEBUG, "ASN.1: No room for Identifier");
147 return -1;
148 }
6fc6879b
JM
149 hdr->identifier = *pos++;
150 hdr->class = hdr->identifier >> 6;
151 hdr->constructed = !!(hdr->identifier & (1 << 5));
152
153 if ((hdr->identifier & 0x1f) == 0x1f) {
154 hdr->tag = 0;
155 do {
156 if (pos >= end) {
157 wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
158 "underflow");
159 return -1;
160 }
161 tmp = *pos++;
162 wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: "
163 "0x%02x", tmp);
164 hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
165 } while (tmp & 0x80);
166 } else
167 hdr->tag = hdr->identifier & 0x1f;
168
3eae9766
JM
169 if (pos >= end) {
170 wpa_printf(MSG_DEBUG, "ASN.1: No room for Length");
171 return -1;
172 }
6fc6879b
JM
173 tmp = *pos++;
174 if (tmp & 0x80) {
175 if (tmp == 0xff) {
176 wpa_printf(MSG_DEBUG, "ASN.1: Reserved length "
177 "value 0xff used");
178 return -1;
179 }
180 tmp &= 0x7f; /* number of subsequent octets */
181 hdr->length = 0;
182 if (tmp > 4) {
183 wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
184 return -1;
185 }
186 while (tmp--) {
187 if (pos >= end) {
188 wpa_printf(MSG_DEBUG, "ASN.1: Length "
189 "underflow");
190 return -1;
191 }
192 hdr->length = (hdr->length << 8) | *pos++;
193 }
194 } else {
195 /* Short form - length 0..127 in one octet */
196 hdr->length = tmp;
197 }
198
199 if (end < pos || hdr->length > (unsigned int) (end - pos)) {
200 wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow");
201 return -1;
202 }
203
204 hdr->payload = pos;
702cc6da
JM
205
206 return asn1_valid_der(hdr) ? 0 : -1;
6fc6879b
JM
207}
208
209
efe22727 210int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid)
6fc6879b 211{
6fc6879b
JM
212 const u8 *pos, *end;
213 unsigned long val;
214 u8 tmp;
215
216 os_memset(oid, 0, sizeof(*oid));
217
efe22727
JM
218 pos = buf;
219 end = buf + len;
6fc6879b
JM
220
221 while (pos < end) {
222 val = 0;
223
224 do {
225 if (pos >= end)
226 return -1;
227 tmp = *pos++;
228 val = (val << 7) | (tmp & 0x7f);
229 } while (tmp & 0x80);
230
231 if (oid->len >= ASN1_MAX_OID_LEN) {
232 wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value");
233 return -1;
234 }
235 if (oid->len == 0) {
236 /*
237 * The first octet encodes the first two object
238 * identifier components in (X*40) + Y formula.
239 * X = 0..2.
240 */
241 oid->oid[0] = val / 40;
242 if (oid->oid[0] > 2)
243 oid->oid[0] = 2;
244 oid->oid[1] = val - oid->oid[0] * 40;
245 oid->len = 2;
246 } else
247 oid->oid[oid->len++] = val;
248 }
249
250 return 0;
251}
252
253
efe22727
JM
254int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
255 const u8 **next)
256{
257 struct asn1_hdr hdr;
258
259 if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
260 return -1;
261
262 if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) {
263 wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d "
264 "tag 0x%x", hdr.class, hdr.tag);
265 return -1;
266 }
267
268 *next = hdr.payload + hdr.length;
269
270 return asn1_parse_oid(hdr.payload, hdr.length, oid);
271}
272
273
d3811845 274void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len)
6fc6879b
JM
275{
276 char *pos = buf;
277 size_t i;
278 int ret;
279
280 if (len == 0)
281 return;
282
283 buf[0] = '\0';
284
285 for (i = 0; i < oid->len; i++) {
286 ret = os_snprintf(pos, buf + len - pos,
287 "%s%lu",
288 i == 0 ? "" : ".", oid->oid[i]);
d85e1fc8 289 if (os_snprintf_error(buf + len - pos, ret))
6fc6879b
JM
290 break;
291 pos += ret;
292 }
293 buf[len - 1] = '\0';
294}
295
296
297static u8 rotate_bits(u8 octet)
298{
299 int i;
300 u8 res;
301
302 res = 0;
303 for (i = 0; i < 8; i++) {
304 res <<= 1;
305 if (octet & 1)
306 res |= 1;
307 octet >>= 1;
308 }
309
310 return res;
311}
312
313
314unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
315{
316 unsigned long val = 0;
317 const u8 *pos = buf;
318
319 /* BER requires that unused bits are zero, so we can ignore the number
320 * of unused bits */
321 pos++;
322
323 if (len >= 2)
324 val |= rotate_bits(*pos++);
325 if (len >= 3)
326 val |= ((unsigned long) rotate_bits(*pos++)) << 8;
327 if (len >= 4)
328 val |= ((unsigned long) rotate_bits(*pos++)) << 16;
329 if (len >= 5)
330 val |= ((unsigned long) rotate_bits(*pos++)) << 24;
331 if (len >= 6)
332 wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored "
333 "(BIT STRING length %lu)",
334 __func__, (unsigned long) len);
335
336 return val;
337}
d3811845
JM
338
339
340int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b)
341{
342 size_t i;
343
344 if (a->len != b->len)
345 return 0;
346
347 for (i = 0; i < a->len; i++) {
348 if (a->oid[i] != b->oid[i])
349 return 0;
350 }
351
352 return 1;
353}
3393d94d
JM
354
355
356int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next)
357{
358 struct asn1_hdr hdr;
359 size_t left;
360 const u8 *pos;
361 int value;
362
363 if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
364 return -1;
365
366 if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
367 wpa_printf(MSG_DEBUG,
368 "ASN.1: Expected INTEGER - found class %d tag 0x%x",
369 hdr.class, hdr.tag);
370 return -1;
371 }
372
373 *next = hdr.payload + hdr.length;
374 pos = hdr.payload;
375 left = hdr.length;
376 if (left > sizeof(value)) {
377 wpa_printf(MSG_DEBUG, "ASN.1: Too large INTEGER (len %u)",
378 hdr.length);
379 return -1;
380 }
381 value = 0;
382 while (left) {
383 value <<= 8;
384 value |= *pos++;
385 left--;
386 }
387
388 *integer = value;
389 return 0;
390}
f7f2843c
JM
391
392
393int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr,
394 const u8 **next)
395{
396 if (asn1_get_next(buf, len, hdr) < 0 ||
397 hdr->class != ASN1_CLASS_UNIVERSAL ||
398 hdr->tag != ASN1_TAG_SEQUENCE) {
399 wpa_printf(MSG_DEBUG,
400 "ASN.1: Expected SEQUENCE - found class %d tag 0x%x",
401 hdr->class, hdr->tag);
402 return -1;
403 }
404
405 if (next)
406 *next = hdr->payload + hdr->length;
407 return 0;
408}
8006742f
JM
409
410
411int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid,
412 const u8 **params, size_t *params_len, const u8 **next)
413{
414 const u8 *pos = buf, *end = buf + len;
415 struct asn1_hdr hdr;
416
417 /*
418 * AlgorithmIdentifier ::= SEQUENCE {
419 * algorithm OBJECT IDENTIFIER,
420 * parameters ANY DEFINED BY algorithm OPTIONAL}
421 */
422 if (asn1_get_sequence(pos, end - pos, &hdr, next) < 0 ||
423 asn1_get_oid(hdr.payload, hdr.length, oid, &pos) < 0)
424 return -1;
425
426 if (params && params_len) {
427 *params = pos;
428 *params_len = hdr.payload + hdr.length - pos;
429 }
430
431 return 0;
432}
31b5950d
JM
433
434
435void asn1_put_integer(struct wpabuf *buf, int val)
436{
437 u8 bin[4];
438 int zeros;
439
440 WPA_PUT_BE32(bin, val);
441 zeros = 0;
442 while (zeros < 3 && bin[zeros] == 0)
443 zeros++;
444 wpabuf_put_u8(buf, ASN1_TAG_INTEGER);
445 wpabuf_put_u8(buf, 4 - zeros);
446 wpabuf_put_data(buf, &bin[zeros], 4 - zeros);
447}
448
449
450static void asn1_put_len(struct wpabuf *buf, size_t len)
451{
452 if (len <= 0x7f) {
453 wpabuf_put_u8(buf, len);
454 } else if (len <= 0xff) {
455 wpabuf_put_u8(buf, 0x80 | 1);
456 wpabuf_put_u8(buf, len);
457 } else if (len <= 0xffff) {
458 wpabuf_put_u8(buf, 0x80 | 2);
459 wpabuf_put_be16(buf, len);
460 } else if (len <= 0xffffff) {
461 wpabuf_put_u8(buf, 0x80 | 3);
462 wpabuf_put_be24(buf, len);
463 } else {
464 wpabuf_put_u8(buf, 0x80 | 4);
465 wpabuf_put_be32(buf, len);
466 }
467}
468
469
470void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val)
471{
472 wpabuf_put_u8(buf, ASN1_TAG_OCTETSTRING);
473 asn1_put_len(buf, wpabuf_len(val));
474 wpabuf_put_buf(buf, val);
475}
476
477
478void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid)
479{
480 u8 *len;
481 size_t i;
482
483 if (oid->len < 2)
484 return;
485 wpabuf_put_u8(buf, ASN1_TAG_OID);
486 len = wpabuf_put(buf, 1);
487 wpabuf_put_u8(buf, 40 * oid->oid[0] + oid->oid[1]);
488 for (i = 2; i < oid->len; i++) {
489 unsigned long val = oid->oid[i];
490 u8 bytes[8];
491 int idx = 0;
492
493 while (val) {
494 bytes[idx] = (idx ? 0x80 : 0x00) | (val & 0x7f);
495 idx++;
496 val >>= 7;
497 }
498 if (idx == 0) {
499 bytes[idx] = 0;
500 idx = 1;
501 }
502 while (idx > 0) {
503 idx--;
504 wpabuf_put_u8(buf, bytes[idx]);
505 }
506 }
507 *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
508}
509
510
511void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag,
512 size_t len)
513{
514 wpabuf_put_u8(buf, class << 6 | (constructed ? 0x20 : 0x00) | tag);
515 asn1_put_len(buf, len);
516}
517
518
519void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload)
520{
521 asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SEQUENCE,
522 wpabuf_len(payload));
523 wpabuf_put_buf(buf, payload);
524}
525
526
527void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload)
528{
529 asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SET,
530 wpabuf_len(payload));
531 wpabuf_put_buf(buf, payload);
532}
533
534
535void asn1_put_utf8string(struct wpabuf *buf, const char *val)
536{
537 asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 0, ASN1_TAG_UTF8STRING,
538 os_strlen(val));
539 wpabuf_put_str(buf, val);
540}
541
542
543struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid,
544 const struct wpabuf *params)
545{
546 struct wpabuf *buf;
547 size_t len;
548
549 /*
550 * AlgorithmIdentifier ::= SEQUENCE {
551 * algorithm OBJECT IDENTIFIER,
552 * parameters ANY DEFINED BY algorithm OPTIONAL}
553 */
554
555 len = 100;
556 if (params)
557 len += wpabuf_len(params);
558 buf = wpabuf_alloc(len);
559 if (!buf)
560 return NULL;
561 asn1_put_oid(buf, oid);
562 if (params)
563 wpabuf_put_buf(buf, params);
564 return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
565}
566
567
568struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag)
569{
570 struct wpabuf *res;
571
572 if (!buf)
573 return NULL;
574 res = wpabuf_alloc(10 + wpabuf_len(buf));
575 if (res) {
576 asn1_put_hdr(res, class, 1, tag, wpabuf_len(buf));
577 wpabuf_put_buf(res, buf);
578 }
579 wpabuf_clear_free(buf);
580 return res;
581}