blob: 75e328556b1c1477c49e2ed8a89adcd9cf1287d7 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * X.509v3 certificate parsing and processing (RFC 3280 profile)
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07003 * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "crypto/crypto.h"
13#include "asn1.h"
14#include "x509v3.h"
15
16
17static void x509_free_name(struct x509_name *name)
18{
19 size_t i;
20
21 for (i = 0; i < name->num_attr; i++) {
22 os_free(name->attr[i].value);
23 name->attr[i].value = NULL;
24 name->attr[i].type = X509_NAME_ATTR_NOT_USED;
25 }
26 name->num_attr = 0;
27 os_free(name->email);
28 name->email = NULL;
29
30 os_free(name->alt_email);
31 os_free(name->dns);
32 os_free(name->uri);
33 os_free(name->ip);
34 name->alt_email = name->dns = name->uri = NULL;
35 name->ip = NULL;
36 name->ip_len = 0;
37 os_memset(&name->rid, 0, sizeof(name->rid));
38}
39
40
41/**
42 * x509_certificate_free - Free an X.509 certificate
43 * @cert: Certificate to be freed
44 */
45void x509_certificate_free(struct x509_certificate *cert)
46{
47 if (cert == NULL)
48 return;
49 if (cert->next) {
50 wpa_printf(MSG_DEBUG, "X509: x509_certificate_free: cer=%p "
51 "was still on a list (next=%p)\n",
52 cert, cert->next);
53 }
54 x509_free_name(&cert->issuer);
55 x509_free_name(&cert->subject);
56 os_free(cert->public_key);
57 os_free(cert->sign_value);
58 os_free(cert);
59}
60
61
62/**
63 * x509_certificate_free - Free an X.509 certificate chain
64 * @cert: Pointer to the first certificate in the chain
65 */
66void x509_certificate_chain_free(struct x509_certificate *cert)
67{
68 struct x509_certificate *next;
69
70 while (cert) {
71 next = cert->next;
72 cert->next = NULL;
73 x509_certificate_free(cert);
74 cert = next;
75 }
76}
77
78
79static int x509_whitespace(char c)
80{
81 return c == ' ' || c == '\t';
82}
83
84
85static void x509_str_strip_whitespace(char *a)
86{
87 char *ipos, *opos;
88 int remove_whitespace = 1;
89
90 ipos = opos = a;
91
92 while (*ipos) {
93 if (remove_whitespace && x509_whitespace(*ipos))
94 ipos++;
95 else {
96 remove_whitespace = x509_whitespace(*ipos);
97 *opos++ = *ipos++;
98 }
99 }
100
101 *opos-- = '\0';
102 if (opos > a && x509_whitespace(*opos))
103 *opos = '\0';
104}
105
106
107static int x509_str_compare(const char *a, const char *b)
108{
109 char *aa, *bb;
110 int ret;
111
112 if (!a && b)
113 return -1;
114 if (a && !b)
115 return 1;
116 if (!a && !b)
117 return 0;
118
119 aa = os_strdup(a);
120 bb = os_strdup(b);
121
122 if (aa == NULL || bb == NULL) {
123 os_free(aa);
124 os_free(bb);
125 return os_strcasecmp(a, b);
126 }
127
128 x509_str_strip_whitespace(aa);
129 x509_str_strip_whitespace(bb);
130
131 ret = os_strcasecmp(aa, bb);
132
133 os_free(aa);
134 os_free(bb);
135
136 return ret;
137}
138
139
140/**
141 * x509_name_compare - Compare X.509 certificate names
142 * @a: Certificate name
143 * @b: Certificate name
144 * Returns: <0, 0, or >0 based on whether a is less than, equal to, or
145 * greater than b
146 */
147int x509_name_compare(struct x509_name *a, struct x509_name *b)
148{
149 int res;
150 size_t i;
151
152 if (!a && b)
153 return -1;
154 if (a && !b)
155 return 1;
156 if (!a && !b)
157 return 0;
158 if (a->num_attr < b->num_attr)
159 return -1;
160 if (a->num_attr > b->num_attr)
161 return 1;
162
163 for (i = 0; i < a->num_attr; i++) {
164 if (a->attr[i].type < b->attr[i].type)
165 return -1;
166 if (a->attr[i].type > b->attr[i].type)
167 return -1;
168 res = x509_str_compare(a->attr[i].value, b->attr[i].value);
169 if (res)
170 return res;
171 }
172 res = x509_str_compare(a->email, b->email);
173 if (res)
174 return res;
175
176 return 0;
177}
178
179
180static int x509_parse_algorithm_identifier(
181 const u8 *buf, size_t len,
182 struct x509_algorithm_identifier *id, const u8 **next)
183{
184 struct asn1_hdr hdr;
185 const u8 *pos, *end;
186
187 /*
188 * AlgorithmIdentifier ::= SEQUENCE {
189 * algorithm OBJECT IDENTIFIER,
190 * parameters ANY DEFINED BY algorithm OPTIONAL
191 * }
192 */
193
194 if (asn1_get_next(buf, len, &hdr) < 0 ||
195 hdr.class != ASN1_CLASS_UNIVERSAL ||
196 hdr.tag != ASN1_TAG_SEQUENCE) {
197 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
198 "(AlgorithmIdentifier) - found class %d tag 0x%x",
199 hdr.class, hdr.tag);
200 return -1;
201 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800202 if (hdr.length > buf + len - hdr.payload)
203 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700204 pos = hdr.payload;
205 end = pos + hdr.length;
206
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700207 *next = end;
208
209 if (asn1_get_oid(pos, end - pos, &id->oid, &pos))
210 return -1;
211
212 /* TODO: optional parameters */
213
214 return 0;
215}
216
217
218static int x509_parse_public_key(const u8 *buf, size_t len,
219 struct x509_certificate *cert,
220 const u8 **next)
221{
222 struct asn1_hdr hdr;
223 const u8 *pos, *end;
224
225 /*
226 * SubjectPublicKeyInfo ::= SEQUENCE {
227 * algorithm AlgorithmIdentifier,
228 * subjectPublicKey BIT STRING
229 * }
230 */
231
232 pos = buf;
233 end = buf + len;
234
235 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
236 hdr.class != ASN1_CLASS_UNIVERSAL ||
237 hdr.tag != ASN1_TAG_SEQUENCE) {
238 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
239 "(SubjectPublicKeyInfo) - found class %d tag 0x%x",
240 hdr.class, hdr.tag);
241 return -1;
242 }
243 pos = hdr.payload;
244
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800245 if (hdr.length > end - pos)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700246 return -1;
247 end = pos + hdr.length;
248 *next = end;
249
250 if (x509_parse_algorithm_identifier(pos, end - pos,
251 &cert->public_key_alg, &pos))
252 return -1;
253
254 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
255 hdr.class != ASN1_CLASS_UNIVERSAL ||
256 hdr.tag != ASN1_TAG_BITSTRING) {
257 wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING "
258 "(subjectPublicKey) - found class %d tag 0x%x",
259 hdr.class, hdr.tag);
260 return -1;
261 }
262 if (hdr.length < 1)
263 return -1;
264 pos = hdr.payload;
265 if (*pos) {
266 wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits",
267 *pos);
268 /*
269 * TODO: should this be rejected? X.509 certificates are
270 * unlikely to use such a construction. Now we would end up
271 * including the extra bits in the buffer which may also be
272 * ok.
273 */
274 }
275 os_free(cert->public_key);
276 cert->public_key = os_malloc(hdr.length - 1);
277 if (cert->public_key == NULL) {
278 wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
279 "public key");
280 return -1;
281 }
282 os_memcpy(cert->public_key, pos + 1, hdr.length - 1);
283 cert->public_key_len = hdr.length - 1;
284 wpa_hexdump(MSG_MSGDUMP, "X509: subjectPublicKey",
285 cert->public_key, cert->public_key_len);
286
287 return 0;
288}
289
290
291static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
292 const u8 **next)
293{
294 struct asn1_hdr hdr;
295 const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end;
296 struct asn1_oid oid;
297 char *val;
298
299 /*
300 * Name ::= CHOICE { RDNSequence }
301 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
302 * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
303 * AttributeTypeAndValue ::= SEQUENCE {
304 * type AttributeType,
305 * value AttributeValue
306 * }
307 * AttributeType ::= OBJECT IDENTIFIER
308 * AttributeValue ::= ANY DEFINED BY AttributeType
309 */
310
311 if (asn1_get_next(buf, len, &hdr) < 0 ||
312 hdr.class != ASN1_CLASS_UNIVERSAL ||
313 hdr.tag != ASN1_TAG_SEQUENCE) {
314 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
315 "(Name / RDNSequencer) - found class %d tag 0x%x",
316 hdr.class, hdr.tag);
317 return -1;
318 }
319 pos = hdr.payload;
320
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800321 if (hdr.length > buf + len - pos)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700322 return -1;
323
324 end = *next = pos + hdr.length;
325
326 while (pos < end) {
327 enum x509_name_attr_type type;
328
329 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
330 hdr.class != ASN1_CLASS_UNIVERSAL ||
331 hdr.tag != ASN1_TAG_SET) {
332 wpa_printf(MSG_DEBUG, "X509: Expected SET "
333 "(RelativeDistinguishedName) - found class "
334 "%d tag 0x%x", hdr.class, hdr.tag);
335 x509_free_name(name);
336 return -1;
337 }
338
339 set_pos = hdr.payload;
340 pos = set_end = hdr.payload + hdr.length;
341
342 if (asn1_get_next(set_pos, set_end - set_pos, &hdr) < 0 ||
343 hdr.class != ASN1_CLASS_UNIVERSAL ||
344 hdr.tag != ASN1_TAG_SEQUENCE) {
345 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
346 "(AttributeTypeAndValue) - found class %d "
347 "tag 0x%x", hdr.class, hdr.tag);
348 x509_free_name(name);
349 return -1;
350 }
351
352 seq_pos = hdr.payload;
353 seq_end = hdr.payload + hdr.length;
354
355 if (asn1_get_oid(seq_pos, seq_end - seq_pos, &oid, &seq_pos)) {
356 x509_free_name(name);
357 return -1;
358 }
359
360 if (asn1_get_next(seq_pos, seq_end - seq_pos, &hdr) < 0 ||
361 hdr.class != ASN1_CLASS_UNIVERSAL) {
362 wpa_printf(MSG_DEBUG, "X509: Failed to parse "
363 "AttributeValue");
364 x509_free_name(name);
365 return -1;
366 }
367
368 /* RFC 3280:
369 * MUST: country, organization, organizational-unit,
370 * distinguished name qualifier, state or province name,
371 * common name, serial number.
372 * SHOULD: locality, title, surname, given name, initials,
373 * pseudonym, generation qualifier.
374 * MUST: domainComponent (RFC 2247).
375 */
376 type = X509_NAME_ATTR_NOT_USED;
377 if (oid.len == 4 &&
378 oid.oid[0] == 2 && oid.oid[1] == 5 && oid.oid[2] == 4) {
379 /* id-at ::= 2.5.4 */
380 switch (oid.oid[3]) {
381 case 3:
382 /* commonName */
383 type = X509_NAME_ATTR_CN;
384 break;
385 case 6:
386 /* countryName */
387 type = X509_NAME_ATTR_C;
388 break;
389 case 7:
390 /* localityName */
391 type = X509_NAME_ATTR_L;
392 break;
393 case 8:
394 /* stateOrProvinceName */
395 type = X509_NAME_ATTR_ST;
396 break;
397 case 10:
398 /* organizationName */
399 type = X509_NAME_ATTR_O;
400 break;
401 case 11:
402 /* organizationalUnitName */
403 type = X509_NAME_ATTR_OU;
404 break;
405 }
406 } else if (oid.len == 7 &&
407 oid.oid[0] == 1 && oid.oid[1] == 2 &&
408 oid.oid[2] == 840 && oid.oid[3] == 113549 &&
409 oid.oid[4] == 1 && oid.oid[5] == 9 &&
410 oid.oid[6] == 1) {
411 /* 1.2.840.113549.1.9.1 - e-mailAddress */
412 os_free(name->email);
413 name->email = os_malloc(hdr.length + 1);
414 if (name->email == NULL) {
415 x509_free_name(name);
416 return -1;
417 }
418 os_memcpy(name->email, hdr.payload, hdr.length);
419 name->email[hdr.length] = '\0';
420 continue;
421 } else if (oid.len == 7 &&
422 oid.oid[0] == 0 && oid.oid[1] == 9 &&
423 oid.oid[2] == 2342 && oid.oid[3] == 19200300 &&
424 oid.oid[4] == 100 && oid.oid[5] == 1 &&
425 oid.oid[6] == 25) {
426 /* 0.9.2342.19200300.100.1.25 - domainComponent */
427 type = X509_NAME_ATTR_DC;
428 }
429
430 if (type == X509_NAME_ATTR_NOT_USED) {
431 wpa_hexdump(MSG_DEBUG, "X509: Unrecognized OID",
432 (u8 *) oid.oid,
433 oid.len * sizeof(oid.oid[0]));
434 wpa_hexdump_ascii(MSG_MSGDUMP, "X509: Attribute Data",
435 hdr.payload, hdr.length);
436 continue;
437 }
438
439 if (name->num_attr == X509_MAX_NAME_ATTRIBUTES) {
440 wpa_printf(MSG_INFO, "X509: Too many Name attributes");
441 x509_free_name(name);
442 return -1;
443 }
444
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700445 val = dup_binstr(hdr.payload, hdr.length);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700446 if (val == NULL) {
447 x509_free_name(name);
448 return -1;
449 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700450 if (os_strlen(val) != hdr.length) {
451 wpa_printf(MSG_INFO, "X509: Reject certificate with "
452 "embedded NUL byte in a string (%s[NUL])",
453 val);
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700454 os_free(val);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700455 x509_free_name(name);
456 return -1;
457 }
458
459 name->attr[name->num_attr].type = type;
460 name->attr[name->num_attr].value = val;
461 name->num_attr++;
462 }
463
464 return 0;
465}
466
467
468static char * x509_name_attr_str(enum x509_name_attr_type type)
469{
470 switch (type) {
471 case X509_NAME_ATTR_NOT_USED:
472 return "[N/A]";
473 case X509_NAME_ATTR_DC:
474 return "DC";
475 case X509_NAME_ATTR_CN:
476 return "CN";
477 case X509_NAME_ATTR_C:
478 return "C";
479 case X509_NAME_ATTR_L:
480 return "L";
481 case X509_NAME_ATTR_ST:
482 return "ST";
483 case X509_NAME_ATTR_O:
484 return "O";
485 case X509_NAME_ATTR_OU:
486 return "OU";
487 }
488 return "?";
489}
490
491
492/**
493 * x509_name_string - Convert an X.509 certificate name into a string
494 * @name: Name to convert
495 * @buf: Buffer for the string
496 * @len: Maximum buffer length
497 */
498void x509_name_string(struct x509_name *name, char *buf, size_t len)
499{
500 char *pos, *end;
501 int ret;
502 size_t i;
503
504 if (len == 0)
505 return;
506
507 pos = buf;
508 end = buf + len;
509
510 for (i = 0; i < name->num_attr; i++) {
511 ret = os_snprintf(pos, end - pos, "%s=%s, ",
512 x509_name_attr_str(name->attr[i].type),
513 name->attr[i].value);
Dmitry Shmidtfb45fd52015-01-05 13:08:17 -0800514 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700515 goto done;
516 pos += ret;
517 }
518
519 if (pos > buf + 1 && pos[-1] == ' ' && pos[-2] == ',') {
520 pos--;
521 *pos = '\0';
522 pos--;
523 *pos = '\0';
524 }
525
526 if (name->email) {
527 ret = os_snprintf(pos, end - pos, "/emailAddress=%s",
528 name->email);
Dmitry Shmidtfb45fd52015-01-05 13:08:17 -0800529 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700530 goto done;
531 pos += ret;
532 }
533
534done:
535 end[-1] = '\0';
536}
537
538
539static int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag,
540 os_time_t *val)
541{
542 const char *pos;
543 int year, month, day, hour, min, sec;
544
545 /*
546 * Time ::= CHOICE {
547 * utcTime UTCTime,
548 * generalTime GeneralizedTime
549 * }
550 *
551 * UTCTime: YYMMDDHHMMSSZ
552 * GeneralizedTime: YYYYMMDDHHMMSSZ
553 */
554
555 pos = (const char *) buf;
556
557 switch (asn1_tag) {
558 case ASN1_TAG_UTCTIME:
559 if (len != 13 || buf[12] != 'Z') {
560 wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized "
561 "UTCTime format", buf, len);
562 return -1;
563 }
564 if (sscanf(pos, "%02d", &year) != 1) {
565 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
566 "UTCTime year", buf, len);
567 return -1;
568 }
569 if (year < 50)
570 year += 2000;
571 else
572 year += 1900;
573 pos += 2;
574 break;
575 case ASN1_TAG_GENERALIZEDTIME:
576 if (len != 15 || buf[14] != 'Z') {
577 wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized "
578 "GeneralizedTime format", buf, len);
579 return -1;
580 }
581 if (sscanf(pos, "%04d", &year) != 1) {
582 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
583 "GeneralizedTime year", buf, len);
584 return -1;
585 }
586 pos += 4;
587 break;
588 default:
589 wpa_printf(MSG_DEBUG, "X509: Expected UTCTime or "
590 "GeneralizedTime - found tag 0x%x", asn1_tag);
591 return -1;
592 }
593
594 if (sscanf(pos, "%02d", &month) != 1) {
595 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
596 "(month)", buf, len);
597 return -1;
598 }
599 pos += 2;
600
601 if (sscanf(pos, "%02d", &day) != 1) {
602 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
603 "(day)", buf, len);
604 return -1;
605 }
606 pos += 2;
607
608 if (sscanf(pos, "%02d", &hour) != 1) {
609 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
610 "(hour)", buf, len);
611 return -1;
612 }
613 pos += 2;
614
615 if (sscanf(pos, "%02d", &min) != 1) {
616 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
617 "(min)", buf, len);
618 return -1;
619 }
620 pos += 2;
621
622 if (sscanf(pos, "%02d", &sec) != 1) {
623 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
624 "(sec)", buf, len);
625 return -1;
626 }
627
628 if (os_mktime(year, month, day, hour, min, sec, val) < 0) {
629 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to convert Time",
630 buf, len);
631 if (year < 1970) {
632 /*
633 * At least some test certificates have been configured
634 * to use dates prior to 1970. Set the date to
635 * beginning of 1970 to handle these case.
636 */
637 wpa_printf(MSG_DEBUG, "X509: Year=%d before epoch - "
638 "assume epoch as the time", year);
639 *val = 0;
640 return 0;
641 }
642 return -1;
643 }
644
645 return 0;
646}
647
648
649static int x509_parse_validity(const u8 *buf, size_t len,
650 struct x509_certificate *cert, const u8 **next)
651{
652 struct asn1_hdr hdr;
653 const u8 *pos;
654 size_t plen;
655
656 /*
657 * Validity ::= SEQUENCE {
658 * notBefore Time,
659 * notAfter Time
660 * }
661 *
662 * RFC 3280, 4.1.2.5:
663 * CAs conforming to this profile MUST always encode certificate
664 * validity dates through the year 2049 as UTCTime; certificate
665 * validity dates in 2050 or later MUST be encoded as GeneralizedTime.
666 */
667
668 if (asn1_get_next(buf, len, &hdr) < 0 ||
669 hdr.class != ASN1_CLASS_UNIVERSAL ||
670 hdr.tag != ASN1_TAG_SEQUENCE) {
671 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
672 "(Validity) - found class %d tag 0x%x",
673 hdr.class, hdr.tag);
674 return -1;
675 }
676 pos = hdr.payload;
677 plen = hdr.length;
678
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800679 if (plen > (size_t) (buf + len - pos))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700680 return -1;
681
682 *next = pos + plen;
683
684 if (asn1_get_next(pos, plen, &hdr) < 0 ||
685 hdr.class != ASN1_CLASS_UNIVERSAL ||
686 x509_parse_time(hdr.payload, hdr.length, hdr.tag,
687 &cert->not_before) < 0) {
688 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notBefore "
689 "Time", hdr.payload, hdr.length);
690 return -1;
691 }
692
693 pos = hdr.payload + hdr.length;
694 plen = *next - pos;
695
696 if (asn1_get_next(pos, plen, &hdr) < 0 ||
697 hdr.class != ASN1_CLASS_UNIVERSAL ||
698 x509_parse_time(hdr.payload, hdr.length, hdr.tag,
699 &cert->not_after) < 0) {
700 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notAfter "
701 "Time", hdr.payload, hdr.length);
702 return -1;
703 }
704
705 wpa_printf(MSG_MSGDUMP, "X509: Validity: notBefore: %lu notAfter: %lu",
706 (unsigned long) cert->not_before,
707 (unsigned long) cert->not_after);
708
709 return 0;
710}
711
712
713static int x509_id_ce_oid(struct asn1_oid *oid)
714{
715 /* id-ce arc from X.509 for standard X.509v3 extensions */
716 return oid->len >= 4 &&
717 oid->oid[0] == 2 /* joint-iso-ccitt */ &&
718 oid->oid[1] == 5 /* ds */ &&
719 oid->oid[2] == 29 /* id-ce */;
720}
721
722
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -0800723static int x509_any_ext_key_usage_oid(struct asn1_oid *oid)
724{
725 return oid->len == 6 &&
726 x509_id_ce_oid(oid) &&
727 oid->oid[3] == 37 /* extKeyUsage */ &&
728 oid->oid[4] == 0 /* anyExtendedKeyUsage */;
729}
730
731
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700732static int x509_parse_ext_key_usage(struct x509_certificate *cert,
733 const u8 *pos, size_t len)
734{
735 struct asn1_hdr hdr;
736
737 /*
738 * KeyUsage ::= BIT STRING {
739 * digitalSignature (0),
740 * nonRepudiation (1),
741 * keyEncipherment (2),
742 * dataEncipherment (3),
743 * keyAgreement (4),
744 * keyCertSign (5),
745 * cRLSign (6),
746 * encipherOnly (7),
747 * decipherOnly (8) }
748 */
749
750 if (asn1_get_next(pos, len, &hdr) < 0 ||
751 hdr.class != ASN1_CLASS_UNIVERSAL ||
752 hdr.tag != ASN1_TAG_BITSTRING ||
753 hdr.length < 1) {
754 wpa_printf(MSG_DEBUG, "X509: Expected BIT STRING in "
755 "KeyUsage; found %d tag 0x%x len %d",
756 hdr.class, hdr.tag, hdr.length);
757 return -1;
758 }
759
760 cert->extensions_present |= X509_EXT_KEY_USAGE;
761 cert->key_usage = asn1_bit_string_to_long(hdr.payload, hdr.length);
762
763 wpa_printf(MSG_DEBUG, "X509: KeyUsage 0x%lx", cert->key_usage);
764
765 return 0;
766}
767
768
769static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,
770 const u8 *pos, size_t len)
771{
772 struct asn1_hdr hdr;
773 unsigned long value;
774 size_t left;
775
776 /*
777 * BasicConstraints ::= SEQUENCE {
778 * cA BOOLEAN DEFAULT FALSE,
779 * pathLenConstraint INTEGER (0..MAX) OPTIONAL }
780 */
781
782 if (asn1_get_next(pos, len, &hdr) < 0 ||
783 hdr.class != ASN1_CLASS_UNIVERSAL ||
784 hdr.tag != ASN1_TAG_SEQUENCE) {
785 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
786 "BasicConstraints; found %d tag 0x%x",
787 hdr.class, hdr.tag);
788 return -1;
789 }
790
791 cert->extensions_present |= X509_EXT_BASIC_CONSTRAINTS;
792
793 if (hdr.length == 0)
794 return 0;
795
796 if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
797 hdr.class != ASN1_CLASS_UNIVERSAL) {
798 wpa_printf(MSG_DEBUG, "X509: Failed to parse "
799 "BasicConstraints");
800 return -1;
801 }
802
803 if (hdr.tag == ASN1_TAG_BOOLEAN) {
804 if (hdr.length != 1) {
805 wpa_printf(MSG_DEBUG, "X509: Unexpected "
806 "Boolean length (%u) in BasicConstraints",
807 hdr.length);
808 return -1;
809 }
810 cert->ca = hdr.payload[0];
811
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800812 if (hdr.length == pos + len - hdr.payload) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700813 wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d",
814 cert->ca);
815 return 0;
816 }
817
818 if (asn1_get_next(hdr.payload + hdr.length, len - hdr.length,
819 &hdr) < 0 ||
820 hdr.class != ASN1_CLASS_UNIVERSAL) {
821 wpa_printf(MSG_DEBUG, "X509: Failed to parse "
822 "BasicConstraints");
823 return -1;
824 }
825 }
826
827 if (hdr.tag != ASN1_TAG_INTEGER) {
828 wpa_printf(MSG_DEBUG, "X509: Expected INTEGER in "
829 "BasicConstraints; found class %d tag 0x%x",
830 hdr.class, hdr.tag);
831 return -1;
832 }
833
834 pos = hdr.payload;
835 left = hdr.length;
836 value = 0;
837 while (left) {
838 value <<= 8;
839 value |= *pos++;
840 left--;
841 }
842
843 cert->path_len_constraint = value;
844 cert->extensions_present |= X509_EXT_PATH_LEN_CONSTRAINT;
845
846 wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d "
847 "pathLenConstraint=%lu",
848 cert->ca, cert->path_len_constraint);
849
850 return 0;
851}
852
853
854static int x509_parse_alt_name_rfc8222(struct x509_name *name,
855 const u8 *pos, size_t len)
856{
857 /* rfc822Name IA5String */
858 wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - rfc822Name", pos, len);
859 os_free(name->alt_email);
860 name->alt_email = os_zalloc(len + 1);
861 if (name->alt_email == NULL)
862 return -1;
863 os_memcpy(name->alt_email, pos, len);
864 if (os_strlen(name->alt_email) != len) {
865 wpa_printf(MSG_INFO, "X509: Reject certificate with "
866 "embedded NUL byte in rfc822Name (%s[NUL])",
867 name->alt_email);
868 os_free(name->alt_email);
869 name->alt_email = NULL;
870 return -1;
871 }
872 return 0;
873}
874
875
876static int x509_parse_alt_name_dns(struct x509_name *name,
877 const u8 *pos, size_t len)
878{
879 /* dNSName IA5String */
880 wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - dNSName", pos, len);
881 os_free(name->dns);
882 name->dns = os_zalloc(len + 1);
883 if (name->dns == NULL)
884 return -1;
885 os_memcpy(name->dns, pos, len);
886 if (os_strlen(name->dns) != len) {
887 wpa_printf(MSG_INFO, "X509: Reject certificate with "
888 "embedded NUL byte in dNSName (%s[NUL])",
889 name->dns);
890 os_free(name->dns);
891 name->dns = NULL;
892 return -1;
893 }
894 return 0;
895}
896
897
898static int x509_parse_alt_name_uri(struct x509_name *name,
899 const u8 *pos, size_t len)
900{
901 /* uniformResourceIdentifier IA5String */
902 wpa_hexdump_ascii(MSG_MSGDUMP,
903 "X509: altName - uniformResourceIdentifier",
904 pos, len);
905 os_free(name->uri);
906 name->uri = os_zalloc(len + 1);
907 if (name->uri == NULL)
908 return -1;
909 os_memcpy(name->uri, pos, len);
910 if (os_strlen(name->uri) != len) {
911 wpa_printf(MSG_INFO, "X509: Reject certificate with "
912 "embedded NUL byte in uniformResourceIdentifier "
913 "(%s[NUL])", name->uri);
914 os_free(name->uri);
915 name->uri = NULL;
916 return -1;
917 }
918 return 0;
919}
920
921
922static int x509_parse_alt_name_ip(struct x509_name *name,
923 const u8 *pos, size_t len)
924{
925 /* iPAddress OCTET STRING */
926 wpa_hexdump(MSG_MSGDUMP, "X509: altName - iPAddress", pos, len);
927 os_free(name->ip);
928 name->ip = os_malloc(len);
929 if (name->ip == NULL)
930 return -1;
931 os_memcpy(name->ip, pos, len);
932 name->ip_len = len;
933 return 0;
934}
935
936
937static int x509_parse_alt_name_rid(struct x509_name *name,
938 const u8 *pos, size_t len)
939{
940 char buf[80];
941
942 /* registeredID OBJECT IDENTIFIER */
943 if (asn1_parse_oid(pos, len, &name->rid) < 0)
944 return -1;
945
946 asn1_oid_to_str(&name->rid, buf, sizeof(buf));
947 wpa_printf(MSG_MSGDUMP, "X509: altName - registeredID: %s", buf);
948
949 return 0;
950}
951
952
953static int x509_parse_ext_alt_name(struct x509_name *name,
954 const u8 *pos, size_t len)
955{
956 struct asn1_hdr hdr;
957 const u8 *p, *end;
958
959 /*
960 * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
961 *
962 * GeneralName ::= CHOICE {
963 * otherName [0] OtherName,
964 * rfc822Name [1] IA5String,
965 * dNSName [2] IA5String,
966 * x400Address [3] ORAddress,
967 * directoryName [4] Name,
968 * ediPartyName [5] EDIPartyName,
969 * uniformResourceIdentifier [6] IA5String,
970 * iPAddress [7] OCTET STRING,
971 * registeredID [8] OBJECT IDENTIFIER }
972 *
973 * OtherName ::= SEQUENCE {
974 * type-id OBJECT IDENTIFIER,
975 * value [0] EXPLICIT ANY DEFINED BY type-id }
976 *
977 * EDIPartyName ::= SEQUENCE {
978 * nameAssigner [0] DirectoryString OPTIONAL,
979 * partyName [1] DirectoryString }
980 */
981
982 for (p = pos, end = pos + len; p < end; p = hdr.payload + hdr.length) {
983 int res;
984
985 if (asn1_get_next(p, end - p, &hdr) < 0) {
986 wpa_printf(MSG_DEBUG, "X509: Failed to parse "
987 "SubjectAltName item");
988 return -1;
989 }
990
991 if (hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC)
992 continue;
993
994 switch (hdr.tag) {
995 case 1:
996 res = x509_parse_alt_name_rfc8222(name, hdr.payload,
997 hdr.length);
998 break;
999 case 2:
1000 res = x509_parse_alt_name_dns(name, hdr.payload,
1001 hdr.length);
1002 break;
1003 case 6:
1004 res = x509_parse_alt_name_uri(name, hdr.payload,
1005 hdr.length);
1006 break;
1007 case 7:
1008 res = x509_parse_alt_name_ip(name, hdr.payload,
1009 hdr.length);
1010 break;
1011 case 8:
1012 res = x509_parse_alt_name_rid(name, hdr.payload,
1013 hdr.length);
1014 break;
1015 case 0: /* TODO: otherName */
1016 case 3: /* TODO: x500Address */
1017 case 4: /* TODO: directoryName */
1018 case 5: /* TODO: ediPartyName */
1019 default:
1020 res = 0;
1021 break;
1022 }
1023 if (res < 0)
1024 return res;
1025 }
1026
1027 return 0;
1028}
1029
1030
1031static int x509_parse_ext_subject_alt_name(struct x509_certificate *cert,
1032 const u8 *pos, size_t len)
1033{
1034 struct asn1_hdr hdr;
1035
1036 /* SubjectAltName ::= GeneralNames */
1037
1038 if (asn1_get_next(pos, len, &hdr) < 0 ||
1039 hdr.class != ASN1_CLASS_UNIVERSAL ||
1040 hdr.tag != ASN1_TAG_SEQUENCE) {
1041 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
1042 "SubjectAltName; found %d tag 0x%x",
1043 hdr.class, hdr.tag);
1044 return -1;
1045 }
1046
1047 wpa_printf(MSG_DEBUG, "X509: SubjectAltName");
1048 cert->extensions_present |= X509_EXT_SUBJECT_ALT_NAME;
1049
1050 if (hdr.length == 0)
1051 return 0;
1052
1053 return x509_parse_ext_alt_name(&cert->subject, hdr.payload,
1054 hdr.length);
1055}
1056
1057
1058static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,
1059 const u8 *pos, size_t len)
1060{
1061 struct asn1_hdr hdr;
1062
1063 /* IssuerAltName ::= GeneralNames */
1064
1065 if (asn1_get_next(pos, len, &hdr) < 0 ||
1066 hdr.class != ASN1_CLASS_UNIVERSAL ||
1067 hdr.tag != ASN1_TAG_SEQUENCE) {
1068 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
1069 "IssuerAltName; found %d tag 0x%x",
1070 hdr.class, hdr.tag);
1071 return -1;
1072 }
1073
1074 wpa_printf(MSG_DEBUG, "X509: IssuerAltName");
1075 cert->extensions_present |= X509_EXT_ISSUER_ALT_NAME;
1076
1077 if (hdr.length == 0)
1078 return 0;
1079
1080 return x509_parse_ext_alt_name(&cert->issuer, hdr.payload,
1081 hdr.length);
1082}
1083
1084
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001085static int x509_id_pkix_oid(struct asn1_oid *oid)
1086{
1087 return oid->len >= 7 &&
1088 oid->oid[0] == 1 /* iso */ &&
1089 oid->oid[1] == 3 /* identified-organization */ &&
1090 oid->oid[2] == 6 /* dod */ &&
1091 oid->oid[3] == 1 /* internet */ &&
1092 oid->oid[4] == 5 /* security */ &&
1093 oid->oid[5] == 5 /* mechanisms */ &&
1094 oid->oid[6] == 7 /* id-pkix */;
1095}
1096
1097
1098static int x509_id_kp_oid(struct asn1_oid *oid)
1099{
1100 /* id-kp */
1101 return oid->len >= 8 &&
1102 x509_id_pkix_oid(oid) &&
1103 oid->oid[7] == 3 /* id-kp */;
1104}
1105
1106
1107static int x509_id_kp_server_auth_oid(struct asn1_oid *oid)
1108{
1109 /* id-kp */
1110 return oid->len == 9 &&
1111 x509_id_kp_oid(oid) &&
1112 oid->oid[8] == 1 /* id-kp-serverAuth */;
1113}
1114
1115
1116static int x509_id_kp_client_auth_oid(struct asn1_oid *oid)
1117{
1118 /* id-kp */
1119 return oid->len == 9 &&
1120 x509_id_kp_oid(oid) &&
1121 oid->oid[8] == 2 /* id-kp-clientAuth */;
1122}
1123
1124
1125static int x509_parse_ext_ext_key_usage(struct x509_certificate *cert,
1126 const u8 *pos, size_t len)
1127{
1128 struct asn1_hdr hdr;
1129 const u8 *end;
1130 struct asn1_oid oid;
1131
1132 /*
1133 * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
1134 *
1135 * KeyPurposeId ::= OBJECT IDENTIFIER
1136 */
1137
1138 if (asn1_get_next(pos, len, &hdr) < 0 ||
1139 hdr.class != ASN1_CLASS_UNIVERSAL ||
1140 hdr.tag != ASN1_TAG_SEQUENCE) {
1141 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
1142 "(ExtKeyUsageSyntax) - found class %d tag 0x%x",
1143 hdr.class, hdr.tag);
1144 return -1;
1145 }
1146 if (hdr.length > pos + len - hdr.payload)
1147 return -1;
1148 pos = hdr.payload;
1149 end = pos + hdr.length;
1150
1151 wpa_hexdump(MSG_MSGDUMP, "X509: ExtKeyUsageSyntax", pos, end - pos);
1152
1153 while (pos < end) {
1154 char buf[80];
1155
1156 if (asn1_get_oid(pos, end - pos, &oid, &pos))
1157 return -1;
1158 if (x509_any_ext_key_usage_oid(&oid)) {
1159 os_strlcpy(buf, "anyExtendedKeyUsage", sizeof(buf));
1160 cert->ext_key_usage |= X509_EXT_KEY_USAGE_ANY;
1161 } else if (x509_id_kp_server_auth_oid(&oid)) {
1162 os_strlcpy(buf, "id-kp-serverAuth", sizeof(buf));
1163 cert->ext_key_usage |= X509_EXT_KEY_USAGE_SERVER_AUTH;
1164 } else if (x509_id_kp_client_auth_oid(&oid)) {
1165 os_strlcpy(buf, "id-kp-clientAuth", sizeof(buf));
1166 cert->ext_key_usage |= X509_EXT_KEY_USAGE_CLIENT_AUTH;
1167 } else {
1168 asn1_oid_to_str(&oid, buf, sizeof(buf));
1169 }
1170 wpa_printf(MSG_DEBUG, "ExtKeyUsage KeyPurposeId: %s", buf);
1171 }
1172
1173 cert->extensions_present |= X509_EXT_EXT_KEY_USAGE;
1174
1175 return 0;
1176}
1177
1178
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001179static int x509_parse_extension_data(struct x509_certificate *cert,
1180 struct asn1_oid *oid,
1181 const u8 *pos, size_t len)
1182{
1183 if (!x509_id_ce_oid(oid))
1184 return 1;
1185
1186 /* TODO: add other extensions required by RFC 3280, Ch 4.2:
1187 * certificate policies (section 4.2.1.5)
1188 * name constraints (section 4.2.1.11)
1189 * policy constraints (section 4.2.1.12)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001190 * inhibit any-policy (section 4.2.1.15)
1191 */
1192 switch (oid->oid[3]) {
1193 case 15: /* id-ce-keyUsage */
1194 return x509_parse_ext_key_usage(cert, pos, len);
1195 case 17: /* id-ce-subjectAltName */
1196 return x509_parse_ext_subject_alt_name(cert, pos, len);
1197 case 18: /* id-ce-issuerAltName */
1198 return x509_parse_ext_issuer_alt_name(cert, pos, len);
1199 case 19: /* id-ce-basicConstraints */
1200 return x509_parse_ext_basic_constraints(cert, pos, len);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001201 case 37: /* id-ce-extKeyUsage */
1202 return x509_parse_ext_ext_key_usage(cert, pos, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001203 default:
1204 return 1;
1205 }
1206}
1207
1208
1209static int x509_parse_extension(struct x509_certificate *cert,
1210 const u8 *pos, size_t len, const u8 **next)
1211{
1212 const u8 *end;
1213 struct asn1_hdr hdr;
1214 struct asn1_oid oid;
1215 int critical_ext = 0, res;
1216 char buf[80];
1217
1218 /*
1219 * Extension ::= SEQUENCE {
1220 * extnID OBJECT IDENTIFIER,
1221 * critical BOOLEAN DEFAULT FALSE,
1222 * extnValue OCTET STRING
1223 * }
1224 */
1225
1226 if (asn1_get_next(pos, len, &hdr) < 0 ||
1227 hdr.class != ASN1_CLASS_UNIVERSAL ||
1228 hdr.tag != ASN1_TAG_SEQUENCE) {
1229 wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
1230 "Extensions: class %d tag 0x%x; expected SEQUENCE",
1231 hdr.class, hdr.tag);
1232 return -1;
1233 }
1234 pos = hdr.payload;
1235 *next = end = pos + hdr.length;
1236
1237 if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
1238 wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data for "
1239 "Extension (expected OID)");
1240 return -1;
1241 }
1242
1243 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1244 hdr.class != ASN1_CLASS_UNIVERSAL ||
1245 (hdr.tag != ASN1_TAG_BOOLEAN &&
1246 hdr.tag != ASN1_TAG_OCTETSTRING)) {
1247 wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
1248 "Extensions: class %d tag 0x%x; expected BOOLEAN "
1249 "or OCTET STRING", hdr.class, hdr.tag);
1250 return -1;
1251 }
1252
1253 if (hdr.tag == ASN1_TAG_BOOLEAN) {
1254 if (hdr.length != 1) {
1255 wpa_printf(MSG_DEBUG, "X509: Unexpected "
1256 "Boolean length (%u)", hdr.length);
1257 return -1;
1258 }
1259 critical_ext = hdr.payload[0];
1260 pos = hdr.payload;
1261 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1262 (hdr.class != ASN1_CLASS_UNIVERSAL &&
1263 hdr.class != ASN1_CLASS_PRIVATE) ||
1264 hdr.tag != ASN1_TAG_OCTETSTRING) {
1265 wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header "
1266 "in Extensions: class %d tag 0x%x; "
1267 "expected OCTET STRING",
1268 hdr.class, hdr.tag);
1269 return -1;
1270 }
1271 }
1272
1273 asn1_oid_to_str(&oid, buf, sizeof(buf));
1274 wpa_printf(MSG_DEBUG, "X509: Extension: extnID=%s critical=%d",
1275 buf, critical_ext);
1276 wpa_hexdump(MSG_MSGDUMP, "X509: extnValue", hdr.payload, hdr.length);
1277
1278 res = x509_parse_extension_data(cert, &oid, hdr.payload, hdr.length);
1279 if (res < 0)
1280 return res;
1281 if (res == 1 && critical_ext) {
1282 wpa_printf(MSG_INFO, "X509: Unknown critical extension %s",
1283 buf);
1284 return -1;
1285 }
1286
1287 return 0;
1288}
1289
1290
1291static int x509_parse_extensions(struct x509_certificate *cert,
1292 const u8 *pos, size_t len)
1293{
1294 const u8 *end;
1295 struct asn1_hdr hdr;
1296
1297 /* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension */
1298
1299 if (asn1_get_next(pos, len, &hdr) < 0 ||
1300 hdr.class != ASN1_CLASS_UNIVERSAL ||
1301 hdr.tag != ASN1_TAG_SEQUENCE) {
1302 wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data "
1303 "for Extensions: class %d tag 0x%x; "
1304 "expected SEQUENCE", hdr.class, hdr.tag);
1305 return -1;
1306 }
1307
1308 pos = hdr.payload;
1309 end = pos + hdr.length;
1310
1311 while (pos < end) {
1312 if (x509_parse_extension(cert, pos, end - pos, &pos)
1313 < 0)
1314 return -1;
1315 }
1316
1317 return 0;
1318}
1319
1320
1321static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
1322 struct x509_certificate *cert,
1323 const u8 **next)
1324{
1325 struct asn1_hdr hdr;
1326 const u8 *pos, *end;
1327 size_t left;
1328 char sbuf[128];
1329 unsigned long value;
1330
1331 /* tbsCertificate TBSCertificate ::= SEQUENCE */
1332 if (asn1_get_next(buf, len, &hdr) < 0 ||
1333 hdr.class != ASN1_CLASS_UNIVERSAL ||
1334 hdr.tag != ASN1_TAG_SEQUENCE) {
1335 wpa_printf(MSG_DEBUG, "X509: tbsCertificate did not start "
1336 "with a valid SEQUENCE - found class %d tag 0x%x",
1337 hdr.class, hdr.tag);
1338 return -1;
1339 }
1340 pos = hdr.payload;
1341 end = *next = pos + hdr.length;
1342
1343 /*
1344 * version [0] EXPLICIT Version DEFAULT v1
1345 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
1346 */
1347 if (asn1_get_next(pos, end - pos, &hdr) < 0)
1348 return -1;
1349 pos = hdr.payload;
1350
1351 if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC) {
1352 if (asn1_get_next(pos, end - pos, &hdr) < 0)
1353 return -1;
1354
1355 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
1356 hdr.tag != ASN1_TAG_INTEGER) {
1357 wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
1358 "version field - found class %d tag 0x%x",
1359 hdr.class, hdr.tag);
1360 return -1;
1361 }
1362 if (hdr.length != 1) {
1363 wpa_printf(MSG_DEBUG, "X509: Unexpected version field "
1364 "length %u (expected 1)", hdr.length);
1365 return -1;
1366 }
1367 pos = hdr.payload;
1368 left = hdr.length;
1369 value = 0;
1370 while (left) {
1371 value <<= 8;
1372 value |= *pos++;
1373 left--;
1374 }
1375
1376 cert->version = value;
1377 if (cert->version != X509_CERT_V1 &&
1378 cert->version != X509_CERT_V2 &&
1379 cert->version != X509_CERT_V3) {
1380 wpa_printf(MSG_DEBUG, "X509: Unsupported version %d",
1381 cert->version + 1);
1382 return -1;
1383 }
1384
1385 if (asn1_get_next(pos, end - pos, &hdr) < 0)
1386 return -1;
1387 } else
1388 cert->version = X509_CERT_V1;
1389 wpa_printf(MSG_MSGDUMP, "X509: Version X.509v%d", cert->version + 1);
1390
1391 /* serialNumber CertificateSerialNumber ::= INTEGER */
1392 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
1393 hdr.tag != ASN1_TAG_INTEGER) {
1394 wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
1395 "serialNumber; class=%d tag=0x%x",
1396 hdr.class, hdr.tag);
1397 return -1;
1398 }
1399
1400 pos = hdr.payload;
1401 left = hdr.length;
1402 while (left) {
1403 cert->serial_number <<= 8;
1404 cert->serial_number |= *pos++;
1405 left--;
1406 }
1407 wpa_printf(MSG_MSGDUMP, "X509: serialNumber %lu", cert->serial_number);
1408
1409 /* signature AlgorithmIdentifier */
1410 if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature,
1411 &pos))
1412 return -1;
1413
1414 /* issuer Name */
1415 if (x509_parse_name(pos, end - pos, &cert->issuer, &pos))
1416 return -1;
1417 x509_name_string(&cert->issuer, sbuf, sizeof(sbuf));
1418 wpa_printf(MSG_MSGDUMP, "X509: issuer %s", sbuf);
1419
1420 /* validity Validity */
1421 if (x509_parse_validity(pos, end - pos, cert, &pos))
1422 return -1;
1423
1424 /* subject Name */
1425 if (x509_parse_name(pos, end - pos, &cert->subject, &pos))
1426 return -1;
1427 x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
1428 wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf);
1429
1430 /* subjectPublicKeyInfo SubjectPublicKeyInfo */
1431 if (x509_parse_public_key(pos, end - pos, cert, &pos))
1432 return -1;
1433
1434 if (pos == end)
1435 return 0;
1436
1437 if (cert->version == X509_CERT_V1)
1438 return 0;
1439
1440 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1441 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
1442 wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
1443 " tag to parse optional tbsCertificate "
1444 "field(s); parsed class %d tag 0x%x",
1445 hdr.class, hdr.tag);
1446 return -1;
1447 }
1448
1449 if (hdr.tag == 1) {
1450 /* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL */
1451 wpa_printf(MSG_DEBUG, "X509: issuerUniqueID");
1452 /* TODO: parse UniqueIdentifier ::= BIT STRING */
1453
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -07001454 pos = hdr.payload + hdr.length;
1455 if (pos == end)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001456 return 0;
1457
1458 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1459 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
1460 wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
1461 " tag to parse optional tbsCertificate "
1462 "field(s); parsed class %d tag 0x%x",
1463 hdr.class, hdr.tag);
1464 return -1;
1465 }
1466 }
1467
1468 if (hdr.tag == 2) {
1469 /* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL */
1470 wpa_printf(MSG_DEBUG, "X509: subjectUniqueID");
1471 /* TODO: parse UniqueIdentifier ::= BIT STRING */
1472
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -07001473 pos = hdr.payload + hdr.length;
1474 if (pos == end)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001475 return 0;
1476
1477 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1478 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
1479 wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
1480 " tag to parse optional tbsCertificate "
1481 "field(s); parsed class %d tag 0x%x",
1482 hdr.class, hdr.tag);
1483 return -1;
1484 }
1485 }
1486
1487 if (hdr.tag != 3) {
1488 wpa_printf(MSG_DEBUG, "X509: Ignored unexpected "
1489 "Context-Specific tag %d in optional "
1490 "tbsCertificate fields", hdr.tag);
1491 return 0;
1492 }
1493
1494 /* extensions [3] EXPLICIT Extensions OPTIONAL */
1495
1496 if (cert->version != X509_CERT_V3) {
1497 wpa_printf(MSG_DEBUG, "X509: X.509%d certificate and "
1498 "Extensions data which are only allowed for "
1499 "version 3", cert->version + 1);
1500 return -1;
1501 }
1502
1503 if (x509_parse_extensions(cert, hdr.payload, hdr.length) < 0)
1504 return -1;
1505
1506 pos = hdr.payload + hdr.length;
1507 if (pos < end) {
1508 wpa_hexdump(MSG_DEBUG,
1509 "X509: Ignored extra tbsCertificate data",
1510 pos, end - pos);
1511 }
1512
1513 return 0;
1514}
1515
1516
1517static int x509_rsadsi_oid(struct asn1_oid *oid)
1518{
1519 return oid->len >= 4 &&
1520 oid->oid[0] == 1 /* iso */ &&
1521 oid->oid[1] == 2 /* member-body */ &&
1522 oid->oid[2] == 840 /* us */ &&
1523 oid->oid[3] == 113549 /* rsadsi */;
1524}
1525
1526
1527static int x509_pkcs_oid(struct asn1_oid *oid)
1528{
1529 return oid->len >= 5 &&
1530 x509_rsadsi_oid(oid) &&
1531 oid->oid[4] == 1 /* pkcs */;
1532}
1533
1534
1535static int x509_digest_oid(struct asn1_oid *oid)
1536{
1537 return oid->len >= 5 &&
1538 x509_rsadsi_oid(oid) &&
1539 oid->oid[4] == 2 /* digestAlgorithm */;
1540}
1541
1542
1543static int x509_sha1_oid(struct asn1_oid *oid)
1544{
1545 return oid->len == 6 &&
1546 oid->oid[0] == 1 /* iso */ &&
1547 oid->oid[1] == 3 /* identified-organization */ &&
1548 oid->oid[2] == 14 /* oiw */ &&
1549 oid->oid[3] == 3 /* secsig */ &&
1550 oid->oid[4] == 2 /* algorithms */ &&
1551 oid->oid[5] == 26 /* id-sha1 */;
1552}
1553
1554
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001555static int x509_sha2_oid(struct asn1_oid *oid)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001556{
1557 return oid->len == 9 &&
1558 oid->oid[0] == 2 /* joint-iso-itu-t */ &&
1559 oid->oid[1] == 16 /* country */ &&
1560 oid->oid[2] == 840 /* us */ &&
1561 oid->oid[3] == 1 /* organization */ &&
1562 oid->oid[4] == 101 /* gov */ &&
1563 oid->oid[5] == 3 /* csor */ &&
1564 oid->oid[6] == 4 /* nistAlgorithm */ &&
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001565 oid->oid[7] == 2 /* hashAlgs */;
1566}
1567
1568
1569static int x509_sha256_oid(struct asn1_oid *oid)
1570{
1571 return x509_sha2_oid(oid) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001572 oid->oid[8] == 1 /* sha256 */;
1573}
1574
1575
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001576static int x509_sha384_oid(struct asn1_oid *oid)
1577{
1578 return x509_sha2_oid(oid) &&
1579 oid->oid[8] == 2 /* sha384 */;
1580}
1581
1582
1583static int x509_sha512_oid(struct asn1_oid *oid)
1584{
1585 return x509_sha2_oid(oid) &&
1586 oid->oid[8] == 3 /* sha512 */;
1587}
1588
1589
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001590/**
1591 * x509_certificate_parse - Parse a X.509 certificate in DER format
1592 * @buf: Pointer to the X.509 certificate in DER format
1593 * @len: Buffer length
1594 * Returns: Pointer to the parsed certificate or %NULL on failure
1595 *
1596 * Caller is responsible for freeing the returned certificate by calling
1597 * x509_certificate_free().
1598 */
1599struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
1600{
1601 struct asn1_hdr hdr;
1602 const u8 *pos, *end, *hash_start;
1603 struct x509_certificate *cert;
1604
1605 cert = os_zalloc(sizeof(*cert) + len);
1606 if (cert == NULL)
1607 return NULL;
1608 os_memcpy(cert + 1, buf, len);
1609 cert->cert_start = (u8 *) (cert + 1);
1610 cert->cert_len = len;
1611
1612 pos = buf;
1613 end = buf + len;
1614
1615 /* RFC 3280 - X.509 v3 certificate / ASN.1 DER */
1616
1617 /* Certificate ::= SEQUENCE */
1618 if (asn1_get_next(pos, len, &hdr) < 0 ||
1619 hdr.class != ASN1_CLASS_UNIVERSAL ||
1620 hdr.tag != ASN1_TAG_SEQUENCE) {
1621 wpa_printf(MSG_DEBUG, "X509: Certificate did not start with "
1622 "a valid SEQUENCE - found class %d tag 0x%x",
1623 hdr.class, hdr.tag);
1624 x509_certificate_free(cert);
1625 return NULL;
1626 }
1627 pos = hdr.payload;
1628
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001629 if (hdr.length > end - pos) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001630 x509_certificate_free(cert);
1631 return NULL;
1632 }
1633
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001634 if (hdr.length < end - pos) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001635 wpa_hexdump(MSG_MSGDUMP, "X509: Ignoring extra data after DER "
1636 "encoded certificate",
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -07001637 pos + hdr.length, end - (pos + hdr.length));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001638 end = pos + hdr.length;
1639 }
1640
1641 hash_start = pos;
1642 cert->tbs_cert_start = cert->cert_start + (hash_start - buf);
1643 if (x509_parse_tbs_certificate(pos, end - pos, cert, &pos)) {
1644 x509_certificate_free(cert);
1645 return NULL;
1646 }
1647 cert->tbs_cert_len = pos - hash_start;
1648
1649 /* signatureAlgorithm AlgorithmIdentifier */
1650 if (x509_parse_algorithm_identifier(pos, end - pos,
1651 &cert->signature_alg, &pos)) {
1652 x509_certificate_free(cert);
1653 return NULL;
1654 }
1655
1656 /* signatureValue BIT STRING */
1657 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1658 hdr.class != ASN1_CLASS_UNIVERSAL ||
1659 hdr.tag != ASN1_TAG_BITSTRING) {
1660 wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING "
1661 "(signatureValue) - found class %d tag 0x%x",
1662 hdr.class, hdr.tag);
1663 x509_certificate_free(cert);
1664 return NULL;
1665 }
1666 if (hdr.length < 1) {
1667 x509_certificate_free(cert);
1668 return NULL;
1669 }
1670 pos = hdr.payload;
1671 if (*pos) {
1672 wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits",
1673 *pos);
1674 /* PKCS #1 v1.5 10.2.1:
1675 * It is an error if the length in bits of the signature S is
1676 * not a multiple of eight.
1677 */
1678 x509_certificate_free(cert);
1679 return NULL;
1680 }
1681 os_free(cert->sign_value);
1682 cert->sign_value = os_malloc(hdr.length - 1);
1683 if (cert->sign_value == NULL) {
1684 wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
1685 "signatureValue");
1686 x509_certificate_free(cert);
1687 return NULL;
1688 }
1689 os_memcpy(cert->sign_value, pos + 1, hdr.length - 1);
1690 cert->sign_value_len = hdr.length - 1;
1691 wpa_hexdump(MSG_MSGDUMP, "X509: signature",
1692 cert->sign_value, cert->sign_value_len);
1693
1694 return cert;
1695}
1696
1697
1698/**
1699 * x509_certificate_check_signature - Verify certificate signature
1700 * @issuer: Issuer certificate
1701 * @cert: Certificate to be verified
1702 * Returns: 0 if cert has a valid signature that was signed by the issuer,
1703 * -1 if not
1704 */
1705int x509_certificate_check_signature(struct x509_certificate *issuer,
1706 struct x509_certificate *cert)
1707{
1708 struct crypto_public_key *pk;
1709 u8 *data;
1710 const u8 *pos, *end, *next, *da_end;
1711 size_t data_len;
1712 struct asn1_hdr hdr;
1713 struct asn1_oid oid;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001714 u8 hash[64];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001715 size_t hash_len;
1716
1717 if (!x509_pkcs_oid(&cert->signature.oid) ||
1718 cert->signature.oid.len != 7 ||
1719 cert->signature.oid.oid[5] != 1 /* pkcs-1 */) {
1720 wpa_printf(MSG_DEBUG, "X509: Unrecognized signature "
1721 "algorithm");
1722 return -1;
1723 }
1724
1725 pk = crypto_public_key_import(issuer->public_key,
1726 issuer->public_key_len);
1727 if (pk == NULL)
1728 return -1;
1729
1730 data_len = cert->sign_value_len;
1731 data = os_malloc(data_len);
1732 if (data == NULL) {
1733 crypto_public_key_free(pk);
1734 return -1;
1735 }
1736
1737 if (crypto_public_key_decrypt_pkcs1(pk, cert->sign_value,
1738 cert->sign_value_len, data,
1739 &data_len) < 0) {
1740 wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature");
1741 crypto_public_key_free(pk);
1742 os_free(data);
1743 return -1;
1744 }
1745 crypto_public_key_free(pk);
1746
1747 wpa_hexdump(MSG_MSGDUMP, "X509: Signature data D", data, data_len);
1748
1749 /*
1750 * PKCS #1 v1.5, 10.1.2:
1751 *
1752 * DigestInfo ::= SEQUENCE {
1753 * digestAlgorithm DigestAlgorithmIdentifier,
1754 * digest Digest
1755 * }
1756 *
1757 * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
1758 *
1759 * Digest ::= OCTET STRING
1760 *
1761 */
1762 if (asn1_get_next(data, data_len, &hdr) < 0 ||
1763 hdr.class != ASN1_CLASS_UNIVERSAL ||
1764 hdr.tag != ASN1_TAG_SEQUENCE) {
1765 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
1766 "(DigestInfo) - found class %d tag 0x%x",
1767 hdr.class, hdr.tag);
1768 os_free(data);
1769 return -1;
1770 }
1771
1772 pos = hdr.payload;
1773 end = pos + hdr.length;
1774
1775 /*
1776 * X.509:
1777 * AlgorithmIdentifier ::= SEQUENCE {
1778 * algorithm OBJECT IDENTIFIER,
1779 * parameters ANY DEFINED BY algorithm OPTIONAL
1780 * }
1781 */
1782
1783 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1784 hdr.class != ASN1_CLASS_UNIVERSAL ||
1785 hdr.tag != ASN1_TAG_SEQUENCE) {
1786 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
1787 "(AlgorithmIdentifier) - found class %d tag 0x%x",
1788 hdr.class, hdr.tag);
1789 os_free(data);
1790 return -1;
1791 }
1792 da_end = hdr.payload + hdr.length;
1793
1794 if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) {
1795 wpa_printf(MSG_DEBUG, "X509: Failed to parse digestAlgorithm");
1796 os_free(data);
1797 return -1;
1798 }
1799
1800 if (x509_sha1_oid(&oid)) {
1801 if (cert->signature.oid.oid[6] !=
1802 5 /* sha-1WithRSAEncryption */) {
1803 wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA1 "
1804 "does not match with certificate "
1805 "signatureAlgorithm (%lu)",
1806 cert->signature.oid.oid[6]);
1807 os_free(data);
1808 return -1;
1809 }
1810 goto skip_digest_oid;
1811 }
1812
1813 if (x509_sha256_oid(&oid)) {
1814 if (cert->signature.oid.oid[6] !=
1815 11 /* sha2561WithRSAEncryption */) {
1816 wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA256 "
1817 "does not match with certificate "
1818 "signatureAlgorithm (%lu)",
1819 cert->signature.oid.oid[6]);
1820 os_free(data);
1821 return -1;
1822 }
1823 goto skip_digest_oid;
1824 }
1825
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001826 if (x509_sha384_oid(&oid)) {
1827 if (cert->signature.oid.oid[6] !=
1828 12 /* sha384WithRSAEncryption */) {
1829 wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA384 "
1830 "does not match with certificate "
1831 "signatureAlgorithm (%lu)",
1832 cert->signature.oid.oid[6]);
1833 os_free(data);
1834 return -1;
1835 }
1836 goto skip_digest_oid;
1837 }
1838
1839 if (x509_sha512_oid(&oid)) {
1840 if (cert->signature.oid.oid[6] !=
1841 13 /* sha512WithRSAEncryption */) {
1842 wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA512 "
1843 "does not match with certificate "
1844 "signatureAlgorithm (%lu)",
1845 cert->signature.oid.oid[6]);
1846 os_free(data);
1847 return -1;
1848 }
1849 goto skip_digest_oid;
1850 }
1851
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001852 if (!x509_digest_oid(&oid)) {
1853 wpa_printf(MSG_DEBUG, "X509: Unrecognized digestAlgorithm");
1854 os_free(data);
1855 return -1;
1856 }
1857 switch (oid.oid[5]) {
1858 case 5: /* md5 */
1859 if (cert->signature.oid.oid[6] != 4 /* md5WithRSAEncryption */)
1860 {
1861 wpa_printf(MSG_DEBUG, "X509: digestAlgorithm MD5 does "
1862 "not match with certificate "
1863 "signatureAlgorithm (%lu)",
1864 cert->signature.oid.oid[6]);
1865 os_free(data);
1866 return -1;
1867 }
1868 break;
1869 case 2: /* md2 */
1870 case 4: /* md4 */
1871 default:
1872 wpa_printf(MSG_DEBUG, "X509: Unsupported digestAlgorithm "
1873 "(%lu)", oid.oid[5]);
1874 os_free(data);
1875 return -1;
1876 }
1877
1878skip_digest_oid:
1879 /* Digest ::= OCTET STRING */
1880 pos = da_end;
1881 end = data + data_len;
1882
1883 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1884 hdr.class != ASN1_CLASS_UNIVERSAL ||
1885 hdr.tag != ASN1_TAG_OCTETSTRING) {
1886 wpa_printf(MSG_DEBUG, "X509: Expected OCTETSTRING "
1887 "(Digest) - found class %d tag 0x%x",
1888 hdr.class, hdr.tag);
1889 os_free(data);
1890 return -1;
1891 }
1892 wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest",
1893 hdr.payload, hdr.length);
1894
1895 switch (cert->signature.oid.oid[6]) {
1896 case 4: /* md5WithRSAEncryption */
1897 md5_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
1898 hash);
1899 hash_len = 16;
1900 wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (MD5)",
1901 hash, hash_len);
1902 break;
1903 case 5: /* sha-1WithRSAEncryption */
1904 sha1_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
1905 hash);
1906 hash_len = 20;
1907 wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA1)",
1908 hash, hash_len);
1909 break;
1910 case 11: /* sha256WithRSAEncryption */
1911 sha256_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
1912 hash);
1913 hash_len = 32;
1914 wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)",
1915 hash, hash_len);
1916 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001917 case 12: /* sha384WithRSAEncryption */
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001918 sha384_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
1919 hash);
1920 hash_len = 48;
1921 wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA384)",
1922 hash, hash_len);
1923 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001924 case 13: /* sha512WithRSAEncryption */
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001925 sha512_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
1926 hash);
1927 hash_len = 64;
1928 wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA512)",
1929 hash, hash_len);
1930 break;
1931 case 2: /* md2WithRSAEncryption */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001932 default:
1933 wpa_printf(MSG_INFO, "X509: Unsupported certificate signature "
1934 "algorithm (%lu)", cert->signature.oid.oid[6]);
1935 os_free(data);
1936 return -1;
1937 }
1938
1939 if (hdr.length != hash_len ||
Dmitry Shmidtc2817022014-07-02 10:32:10 -07001940 os_memcmp_const(hdr.payload, hash, hdr.length) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001941 wpa_printf(MSG_INFO, "X509: Certificate Digest does not match "
1942 "with calculated tbsCertificate hash");
1943 os_free(data);
1944 return -1;
1945 }
1946
Dmitry Shmidt50b691d2014-05-21 14:01:45 -07001947 if (hdr.payload + hdr.length < data + data_len) {
1948 wpa_hexdump(MSG_INFO,
1949 "X509: Extra data after certificate signature hash",
1950 hdr.payload + hdr.length,
1951 data + data_len - hdr.payload - hdr.length);
1952 os_free(data);
1953 return -1;
1954 }
1955
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001956 os_free(data);
1957
1958 wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with "
1959 "calculated tbsCertificate hash");
1960
1961 return 0;
1962}
1963
1964
1965static int x509_valid_issuer(const struct x509_certificate *cert)
1966{
1967 if ((cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS) &&
1968 !cert->ca) {
1969 wpa_printf(MSG_DEBUG, "X509: Non-CA certificate used as an "
1970 "issuer");
1971 return -1;
1972 }
1973
1974 if (cert->version == X509_CERT_V3 &&
1975 !(cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS)) {
1976 wpa_printf(MSG_DEBUG, "X509: v3 CA certificate did not "
1977 "include BasicConstraints extension");
1978 return -1;
1979 }
1980
1981 if ((cert->extensions_present & X509_EXT_KEY_USAGE) &&
1982 !(cert->key_usage & X509_KEY_USAGE_KEY_CERT_SIGN)) {
1983 wpa_printf(MSG_DEBUG, "X509: Issuer certificate did not have "
1984 "keyCertSign bit in Key Usage");
1985 return -1;
1986 }
1987
1988 return 0;
1989}
1990
1991
1992/**
1993 * x509_certificate_chain_validate - Validate X.509 certificate chain
1994 * @trusted: List of trusted certificates
1995 * @chain: Certificate chain to be validated (first chain must be issued by
1996 * signed by the second certificate in the chain and so on)
1997 * @reason: Buffer for returning failure reason (X509_VALIDATE_*)
1998 * Returns: 0 if chain is valid, -1 if not
1999 */
2000int x509_certificate_chain_validate(struct x509_certificate *trusted,
2001 struct x509_certificate *chain,
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07002002 int *reason, int disable_time_checks)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002003{
2004 long unsigned idx;
2005 int chain_trusted = 0;
2006 struct x509_certificate *cert, *trust;
2007 char buf[128];
2008 struct os_time now;
2009
2010 *reason = X509_VALIDATE_OK;
2011
2012 wpa_printf(MSG_DEBUG, "X509: Validate certificate chain");
2013 os_get_time(&now);
2014
2015 for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
2016 x509_name_string(&cert->subject, buf, sizeof(buf));
2017 wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
2018
2019 if (chain_trusted)
2020 continue;
2021
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07002022 if (!disable_time_checks &&
2023 ((unsigned long) now.sec <
2024 (unsigned long) cert->not_before ||
2025 (unsigned long) now.sec >
2026 (unsigned long) cert->not_after)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002027 wpa_printf(MSG_INFO, "X509: Certificate not valid "
2028 "(now=%lu not_before=%lu not_after=%lu)",
2029 now.sec, cert->not_before, cert->not_after);
2030 *reason = X509_VALIDATE_CERTIFICATE_EXPIRED;
2031 return -1;
2032 }
2033
2034 if (cert->next) {
2035 if (x509_name_compare(&cert->issuer,
2036 &cert->next->subject) != 0) {
2037 wpa_printf(MSG_DEBUG, "X509: Certificate "
2038 "chain issuer name mismatch");
2039 x509_name_string(&cert->issuer, buf,
2040 sizeof(buf));
2041 wpa_printf(MSG_DEBUG, "X509: cert issuer: %s",
2042 buf);
2043 x509_name_string(&cert->next->subject, buf,
2044 sizeof(buf));
2045 wpa_printf(MSG_DEBUG, "X509: next cert "
2046 "subject: %s", buf);
2047 *reason = X509_VALIDATE_CERTIFICATE_UNKNOWN;
2048 return -1;
2049 }
2050
2051 if (x509_valid_issuer(cert->next) < 0) {
2052 *reason = X509_VALIDATE_BAD_CERTIFICATE;
2053 return -1;
2054 }
2055
2056 if ((cert->next->extensions_present &
2057 X509_EXT_PATH_LEN_CONSTRAINT) &&
2058 idx > cert->next->path_len_constraint) {
2059 wpa_printf(MSG_DEBUG, "X509: pathLenConstraint"
2060 " not met (idx=%lu issuer "
2061 "pathLenConstraint=%lu)", idx,
2062 cert->next->path_len_constraint);
2063 *reason = X509_VALIDATE_BAD_CERTIFICATE;
2064 return -1;
2065 }
2066
2067 if (x509_certificate_check_signature(cert->next, cert)
2068 < 0) {
2069 wpa_printf(MSG_DEBUG, "X509: Invalid "
2070 "certificate signature within "
2071 "chain");
2072 *reason = X509_VALIDATE_BAD_CERTIFICATE;
2073 return -1;
2074 }
2075 }
2076
2077 for (trust = trusted; trust; trust = trust->next) {
2078 if (x509_name_compare(&cert->issuer, &trust->subject)
2079 == 0)
2080 break;
2081 }
2082
2083 if (trust) {
2084 wpa_printf(MSG_DEBUG, "X509: Found issuer from the "
2085 "list of trusted certificates");
2086 if (x509_valid_issuer(trust) < 0) {
2087 *reason = X509_VALIDATE_BAD_CERTIFICATE;
2088 return -1;
2089 }
2090
2091 if (x509_certificate_check_signature(trust, cert) < 0)
2092 {
2093 wpa_printf(MSG_DEBUG, "X509: Invalid "
2094 "certificate signature");
2095 *reason = X509_VALIDATE_BAD_CERTIFICATE;
2096 return -1;
2097 }
2098
2099 wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
2100 "found to complete the chain");
2101 chain_trusted = 1;
2102 }
2103 }
2104
2105 if (!chain_trusted) {
2106 wpa_printf(MSG_DEBUG, "X509: Did not find any of the issuers "
2107 "from the list of trusted certificates");
2108 if (trusted) {
2109 *reason = X509_VALIDATE_UNKNOWN_CA;
2110 return -1;
2111 }
2112 wpa_printf(MSG_DEBUG, "X509: Certificate chain validation "
2113 "disabled - ignore unknown CA issue");
2114 }
2115
2116 wpa_printf(MSG_DEBUG, "X509: Certificate chain valid");
2117
2118 return 0;
2119}
2120
2121
2122/**
2123 * x509_certificate_get_subject - Get a certificate based on Subject name
2124 * @chain: Certificate chain to search through
2125 * @name: Subject name to search for
2126 * Returns: Pointer to the certificate with the given Subject name or
2127 * %NULL on failure
2128 */
2129struct x509_certificate *
2130x509_certificate_get_subject(struct x509_certificate *chain,
2131 struct x509_name *name)
2132{
2133 struct x509_certificate *cert;
2134
2135 for (cert = chain; cert; cert = cert->next) {
2136 if (x509_name_compare(&cert->subject, name) == 0)
2137 return cert;
2138 }
2139 return NULL;
2140}
2141
2142
2143/**
2144 * x509_certificate_self_signed - Is the certificate self-signed?
2145 * @cert: Certificate
2146 * Returns: 1 if certificate is self-signed, 0 if not
2147 */
2148int x509_certificate_self_signed(struct x509_certificate *cert)
2149{
2150 return x509_name_compare(&cert->issuer, &cert->subject) == 0;
2151}