blob: e7b7c4115c12b3ab0a0a53935d5f1a91a53edbc8 [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
723static int x509_parse_ext_key_usage(struct x509_certificate *cert,
724 const u8 *pos, size_t len)
725{
726 struct asn1_hdr hdr;
727
728 /*
729 * KeyUsage ::= BIT STRING {
730 * digitalSignature (0),
731 * nonRepudiation (1),
732 * keyEncipherment (2),
733 * dataEncipherment (3),
734 * keyAgreement (4),
735 * keyCertSign (5),
736 * cRLSign (6),
737 * encipherOnly (7),
738 * decipherOnly (8) }
739 */
740
741 if (asn1_get_next(pos, len, &hdr) < 0 ||
742 hdr.class != ASN1_CLASS_UNIVERSAL ||
743 hdr.tag != ASN1_TAG_BITSTRING ||
744 hdr.length < 1) {
745 wpa_printf(MSG_DEBUG, "X509: Expected BIT STRING in "
746 "KeyUsage; found %d tag 0x%x len %d",
747 hdr.class, hdr.tag, hdr.length);
748 return -1;
749 }
750
751 cert->extensions_present |= X509_EXT_KEY_USAGE;
752 cert->key_usage = asn1_bit_string_to_long(hdr.payload, hdr.length);
753
754 wpa_printf(MSG_DEBUG, "X509: KeyUsage 0x%lx", cert->key_usage);
755
756 return 0;
757}
758
759
760static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,
761 const u8 *pos, size_t len)
762{
763 struct asn1_hdr hdr;
764 unsigned long value;
765 size_t left;
766
767 /*
768 * BasicConstraints ::= SEQUENCE {
769 * cA BOOLEAN DEFAULT FALSE,
770 * pathLenConstraint INTEGER (0..MAX) OPTIONAL }
771 */
772
773 if (asn1_get_next(pos, len, &hdr) < 0 ||
774 hdr.class != ASN1_CLASS_UNIVERSAL ||
775 hdr.tag != ASN1_TAG_SEQUENCE) {
776 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
777 "BasicConstraints; found %d tag 0x%x",
778 hdr.class, hdr.tag);
779 return -1;
780 }
781
782 cert->extensions_present |= X509_EXT_BASIC_CONSTRAINTS;
783
784 if (hdr.length == 0)
785 return 0;
786
787 if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
788 hdr.class != ASN1_CLASS_UNIVERSAL) {
789 wpa_printf(MSG_DEBUG, "X509: Failed to parse "
790 "BasicConstraints");
791 return -1;
792 }
793
794 if (hdr.tag == ASN1_TAG_BOOLEAN) {
795 if (hdr.length != 1) {
796 wpa_printf(MSG_DEBUG, "X509: Unexpected "
797 "Boolean length (%u) in BasicConstraints",
798 hdr.length);
799 return -1;
800 }
801 cert->ca = hdr.payload[0];
802
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800803 if (hdr.length == pos + len - hdr.payload) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700804 wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d",
805 cert->ca);
806 return 0;
807 }
808
809 if (asn1_get_next(hdr.payload + hdr.length, len - hdr.length,
810 &hdr) < 0 ||
811 hdr.class != ASN1_CLASS_UNIVERSAL) {
812 wpa_printf(MSG_DEBUG, "X509: Failed to parse "
813 "BasicConstraints");
814 return -1;
815 }
816 }
817
818 if (hdr.tag != ASN1_TAG_INTEGER) {
819 wpa_printf(MSG_DEBUG, "X509: Expected INTEGER in "
820 "BasicConstraints; found class %d tag 0x%x",
821 hdr.class, hdr.tag);
822 return -1;
823 }
824
825 pos = hdr.payload;
826 left = hdr.length;
827 value = 0;
828 while (left) {
829 value <<= 8;
830 value |= *pos++;
831 left--;
832 }
833
834 cert->path_len_constraint = value;
835 cert->extensions_present |= X509_EXT_PATH_LEN_CONSTRAINT;
836
837 wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d "
838 "pathLenConstraint=%lu",
839 cert->ca, cert->path_len_constraint);
840
841 return 0;
842}
843
844
845static int x509_parse_alt_name_rfc8222(struct x509_name *name,
846 const u8 *pos, size_t len)
847{
848 /* rfc822Name IA5String */
849 wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - rfc822Name", pos, len);
850 os_free(name->alt_email);
851 name->alt_email = os_zalloc(len + 1);
852 if (name->alt_email == NULL)
853 return -1;
854 os_memcpy(name->alt_email, pos, len);
855 if (os_strlen(name->alt_email) != len) {
856 wpa_printf(MSG_INFO, "X509: Reject certificate with "
857 "embedded NUL byte in rfc822Name (%s[NUL])",
858 name->alt_email);
859 os_free(name->alt_email);
860 name->alt_email = NULL;
861 return -1;
862 }
863 return 0;
864}
865
866
867static int x509_parse_alt_name_dns(struct x509_name *name,
868 const u8 *pos, size_t len)
869{
870 /* dNSName IA5String */
871 wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - dNSName", pos, len);
872 os_free(name->dns);
873 name->dns = os_zalloc(len + 1);
874 if (name->dns == NULL)
875 return -1;
876 os_memcpy(name->dns, pos, len);
877 if (os_strlen(name->dns) != len) {
878 wpa_printf(MSG_INFO, "X509: Reject certificate with "
879 "embedded NUL byte in dNSName (%s[NUL])",
880 name->dns);
881 os_free(name->dns);
882 name->dns = NULL;
883 return -1;
884 }
885 return 0;
886}
887
888
889static int x509_parse_alt_name_uri(struct x509_name *name,
890 const u8 *pos, size_t len)
891{
892 /* uniformResourceIdentifier IA5String */
893 wpa_hexdump_ascii(MSG_MSGDUMP,
894 "X509: altName - uniformResourceIdentifier",
895 pos, len);
896 os_free(name->uri);
897 name->uri = os_zalloc(len + 1);
898 if (name->uri == NULL)
899 return -1;
900 os_memcpy(name->uri, pos, len);
901 if (os_strlen(name->uri) != len) {
902 wpa_printf(MSG_INFO, "X509: Reject certificate with "
903 "embedded NUL byte in uniformResourceIdentifier "
904 "(%s[NUL])", name->uri);
905 os_free(name->uri);
906 name->uri = NULL;
907 return -1;
908 }
909 return 0;
910}
911
912
913static int x509_parse_alt_name_ip(struct x509_name *name,
914 const u8 *pos, size_t len)
915{
916 /* iPAddress OCTET STRING */
917 wpa_hexdump(MSG_MSGDUMP, "X509: altName - iPAddress", pos, len);
918 os_free(name->ip);
919 name->ip = os_malloc(len);
920 if (name->ip == NULL)
921 return -1;
922 os_memcpy(name->ip, pos, len);
923 name->ip_len = len;
924 return 0;
925}
926
927
928static int x509_parse_alt_name_rid(struct x509_name *name,
929 const u8 *pos, size_t len)
930{
931 char buf[80];
932
933 /* registeredID OBJECT IDENTIFIER */
934 if (asn1_parse_oid(pos, len, &name->rid) < 0)
935 return -1;
936
937 asn1_oid_to_str(&name->rid, buf, sizeof(buf));
938 wpa_printf(MSG_MSGDUMP, "X509: altName - registeredID: %s", buf);
939
940 return 0;
941}
942
943
944static int x509_parse_ext_alt_name(struct x509_name *name,
945 const u8 *pos, size_t len)
946{
947 struct asn1_hdr hdr;
948 const u8 *p, *end;
949
950 /*
951 * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
952 *
953 * GeneralName ::= CHOICE {
954 * otherName [0] OtherName,
955 * rfc822Name [1] IA5String,
956 * dNSName [2] IA5String,
957 * x400Address [3] ORAddress,
958 * directoryName [4] Name,
959 * ediPartyName [5] EDIPartyName,
960 * uniformResourceIdentifier [6] IA5String,
961 * iPAddress [7] OCTET STRING,
962 * registeredID [8] OBJECT IDENTIFIER }
963 *
964 * OtherName ::= SEQUENCE {
965 * type-id OBJECT IDENTIFIER,
966 * value [0] EXPLICIT ANY DEFINED BY type-id }
967 *
968 * EDIPartyName ::= SEQUENCE {
969 * nameAssigner [0] DirectoryString OPTIONAL,
970 * partyName [1] DirectoryString }
971 */
972
973 for (p = pos, end = pos + len; p < end; p = hdr.payload + hdr.length) {
974 int res;
975
976 if (asn1_get_next(p, end - p, &hdr) < 0) {
977 wpa_printf(MSG_DEBUG, "X509: Failed to parse "
978 "SubjectAltName item");
979 return -1;
980 }
981
982 if (hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC)
983 continue;
984
985 switch (hdr.tag) {
986 case 1:
987 res = x509_parse_alt_name_rfc8222(name, hdr.payload,
988 hdr.length);
989 break;
990 case 2:
991 res = x509_parse_alt_name_dns(name, hdr.payload,
992 hdr.length);
993 break;
994 case 6:
995 res = x509_parse_alt_name_uri(name, hdr.payload,
996 hdr.length);
997 break;
998 case 7:
999 res = x509_parse_alt_name_ip(name, hdr.payload,
1000 hdr.length);
1001 break;
1002 case 8:
1003 res = x509_parse_alt_name_rid(name, hdr.payload,
1004 hdr.length);
1005 break;
1006 case 0: /* TODO: otherName */
1007 case 3: /* TODO: x500Address */
1008 case 4: /* TODO: directoryName */
1009 case 5: /* TODO: ediPartyName */
1010 default:
1011 res = 0;
1012 break;
1013 }
1014 if (res < 0)
1015 return res;
1016 }
1017
1018 return 0;
1019}
1020
1021
1022static int x509_parse_ext_subject_alt_name(struct x509_certificate *cert,
1023 const u8 *pos, size_t len)
1024{
1025 struct asn1_hdr hdr;
1026
1027 /* SubjectAltName ::= GeneralNames */
1028
1029 if (asn1_get_next(pos, len, &hdr) < 0 ||
1030 hdr.class != ASN1_CLASS_UNIVERSAL ||
1031 hdr.tag != ASN1_TAG_SEQUENCE) {
1032 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
1033 "SubjectAltName; found %d tag 0x%x",
1034 hdr.class, hdr.tag);
1035 return -1;
1036 }
1037
1038 wpa_printf(MSG_DEBUG, "X509: SubjectAltName");
1039 cert->extensions_present |= X509_EXT_SUBJECT_ALT_NAME;
1040
1041 if (hdr.length == 0)
1042 return 0;
1043
1044 return x509_parse_ext_alt_name(&cert->subject, hdr.payload,
1045 hdr.length);
1046}
1047
1048
1049static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,
1050 const u8 *pos, size_t len)
1051{
1052 struct asn1_hdr hdr;
1053
1054 /* IssuerAltName ::= GeneralNames */
1055
1056 if (asn1_get_next(pos, len, &hdr) < 0 ||
1057 hdr.class != ASN1_CLASS_UNIVERSAL ||
1058 hdr.tag != ASN1_TAG_SEQUENCE) {
1059 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
1060 "IssuerAltName; found %d tag 0x%x",
1061 hdr.class, hdr.tag);
1062 return -1;
1063 }
1064
1065 wpa_printf(MSG_DEBUG, "X509: IssuerAltName");
1066 cert->extensions_present |= X509_EXT_ISSUER_ALT_NAME;
1067
1068 if (hdr.length == 0)
1069 return 0;
1070
1071 return x509_parse_ext_alt_name(&cert->issuer, hdr.payload,
1072 hdr.length);
1073}
1074
1075
1076static int x509_parse_extension_data(struct x509_certificate *cert,
1077 struct asn1_oid *oid,
1078 const u8 *pos, size_t len)
1079{
1080 if (!x509_id_ce_oid(oid))
1081 return 1;
1082
1083 /* TODO: add other extensions required by RFC 3280, Ch 4.2:
1084 * certificate policies (section 4.2.1.5)
1085 * name constraints (section 4.2.1.11)
1086 * policy constraints (section 4.2.1.12)
1087 * extended key usage (section 4.2.1.13)
1088 * inhibit any-policy (section 4.2.1.15)
1089 */
1090 switch (oid->oid[3]) {
1091 case 15: /* id-ce-keyUsage */
1092 return x509_parse_ext_key_usage(cert, pos, len);
1093 case 17: /* id-ce-subjectAltName */
1094 return x509_parse_ext_subject_alt_name(cert, pos, len);
1095 case 18: /* id-ce-issuerAltName */
1096 return x509_parse_ext_issuer_alt_name(cert, pos, len);
1097 case 19: /* id-ce-basicConstraints */
1098 return x509_parse_ext_basic_constraints(cert, pos, len);
1099 default:
1100 return 1;
1101 }
1102}
1103
1104
1105static int x509_parse_extension(struct x509_certificate *cert,
1106 const u8 *pos, size_t len, const u8 **next)
1107{
1108 const u8 *end;
1109 struct asn1_hdr hdr;
1110 struct asn1_oid oid;
1111 int critical_ext = 0, res;
1112 char buf[80];
1113
1114 /*
1115 * Extension ::= SEQUENCE {
1116 * extnID OBJECT IDENTIFIER,
1117 * critical BOOLEAN DEFAULT FALSE,
1118 * extnValue OCTET STRING
1119 * }
1120 */
1121
1122 if (asn1_get_next(pos, len, &hdr) < 0 ||
1123 hdr.class != ASN1_CLASS_UNIVERSAL ||
1124 hdr.tag != ASN1_TAG_SEQUENCE) {
1125 wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
1126 "Extensions: class %d tag 0x%x; expected SEQUENCE",
1127 hdr.class, hdr.tag);
1128 return -1;
1129 }
1130 pos = hdr.payload;
1131 *next = end = pos + hdr.length;
1132
1133 if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
1134 wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data for "
1135 "Extension (expected OID)");
1136 return -1;
1137 }
1138
1139 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1140 hdr.class != ASN1_CLASS_UNIVERSAL ||
1141 (hdr.tag != ASN1_TAG_BOOLEAN &&
1142 hdr.tag != ASN1_TAG_OCTETSTRING)) {
1143 wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
1144 "Extensions: class %d tag 0x%x; expected BOOLEAN "
1145 "or OCTET STRING", hdr.class, hdr.tag);
1146 return -1;
1147 }
1148
1149 if (hdr.tag == ASN1_TAG_BOOLEAN) {
1150 if (hdr.length != 1) {
1151 wpa_printf(MSG_DEBUG, "X509: Unexpected "
1152 "Boolean length (%u)", hdr.length);
1153 return -1;
1154 }
1155 critical_ext = hdr.payload[0];
1156 pos = hdr.payload;
1157 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1158 (hdr.class != ASN1_CLASS_UNIVERSAL &&
1159 hdr.class != ASN1_CLASS_PRIVATE) ||
1160 hdr.tag != ASN1_TAG_OCTETSTRING) {
1161 wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header "
1162 "in Extensions: class %d tag 0x%x; "
1163 "expected OCTET STRING",
1164 hdr.class, hdr.tag);
1165 return -1;
1166 }
1167 }
1168
1169 asn1_oid_to_str(&oid, buf, sizeof(buf));
1170 wpa_printf(MSG_DEBUG, "X509: Extension: extnID=%s critical=%d",
1171 buf, critical_ext);
1172 wpa_hexdump(MSG_MSGDUMP, "X509: extnValue", hdr.payload, hdr.length);
1173
1174 res = x509_parse_extension_data(cert, &oid, hdr.payload, hdr.length);
1175 if (res < 0)
1176 return res;
1177 if (res == 1 && critical_ext) {
1178 wpa_printf(MSG_INFO, "X509: Unknown critical extension %s",
1179 buf);
1180 return -1;
1181 }
1182
1183 return 0;
1184}
1185
1186
1187static int x509_parse_extensions(struct x509_certificate *cert,
1188 const u8 *pos, size_t len)
1189{
1190 const u8 *end;
1191 struct asn1_hdr hdr;
1192
1193 /* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension */
1194
1195 if (asn1_get_next(pos, len, &hdr) < 0 ||
1196 hdr.class != ASN1_CLASS_UNIVERSAL ||
1197 hdr.tag != ASN1_TAG_SEQUENCE) {
1198 wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data "
1199 "for Extensions: class %d tag 0x%x; "
1200 "expected SEQUENCE", hdr.class, hdr.tag);
1201 return -1;
1202 }
1203
1204 pos = hdr.payload;
1205 end = pos + hdr.length;
1206
1207 while (pos < end) {
1208 if (x509_parse_extension(cert, pos, end - pos, &pos)
1209 < 0)
1210 return -1;
1211 }
1212
1213 return 0;
1214}
1215
1216
1217static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
1218 struct x509_certificate *cert,
1219 const u8 **next)
1220{
1221 struct asn1_hdr hdr;
1222 const u8 *pos, *end;
1223 size_t left;
1224 char sbuf[128];
1225 unsigned long value;
1226
1227 /* tbsCertificate TBSCertificate ::= SEQUENCE */
1228 if (asn1_get_next(buf, len, &hdr) < 0 ||
1229 hdr.class != ASN1_CLASS_UNIVERSAL ||
1230 hdr.tag != ASN1_TAG_SEQUENCE) {
1231 wpa_printf(MSG_DEBUG, "X509: tbsCertificate did not start "
1232 "with a valid SEQUENCE - found class %d tag 0x%x",
1233 hdr.class, hdr.tag);
1234 return -1;
1235 }
1236 pos = hdr.payload;
1237 end = *next = pos + hdr.length;
1238
1239 /*
1240 * version [0] EXPLICIT Version DEFAULT v1
1241 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
1242 */
1243 if (asn1_get_next(pos, end - pos, &hdr) < 0)
1244 return -1;
1245 pos = hdr.payload;
1246
1247 if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC) {
1248 if (asn1_get_next(pos, end - pos, &hdr) < 0)
1249 return -1;
1250
1251 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
1252 hdr.tag != ASN1_TAG_INTEGER) {
1253 wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
1254 "version field - found class %d tag 0x%x",
1255 hdr.class, hdr.tag);
1256 return -1;
1257 }
1258 if (hdr.length != 1) {
1259 wpa_printf(MSG_DEBUG, "X509: Unexpected version field "
1260 "length %u (expected 1)", hdr.length);
1261 return -1;
1262 }
1263 pos = hdr.payload;
1264 left = hdr.length;
1265 value = 0;
1266 while (left) {
1267 value <<= 8;
1268 value |= *pos++;
1269 left--;
1270 }
1271
1272 cert->version = value;
1273 if (cert->version != X509_CERT_V1 &&
1274 cert->version != X509_CERT_V2 &&
1275 cert->version != X509_CERT_V3) {
1276 wpa_printf(MSG_DEBUG, "X509: Unsupported version %d",
1277 cert->version + 1);
1278 return -1;
1279 }
1280
1281 if (asn1_get_next(pos, end - pos, &hdr) < 0)
1282 return -1;
1283 } else
1284 cert->version = X509_CERT_V1;
1285 wpa_printf(MSG_MSGDUMP, "X509: Version X.509v%d", cert->version + 1);
1286
1287 /* serialNumber CertificateSerialNumber ::= INTEGER */
1288 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
1289 hdr.tag != ASN1_TAG_INTEGER) {
1290 wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
1291 "serialNumber; class=%d tag=0x%x",
1292 hdr.class, hdr.tag);
1293 return -1;
1294 }
1295
1296 pos = hdr.payload;
1297 left = hdr.length;
1298 while (left) {
1299 cert->serial_number <<= 8;
1300 cert->serial_number |= *pos++;
1301 left--;
1302 }
1303 wpa_printf(MSG_MSGDUMP, "X509: serialNumber %lu", cert->serial_number);
1304
1305 /* signature AlgorithmIdentifier */
1306 if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature,
1307 &pos))
1308 return -1;
1309
1310 /* issuer Name */
1311 if (x509_parse_name(pos, end - pos, &cert->issuer, &pos))
1312 return -1;
1313 x509_name_string(&cert->issuer, sbuf, sizeof(sbuf));
1314 wpa_printf(MSG_MSGDUMP, "X509: issuer %s", sbuf);
1315
1316 /* validity Validity */
1317 if (x509_parse_validity(pos, end - pos, cert, &pos))
1318 return -1;
1319
1320 /* subject Name */
1321 if (x509_parse_name(pos, end - pos, &cert->subject, &pos))
1322 return -1;
1323 x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
1324 wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf);
1325
1326 /* subjectPublicKeyInfo SubjectPublicKeyInfo */
1327 if (x509_parse_public_key(pos, end - pos, cert, &pos))
1328 return -1;
1329
1330 if (pos == end)
1331 return 0;
1332
1333 if (cert->version == X509_CERT_V1)
1334 return 0;
1335
1336 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1337 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
1338 wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
1339 " tag to parse optional tbsCertificate "
1340 "field(s); parsed class %d tag 0x%x",
1341 hdr.class, hdr.tag);
1342 return -1;
1343 }
1344
1345 if (hdr.tag == 1) {
1346 /* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL */
1347 wpa_printf(MSG_DEBUG, "X509: issuerUniqueID");
1348 /* TODO: parse UniqueIdentifier ::= BIT STRING */
1349
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -07001350 pos = hdr.payload + hdr.length;
1351 if (pos == end)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001352 return 0;
1353
1354 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1355 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
1356 wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
1357 " tag to parse optional tbsCertificate "
1358 "field(s); parsed class %d tag 0x%x",
1359 hdr.class, hdr.tag);
1360 return -1;
1361 }
1362 }
1363
1364 if (hdr.tag == 2) {
1365 /* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL */
1366 wpa_printf(MSG_DEBUG, "X509: subjectUniqueID");
1367 /* TODO: parse UniqueIdentifier ::= BIT STRING */
1368
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -07001369 pos = hdr.payload + hdr.length;
1370 if (pos == end)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001371 return 0;
1372
1373 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1374 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
1375 wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
1376 " tag to parse optional tbsCertificate "
1377 "field(s); parsed class %d tag 0x%x",
1378 hdr.class, hdr.tag);
1379 return -1;
1380 }
1381 }
1382
1383 if (hdr.tag != 3) {
1384 wpa_printf(MSG_DEBUG, "X509: Ignored unexpected "
1385 "Context-Specific tag %d in optional "
1386 "tbsCertificate fields", hdr.tag);
1387 return 0;
1388 }
1389
1390 /* extensions [3] EXPLICIT Extensions OPTIONAL */
1391
1392 if (cert->version != X509_CERT_V3) {
1393 wpa_printf(MSG_DEBUG, "X509: X.509%d certificate and "
1394 "Extensions data which are only allowed for "
1395 "version 3", cert->version + 1);
1396 return -1;
1397 }
1398
1399 if (x509_parse_extensions(cert, hdr.payload, hdr.length) < 0)
1400 return -1;
1401
1402 pos = hdr.payload + hdr.length;
1403 if (pos < end) {
1404 wpa_hexdump(MSG_DEBUG,
1405 "X509: Ignored extra tbsCertificate data",
1406 pos, end - pos);
1407 }
1408
1409 return 0;
1410}
1411
1412
1413static int x509_rsadsi_oid(struct asn1_oid *oid)
1414{
1415 return oid->len >= 4 &&
1416 oid->oid[0] == 1 /* iso */ &&
1417 oid->oid[1] == 2 /* member-body */ &&
1418 oid->oid[2] == 840 /* us */ &&
1419 oid->oid[3] == 113549 /* rsadsi */;
1420}
1421
1422
1423static int x509_pkcs_oid(struct asn1_oid *oid)
1424{
1425 return oid->len >= 5 &&
1426 x509_rsadsi_oid(oid) &&
1427 oid->oid[4] == 1 /* pkcs */;
1428}
1429
1430
1431static int x509_digest_oid(struct asn1_oid *oid)
1432{
1433 return oid->len >= 5 &&
1434 x509_rsadsi_oid(oid) &&
1435 oid->oid[4] == 2 /* digestAlgorithm */;
1436}
1437
1438
1439static int x509_sha1_oid(struct asn1_oid *oid)
1440{
1441 return oid->len == 6 &&
1442 oid->oid[0] == 1 /* iso */ &&
1443 oid->oid[1] == 3 /* identified-organization */ &&
1444 oid->oid[2] == 14 /* oiw */ &&
1445 oid->oid[3] == 3 /* secsig */ &&
1446 oid->oid[4] == 2 /* algorithms */ &&
1447 oid->oid[5] == 26 /* id-sha1 */;
1448}
1449
1450
1451static int x509_sha256_oid(struct asn1_oid *oid)
1452{
1453 return oid->len == 9 &&
1454 oid->oid[0] == 2 /* joint-iso-itu-t */ &&
1455 oid->oid[1] == 16 /* country */ &&
1456 oid->oid[2] == 840 /* us */ &&
1457 oid->oid[3] == 1 /* organization */ &&
1458 oid->oid[4] == 101 /* gov */ &&
1459 oid->oid[5] == 3 /* csor */ &&
1460 oid->oid[6] == 4 /* nistAlgorithm */ &&
1461 oid->oid[7] == 2 /* hashAlgs */ &&
1462 oid->oid[8] == 1 /* sha256 */;
1463}
1464
1465
1466/**
1467 * x509_certificate_parse - Parse a X.509 certificate in DER format
1468 * @buf: Pointer to the X.509 certificate in DER format
1469 * @len: Buffer length
1470 * Returns: Pointer to the parsed certificate or %NULL on failure
1471 *
1472 * Caller is responsible for freeing the returned certificate by calling
1473 * x509_certificate_free().
1474 */
1475struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
1476{
1477 struct asn1_hdr hdr;
1478 const u8 *pos, *end, *hash_start;
1479 struct x509_certificate *cert;
1480
1481 cert = os_zalloc(sizeof(*cert) + len);
1482 if (cert == NULL)
1483 return NULL;
1484 os_memcpy(cert + 1, buf, len);
1485 cert->cert_start = (u8 *) (cert + 1);
1486 cert->cert_len = len;
1487
1488 pos = buf;
1489 end = buf + len;
1490
1491 /* RFC 3280 - X.509 v3 certificate / ASN.1 DER */
1492
1493 /* Certificate ::= SEQUENCE */
1494 if (asn1_get_next(pos, len, &hdr) < 0 ||
1495 hdr.class != ASN1_CLASS_UNIVERSAL ||
1496 hdr.tag != ASN1_TAG_SEQUENCE) {
1497 wpa_printf(MSG_DEBUG, "X509: Certificate did not start with "
1498 "a valid SEQUENCE - found class %d tag 0x%x",
1499 hdr.class, hdr.tag);
1500 x509_certificate_free(cert);
1501 return NULL;
1502 }
1503 pos = hdr.payload;
1504
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001505 if (hdr.length > end - pos) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001506 x509_certificate_free(cert);
1507 return NULL;
1508 }
1509
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001510 if (hdr.length < end - pos) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001511 wpa_hexdump(MSG_MSGDUMP, "X509: Ignoring extra data after DER "
1512 "encoded certificate",
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -07001513 pos + hdr.length, end - (pos + hdr.length));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001514 end = pos + hdr.length;
1515 }
1516
1517 hash_start = pos;
1518 cert->tbs_cert_start = cert->cert_start + (hash_start - buf);
1519 if (x509_parse_tbs_certificate(pos, end - pos, cert, &pos)) {
1520 x509_certificate_free(cert);
1521 return NULL;
1522 }
1523 cert->tbs_cert_len = pos - hash_start;
1524
1525 /* signatureAlgorithm AlgorithmIdentifier */
1526 if (x509_parse_algorithm_identifier(pos, end - pos,
1527 &cert->signature_alg, &pos)) {
1528 x509_certificate_free(cert);
1529 return NULL;
1530 }
1531
1532 /* signatureValue BIT STRING */
1533 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1534 hdr.class != ASN1_CLASS_UNIVERSAL ||
1535 hdr.tag != ASN1_TAG_BITSTRING) {
1536 wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING "
1537 "(signatureValue) - found class %d tag 0x%x",
1538 hdr.class, hdr.tag);
1539 x509_certificate_free(cert);
1540 return NULL;
1541 }
1542 if (hdr.length < 1) {
1543 x509_certificate_free(cert);
1544 return NULL;
1545 }
1546 pos = hdr.payload;
1547 if (*pos) {
1548 wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits",
1549 *pos);
1550 /* PKCS #1 v1.5 10.2.1:
1551 * It is an error if the length in bits of the signature S is
1552 * not a multiple of eight.
1553 */
1554 x509_certificate_free(cert);
1555 return NULL;
1556 }
1557 os_free(cert->sign_value);
1558 cert->sign_value = os_malloc(hdr.length - 1);
1559 if (cert->sign_value == NULL) {
1560 wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
1561 "signatureValue");
1562 x509_certificate_free(cert);
1563 return NULL;
1564 }
1565 os_memcpy(cert->sign_value, pos + 1, hdr.length - 1);
1566 cert->sign_value_len = hdr.length - 1;
1567 wpa_hexdump(MSG_MSGDUMP, "X509: signature",
1568 cert->sign_value, cert->sign_value_len);
1569
1570 return cert;
1571}
1572
1573
1574/**
1575 * x509_certificate_check_signature - Verify certificate signature
1576 * @issuer: Issuer certificate
1577 * @cert: Certificate to be verified
1578 * Returns: 0 if cert has a valid signature that was signed by the issuer,
1579 * -1 if not
1580 */
1581int x509_certificate_check_signature(struct x509_certificate *issuer,
1582 struct x509_certificate *cert)
1583{
1584 struct crypto_public_key *pk;
1585 u8 *data;
1586 const u8 *pos, *end, *next, *da_end;
1587 size_t data_len;
1588 struct asn1_hdr hdr;
1589 struct asn1_oid oid;
1590 u8 hash[32];
1591 size_t hash_len;
1592
1593 if (!x509_pkcs_oid(&cert->signature.oid) ||
1594 cert->signature.oid.len != 7 ||
1595 cert->signature.oid.oid[5] != 1 /* pkcs-1 */) {
1596 wpa_printf(MSG_DEBUG, "X509: Unrecognized signature "
1597 "algorithm");
1598 return -1;
1599 }
1600
1601 pk = crypto_public_key_import(issuer->public_key,
1602 issuer->public_key_len);
1603 if (pk == NULL)
1604 return -1;
1605
1606 data_len = cert->sign_value_len;
1607 data = os_malloc(data_len);
1608 if (data == NULL) {
1609 crypto_public_key_free(pk);
1610 return -1;
1611 }
1612
1613 if (crypto_public_key_decrypt_pkcs1(pk, cert->sign_value,
1614 cert->sign_value_len, data,
1615 &data_len) < 0) {
1616 wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature");
1617 crypto_public_key_free(pk);
1618 os_free(data);
1619 return -1;
1620 }
1621 crypto_public_key_free(pk);
1622
1623 wpa_hexdump(MSG_MSGDUMP, "X509: Signature data D", data, data_len);
1624
1625 /*
1626 * PKCS #1 v1.5, 10.1.2:
1627 *
1628 * DigestInfo ::= SEQUENCE {
1629 * digestAlgorithm DigestAlgorithmIdentifier,
1630 * digest Digest
1631 * }
1632 *
1633 * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
1634 *
1635 * Digest ::= OCTET STRING
1636 *
1637 */
1638 if (asn1_get_next(data, data_len, &hdr) < 0 ||
1639 hdr.class != ASN1_CLASS_UNIVERSAL ||
1640 hdr.tag != ASN1_TAG_SEQUENCE) {
1641 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
1642 "(DigestInfo) - found class %d tag 0x%x",
1643 hdr.class, hdr.tag);
1644 os_free(data);
1645 return -1;
1646 }
1647
1648 pos = hdr.payload;
1649 end = pos + hdr.length;
1650
1651 /*
1652 * X.509:
1653 * AlgorithmIdentifier ::= SEQUENCE {
1654 * algorithm OBJECT IDENTIFIER,
1655 * parameters ANY DEFINED BY algorithm OPTIONAL
1656 * }
1657 */
1658
1659 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1660 hdr.class != ASN1_CLASS_UNIVERSAL ||
1661 hdr.tag != ASN1_TAG_SEQUENCE) {
1662 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
1663 "(AlgorithmIdentifier) - found class %d tag 0x%x",
1664 hdr.class, hdr.tag);
1665 os_free(data);
1666 return -1;
1667 }
1668 da_end = hdr.payload + hdr.length;
1669
1670 if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) {
1671 wpa_printf(MSG_DEBUG, "X509: Failed to parse digestAlgorithm");
1672 os_free(data);
1673 return -1;
1674 }
1675
1676 if (x509_sha1_oid(&oid)) {
1677 if (cert->signature.oid.oid[6] !=
1678 5 /* sha-1WithRSAEncryption */) {
1679 wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA1 "
1680 "does not match with certificate "
1681 "signatureAlgorithm (%lu)",
1682 cert->signature.oid.oid[6]);
1683 os_free(data);
1684 return -1;
1685 }
1686 goto skip_digest_oid;
1687 }
1688
1689 if (x509_sha256_oid(&oid)) {
1690 if (cert->signature.oid.oid[6] !=
1691 11 /* sha2561WithRSAEncryption */) {
1692 wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA256 "
1693 "does not match with certificate "
1694 "signatureAlgorithm (%lu)",
1695 cert->signature.oid.oid[6]);
1696 os_free(data);
1697 return -1;
1698 }
1699 goto skip_digest_oid;
1700 }
1701
1702 if (!x509_digest_oid(&oid)) {
1703 wpa_printf(MSG_DEBUG, "X509: Unrecognized digestAlgorithm");
1704 os_free(data);
1705 return -1;
1706 }
1707 switch (oid.oid[5]) {
1708 case 5: /* md5 */
1709 if (cert->signature.oid.oid[6] != 4 /* md5WithRSAEncryption */)
1710 {
1711 wpa_printf(MSG_DEBUG, "X509: digestAlgorithm MD5 does "
1712 "not match with certificate "
1713 "signatureAlgorithm (%lu)",
1714 cert->signature.oid.oid[6]);
1715 os_free(data);
1716 return -1;
1717 }
1718 break;
1719 case 2: /* md2 */
1720 case 4: /* md4 */
1721 default:
1722 wpa_printf(MSG_DEBUG, "X509: Unsupported digestAlgorithm "
1723 "(%lu)", oid.oid[5]);
1724 os_free(data);
1725 return -1;
1726 }
1727
1728skip_digest_oid:
1729 /* Digest ::= OCTET STRING */
1730 pos = da_end;
1731 end = data + data_len;
1732
1733 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1734 hdr.class != ASN1_CLASS_UNIVERSAL ||
1735 hdr.tag != ASN1_TAG_OCTETSTRING) {
1736 wpa_printf(MSG_DEBUG, "X509: Expected OCTETSTRING "
1737 "(Digest) - found class %d tag 0x%x",
1738 hdr.class, hdr.tag);
1739 os_free(data);
1740 return -1;
1741 }
1742 wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest",
1743 hdr.payload, hdr.length);
1744
1745 switch (cert->signature.oid.oid[6]) {
1746 case 4: /* md5WithRSAEncryption */
1747 md5_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
1748 hash);
1749 hash_len = 16;
1750 wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (MD5)",
1751 hash, hash_len);
1752 break;
1753 case 5: /* sha-1WithRSAEncryption */
1754 sha1_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
1755 hash);
1756 hash_len = 20;
1757 wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA1)",
1758 hash, hash_len);
1759 break;
1760 case 11: /* sha256WithRSAEncryption */
1761 sha256_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
1762 hash);
1763 hash_len = 32;
1764 wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)",
1765 hash, hash_len);
1766 break;
1767 case 2: /* md2WithRSAEncryption */
1768 case 12: /* sha384WithRSAEncryption */
1769 case 13: /* sha512WithRSAEncryption */
1770 default:
1771 wpa_printf(MSG_INFO, "X509: Unsupported certificate signature "
1772 "algorithm (%lu)", cert->signature.oid.oid[6]);
1773 os_free(data);
1774 return -1;
1775 }
1776
1777 if (hdr.length != hash_len ||
Dmitry Shmidtc2817022014-07-02 10:32:10 -07001778 os_memcmp_const(hdr.payload, hash, hdr.length) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001779 wpa_printf(MSG_INFO, "X509: Certificate Digest does not match "
1780 "with calculated tbsCertificate hash");
1781 os_free(data);
1782 return -1;
1783 }
1784
Dmitry Shmidt50b691d2014-05-21 14:01:45 -07001785 if (hdr.payload + hdr.length < data + data_len) {
1786 wpa_hexdump(MSG_INFO,
1787 "X509: Extra data after certificate signature hash",
1788 hdr.payload + hdr.length,
1789 data + data_len - hdr.payload - hdr.length);
1790 os_free(data);
1791 return -1;
1792 }
1793
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001794 os_free(data);
1795
1796 wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with "
1797 "calculated tbsCertificate hash");
1798
1799 return 0;
1800}
1801
1802
1803static int x509_valid_issuer(const struct x509_certificate *cert)
1804{
1805 if ((cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS) &&
1806 !cert->ca) {
1807 wpa_printf(MSG_DEBUG, "X509: Non-CA certificate used as an "
1808 "issuer");
1809 return -1;
1810 }
1811
1812 if (cert->version == X509_CERT_V3 &&
1813 !(cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS)) {
1814 wpa_printf(MSG_DEBUG, "X509: v3 CA certificate did not "
1815 "include BasicConstraints extension");
1816 return -1;
1817 }
1818
1819 if ((cert->extensions_present & X509_EXT_KEY_USAGE) &&
1820 !(cert->key_usage & X509_KEY_USAGE_KEY_CERT_SIGN)) {
1821 wpa_printf(MSG_DEBUG, "X509: Issuer certificate did not have "
1822 "keyCertSign bit in Key Usage");
1823 return -1;
1824 }
1825
1826 return 0;
1827}
1828
1829
1830/**
1831 * x509_certificate_chain_validate - Validate X.509 certificate chain
1832 * @trusted: List of trusted certificates
1833 * @chain: Certificate chain to be validated (first chain must be issued by
1834 * signed by the second certificate in the chain and so on)
1835 * @reason: Buffer for returning failure reason (X509_VALIDATE_*)
1836 * Returns: 0 if chain is valid, -1 if not
1837 */
1838int x509_certificate_chain_validate(struct x509_certificate *trusted,
1839 struct x509_certificate *chain,
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07001840 int *reason, int disable_time_checks)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001841{
1842 long unsigned idx;
1843 int chain_trusted = 0;
1844 struct x509_certificate *cert, *trust;
1845 char buf[128];
1846 struct os_time now;
1847
1848 *reason = X509_VALIDATE_OK;
1849
1850 wpa_printf(MSG_DEBUG, "X509: Validate certificate chain");
1851 os_get_time(&now);
1852
1853 for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
1854 x509_name_string(&cert->subject, buf, sizeof(buf));
1855 wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
1856
1857 if (chain_trusted)
1858 continue;
1859
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07001860 if (!disable_time_checks &&
1861 ((unsigned long) now.sec <
1862 (unsigned long) cert->not_before ||
1863 (unsigned long) now.sec >
1864 (unsigned long) cert->not_after)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001865 wpa_printf(MSG_INFO, "X509: Certificate not valid "
1866 "(now=%lu not_before=%lu not_after=%lu)",
1867 now.sec, cert->not_before, cert->not_after);
1868 *reason = X509_VALIDATE_CERTIFICATE_EXPIRED;
1869 return -1;
1870 }
1871
1872 if (cert->next) {
1873 if (x509_name_compare(&cert->issuer,
1874 &cert->next->subject) != 0) {
1875 wpa_printf(MSG_DEBUG, "X509: Certificate "
1876 "chain issuer name mismatch");
1877 x509_name_string(&cert->issuer, buf,
1878 sizeof(buf));
1879 wpa_printf(MSG_DEBUG, "X509: cert issuer: %s",
1880 buf);
1881 x509_name_string(&cert->next->subject, buf,
1882 sizeof(buf));
1883 wpa_printf(MSG_DEBUG, "X509: next cert "
1884 "subject: %s", buf);
1885 *reason = X509_VALIDATE_CERTIFICATE_UNKNOWN;
1886 return -1;
1887 }
1888
1889 if (x509_valid_issuer(cert->next) < 0) {
1890 *reason = X509_VALIDATE_BAD_CERTIFICATE;
1891 return -1;
1892 }
1893
1894 if ((cert->next->extensions_present &
1895 X509_EXT_PATH_LEN_CONSTRAINT) &&
1896 idx > cert->next->path_len_constraint) {
1897 wpa_printf(MSG_DEBUG, "X509: pathLenConstraint"
1898 " not met (idx=%lu issuer "
1899 "pathLenConstraint=%lu)", idx,
1900 cert->next->path_len_constraint);
1901 *reason = X509_VALIDATE_BAD_CERTIFICATE;
1902 return -1;
1903 }
1904
1905 if (x509_certificate_check_signature(cert->next, cert)
1906 < 0) {
1907 wpa_printf(MSG_DEBUG, "X509: Invalid "
1908 "certificate signature within "
1909 "chain");
1910 *reason = X509_VALIDATE_BAD_CERTIFICATE;
1911 return -1;
1912 }
1913 }
1914
1915 for (trust = trusted; trust; trust = trust->next) {
1916 if (x509_name_compare(&cert->issuer, &trust->subject)
1917 == 0)
1918 break;
1919 }
1920
1921 if (trust) {
1922 wpa_printf(MSG_DEBUG, "X509: Found issuer from the "
1923 "list of trusted certificates");
1924 if (x509_valid_issuer(trust) < 0) {
1925 *reason = X509_VALIDATE_BAD_CERTIFICATE;
1926 return -1;
1927 }
1928
1929 if (x509_certificate_check_signature(trust, cert) < 0)
1930 {
1931 wpa_printf(MSG_DEBUG, "X509: Invalid "
1932 "certificate signature");
1933 *reason = X509_VALIDATE_BAD_CERTIFICATE;
1934 return -1;
1935 }
1936
1937 wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
1938 "found to complete the chain");
1939 chain_trusted = 1;
1940 }
1941 }
1942
1943 if (!chain_trusted) {
1944 wpa_printf(MSG_DEBUG, "X509: Did not find any of the issuers "
1945 "from the list of trusted certificates");
1946 if (trusted) {
1947 *reason = X509_VALIDATE_UNKNOWN_CA;
1948 return -1;
1949 }
1950 wpa_printf(MSG_DEBUG, "X509: Certificate chain validation "
1951 "disabled - ignore unknown CA issue");
1952 }
1953
1954 wpa_printf(MSG_DEBUG, "X509: Certificate chain valid");
1955
1956 return 0;
1957}
1958
1959
1960/**
1961 * x509_certificate_get_subject - Get a certificate based on Subject name
1962 * @chain: Certificate chain to search through
1963 * @name: Subject name to search for
1964 * Returns: Pointer to the certificate with the given Subject name or
1965 * %NULL on failure
1966 */
1967struct x509_certificate *
1968x509_certificate_get_subject(struct x509_certificate *chain,
1969 struct x509_name *name)
1970{
1971 struct x509_certificate *cert;
1972
1973 for (cert = chain; cert; cert = cert->next) {
1974 if (x509_name_compare(&cert->subject, name) == 0)
1975 return cert;
1976 }
1977 return NULL;
1978}
1979
1980
1981/**
1982 * x509_certificate_self_signed - Is the certificate self-signed?
1983 * @cert: Certificate
1984 * Returns: 1 if certificate is self-signed, 0 if not
1985 */
1986int x509_certificate_self_signed(struct x509_certificate *cert)
1987{
1988 return x509_name_compare(&cert->issuer, &cert->subject) == 0;
1989}