blob: d2e685cb39c382a6a9ecfb348b5499894f9045eb [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * X.509v3 certificate parsing and processing (RFC 3280 profile)
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08003 * Copyright (c) 2006-2015, 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
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -080017void x509_free_name(struct x509_name *name)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070018{
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);
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -080058 os_free(cert->subject_dn);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070059 os_free(cert);
60}
61
62
63/**
64 * x509_certificate_free - Free an X.509 certificate chain
65 * @cert: Pointer to the first certificate in the chain
66 */
67void x509_certificate_chain_free(struct x509_certificate *cert)
68{
69 struct x509_certificate *next;
70
71 while (cert) {
72 next = cert->next;
73 cert->next = NULL;
74 x509_certificate_free(cert);
75 cert = next;
76 }
77}
78
79
80static int x509_whitespace(char c)
81{
82 return c == ' ' || c == '\t';
83}
84
85
86static void x509_str_strip_whitespace(char *a)
87{
88 char *ipos, *opos;
89 int remove_whitespace = 1;
90
91 ipos = opos = a;
92
93 while (*ipos) {
94 if (remove_whitespace && x509_whitespace(*ipos))
95 ipos++;
96 else {
97 remove_whitespace = x509_whitespace(*ipos);
98 *opos++ = *ipos++;
99 }
100 }
101
102 *opos-- = '\0';
103 if (opos > a && x509_whitespace(*opos))
104 *opos = '\0';
105}
106
107
108static int x509_str_compare(const char *a, const char *b)
109{
110 char *aa, *bb;
111 int ret;
112
113 if (!a && b)
114 return -1;
115 if (a && !b)
116 return 1;
117 if (!a && !b)
118 return 0;
119
120 aa = os_strdup(a);
121 bb = os_strdup(b);
122
123 if (aa == NULL || bb == NULL) {
124 os_free(aa);
125 os_free(bb);
126 return os_strcasecmp(a, b);
127 }
128
129 x509_str_strip_whitespace(aa);
130 x509_str_strip_whitespace(bb);
131
132 ret = os_strcasecmp(aa, bb);
133
134 os_free(aa);
135 os_free(bb);
136
137 return ret;
138}
139
140
141/**
142 * x509_name_compare - Compare X.509 certificate names
143 * @a: Certificate name
144 * @b: Certificate name
145 * Returns: <0, 0, or >0 based on whether a is less than, equal to, or
146 * greater than b
147 */
148int x509_name_compare(struct x509_name *a, struct x509_name *b)
149{
150 int res;
151 size_t i;
152
153 if (!a && b)
154 return -1;
155 if (a && !b)
156 return 1;
157 if (!a && !b)
158 return 0;
159 if (a->num_attr < b->num_attr)
160 return -1;
161 if (a->num_attr > b->num_attr)
162 return 1;
163
164 for (i = 0; i < a->num_attr; i++) {
165 if (a->attr[i].type < b->attr[i].type)
166 return -1;
167 if (a->attr[i].type > b->attr[i].type)
168 return -1;
169 res = x509_str_compare(a->attr[i].value, b->attr[i].value);
170 if (res)
171 return res;
172 }
173 res = x509_str_compare(a->email, b->email);
174 if (res)
175 return res;
176
177 return 0;
178}
179
180
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800181int x509_parse_algorithm_identifier(const u8 *buf, size_t len,
182 struct x509_algorithm_identifier *id,
183 const u8 **next)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700184{
185 struct asn1_hdr hdr;
186 const u8 *pos, *end;
187
188 /*
189 * AlgorithmIdentifier ::= SEQUENCE {
190 * algorithm OBJECT IDENTIFIER,
191 * parameters ANY DEFINED BY algorithm OPTIONAL
192 * }
193 */
194
195 if (asn1_get_next(buf, len, &hdr) < 0 ||
196 hdr.class != ASN1_CLASS_UNIVERSAL ||
197 hdr.tag != ASN1_TAG_SEQUENCE) {
198 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
199 "(AlgorithmIdentifier) - found class %d tag 0x%x",
200 hdr.class, hdr.tag);
201 return -1;
202 }
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800203 if (hdr.length > buf + len - hdr.payload)
204 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700205 pos = hdr.payload;
206 end = pos + hdr.length;
207
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700208 *next = end;
209
210 if (asn1_get_oid(pos, end - pos, &id->oid, &pos))
211 return -1;
212
213 /* TODO: optional parameters */
214
215 return 0;
216}
217
218
219static int x509_parse_public_key(const u8 *buf, size_t len,
220 struct x509_certificate *cert,
221 const u8 **next)
222{
223 struct asn1_hdr hdr;
224 const u8 *pos, *end;
225
226 /*
227 * SubjectPublicKeyInfo ::= SEQUENCE {
228 * algorithm AlgorithmIdentifier,
229 * subjectPublicKey BIT STRING
230 * }
231 */
232
233 pos = buf;
234 end = buf + len;
235
236 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
237 hdr.class != ASN1_CLASS_UNIVERSAL ||
238 hdr.tag != ASN1_TAG_SEQUENCE) {
239 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
240 "(SubjectPublicKeyInfo) - found class %d tag 0x%x",
241 hdr.class, hdr.tag);
242 return -1;
243 }
244 pos = hdr.payload;
245
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800246 if (hdr.length > end - pos)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700247 return -1;
248 end = pos + hdr.length;
249 *next = end;
250
251 if (x509_parse_algorithm_identifier(pos, end - pos,
252 &cert->public_key_alg, &pos))
253 return -1;
254
255 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
256 hdr.class != ASN1_CLASS_UNIVERSAL ||
257 hdr.tag != ASN1_TAG_BITSTRING) {
258 wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING "
259 "(subjectPublicKey) - found class %d tag 0x%x",
260 hdr.class, hdr.tag);
261 return -1;
262 }
263 if (hdr.length < 1)
264 return -1;
265 pos = hdr.payload;
266 if (*pos) {
Hai Shalomb755a2a2020-04-23 21:49:02 -0700267 wpa_printf(MSG_DEBUG,
268 "X509: BITSTRING (subjectPublicKey) - %d unused bits",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700269 *pos);
270 /*
271 * TODO: should this be rejected? X.509 certificates are
272 * unlikely to use such a construction. Now we would end up
273 * including the extra bits in the buffer which may also be
274 * ok.
275 */
276 }
277 os_free(cert->public_key);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700278 cert->public_key = os_memdup(pos + 1, hdr.length - 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700279 if (cert->public_key == NULL) {
280 wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
281 "public key");
282 return -1;
283 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700284 cert->public_key_len = hdr.length - 1;
285 wpa_hexdump(MSG_MSGDUMP, "X509: subjectPublicKey",
286 cert->public_key, cert->public_key_len);
287
288 return 0;
289}
290
291
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800292int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
293 const u8 **next)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700294{
295 struct asn1_hdr hdr;
296 const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end;
297 struct asn1_oid oid;
298 char *val;
299
300 /*
301 * Name ::= CHOICE { RDNSequence }
302 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
303 * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
304 * AttributeTypeAndValue ::= SEQUENCE {
305 * type AttributeType,
306 * value AttributeValue
307 * }
308 * AttributeType ::= OBJECT IDENTIFIER
309 * AttributeValue ::= ANY DEFINED BY AttributeType
310 */
311
312 if (asn1_get_next(buf, len, &hdr) < 0 ||
313 hdr.class != ASN1_CLASS_UNIVERSAL ||
314 hdr.tag != ASN1_TAG_SEQUENCE) {
315 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
316 "(Name / RDNSequencer) - found class %d tag 0x%x",
317 hdr.class, hdr.tag);
318 return -1;
319 }
320 pos = hdr.payload;
321
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800322 if (hdr.length > buf + len - pos)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700323 return -1;
324
325 end = *next = pos + hdr.length;
326
327 while (pos < end) {
328 enum x509_name_attr_type type;
329
330 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
331 hdr.class != ASN1_CLASS_UNIVERSAL ||
332 hdr.tag != ASN1_TAG_SET) {
333 wpa_printf(MSG_DEBUG, "X509: Expected SET "
334 "(RelativeDistinguishedName) - found class "
335 "%d tag 0x%x", hdr.class, hdr.tag);
336 x509_free_name(name);
337 return -1;
338 }
339
340 set_pos = hdr.payload;
341 pos = set_end = hdr.payload + hdr.length;
342
343 if (asn1_get_next(set_pos, set_end - set_pos, &hdr) < 0 ||
344 hdr.class != ASN1_CLASS_UNIVERSAL ||
345 hdr.tag != ASN1_TAG_SEQUENCE) {
346 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
347 "(AttributeTypeAndValue) - found class %d "
348 "tag 0x%x", hdr.class, hdr.tag);
349 x509_free_name(name);
350 return -1;
351 }
352
353 seq_pos = hdr.payload;
354 seq_end = hdr.payload + hdr.length;
355
356 if (asn1_get_oid(seq_pos, seq_end - seq_pos, &oid, &seq_pos)) {
357 x509_free_name(name);
358 return -1;
359 }
360
361 if (asn1_get_next(seq_pos, seq_end - seq_pos, &hdr) < 0 ||
362 hdr.class != ASN1_CLASS_UNIVERSAL) {
363 wpa_printf(MSG_DEBUG, "X509: Failed to parse "
364 "AttributeValue");
365 x509_free_name(name);
366 return -1;
367 }
368
369 /* RFC 3280:
370 * MUST: country, organization, organizational-unit,
371 * distinguished name qualifier, state or province name,
372 * common name, serial number.
373 * SHOULD: locality, title, surname, given name, initials,
374 * pseudonym, generation qualifier.
375 * MUST: domainComponent (RFC 2247).
376 */
377 type = X509_NAME_ATTR_NOT_USED;
378 if (oid.len == 4 &&
379 oid.oid[0] == 2 && oid.oid[1] == 5 && oid.oid[2] == 4) {
380 /* id-at ::= 2.5.4 */
381 switch (oid.oid[3]) {
382 case 3:
383 /* commonName */
384 type = X509_NAME_ATTR_CN;
385 break;
386 case 6:
387 /* countryName */
388 type = X509_NAME_ATTR_C;
389 break;
390 case 7:
391 /* localityName */
392 type = X509_NAME_ATTR_L;
393 break;
394 case 8:
395 /* stateOrProvinceName */
396 type = X509_NAME_ATTR_ST;
397 break;
398 case 10:
399 /* organizationName */
400 type = X509_NAME_ATTR_O;
401 break;
402 case 11:
403 /* organizationalUnitName */
404 type = X509_NAME_ATTR_OU;
405 break;
406 }
407 } else if (oid.len == 7 &&
408 oid.oid[0] == 1 && oid.oid[1] == 2 &&
409 oid.oid[2] == 840 && oid.oid[3] == 113549 &&
410 oid.oid[4] == 1 && oid.oid[5] == 9 &&
411 oid.oid[6] == 1) {
412 /* 1.2.840.113549.1.9.1 - e-mailAddress */
413 os_free(name->email);
414 name->email = os_malloc(hdr.length + 1);
415 if (name->email == NULL) {
416 x509_free_name(name);
417 return -1;
418 }
419 os_memcpy(name->email, hdr.payload, hdr.length);
420 name->email[hdr.length] = '\0';
421 continue;
422 } else if (oid.len == 7 &&
423 oid.oid[0] == 0 && oid.oid[1] == 9 &&
424 oid.oid[2] == 2342 && oid.oid[3] == 19200300 &&
425 oid.oid[4] == 100 && oid.oid[5] == 1 &&
426 oid.oid[6] == 25) {
427 /* 0.9.2342.19200300.100.1.25 - domainComponent */
428 type = X509_NAME_ATTR_DC;
429 }
430
431 if (type == X509_NAME_ATTR_NOT_USED) {
432 wpa_hexdump(MSG_DEBUG, "X509: Unrecognized OID",
433 (u8 *) oid.oid,
434 oid.len * sizeof(oid.oid[0]));
435 wpa_hexdump_ascii(MSG_MSGDUMP, "X509: Attribute Data",
436 hdr.payload, hdr.length);
437 continue;
438 }
439
440 if (name->num_attr == X509_MAX_NAME_ATTRIBUTES) {
441 wpa_printf(MSG_INFO, "X509: Too many Name attributes");
442 x509_free_name(name);
443 return -1;
444 }
445
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700446 val = dup_binstr(hdr.payload, hdr.length);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700447 if (val == NULL) {
448 x509_free_name(name);
449 return -1;
450 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700451 if (os_strlen(val) != hdr.length) {
452 wpa_printf(MSG_INFO, "X509: Reject certificate with "
453 "embedded NUL byte in a string (%s[NUL])",
454 val);
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700455 os_free(val);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700456 x509_free_name(name);
457 return -1;
458 }
459
460 name->attr[name->num_attr].type = type;
461 name->attr[name->num_attr].value = val;
462 name->num_attr++;
463 }
464
465 return 0;
466}
467
468
469static char * x509_name_attr_str(enum x509_name_attr_type type)
470{
471 switch (type) {
472 case X509_NAME_ATTR_NOT_USED:
473 return "[N/A]";
474 case X509_NAME_ATTR_DC:
475 return "DC";
476 case X509_NAME_ATTR_CN:
477 return "CN";
478 case X509_NAME_ATTR_C:
479 return "C";
480 case X509_NAME_ATTR_L:
481 return "L";
482 case X509_NAME_ATTR_ST:
483 return "ST";
484 case X509_NAME_ATTR_O:
485 return "O";
486 case X509_NAME_ATTR_OU:
487 return "OU";
488 }
489 return "?";
490}
491
492
493/**
494 * x509_name_string - Convert an X.509 certificate name into a string
495 * @name: Name to convert
496 * @buf: Buffer for the string
497 * @len: Maximum buffer length
498 */
499void x509_name_string(struct x509_name *name, char *buf, size_t len)
500{
501 char *pos, *end;
502 int ret;
503 size_t i;
504
505 if (len == 0)
506 return;
507
508 pos = buf;
509 end = buf + len;
510
511 for (i = 0; i < name->num_attr; i++) {
512 ret = os_snprintf(pos, end - pos, "%s=%s, ",
513 x509_name_attr_str(name->attr[i].type),
514 name->attr[i].value);
Dmitry Shmidtfb45fd52015-01-05 13:08:17 -0800515 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700516 goto done;
517 pos += ret;
518 }
519
520 if (pos > buf + 1 && pos[-1] == ' ' && pos[-2] == ',') {
521 pos--;
522 *pos = '\0';
523 pos--;
524 *pos = '\0';
525 }
526
527 if (name->email) {
528 ret = os_snprintf(pos, end - pos, "/emailAddress=%s",
529 name->email);
Dmitry Shmidtfb45fd52015-01-05 13:08:17 -0800530 if (os_snprintf_error(end - pos, ret))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700531 goto done;
532 pos += ret;
533 }
534
535done:
Hai Shalom74f70d42019-02-11 14:42:39 -0800536 if (pos < end)
537 *pos = '\0';
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700538 end[-1] = '\0';
539}
540
541
Hai Shalom81f62d82019-07-22 12:10:00 -0700542static int parse_uint2(const char *pos, size_t len)
543{
544 char buf[3];
545 int ret;
546
547 if (len < 2)
548 return -1;
549 buf[0] = pos[0];
550 buf[1] = pos[1];
551 buf[2] = 0x00;
552 if (sscanf(buf, "%2d", &ret) != 1)
553 return -1;
554 return ret;
555}
556
557
558static int parse_uint4(const char *pos, size_t len)
559{
560 char buf[5];
561 int ret;
562
563 if (len < 4)
564 return -1;
565 buf[0] = pos[0];
566 buf[1] = pos[1];
567 buf[2] = pos[2];
568 buf[3] = pos[3];
569 buf[4] = 0x00;
570 if (sscanf(buf, "%4d", &ret) != 1)
571 return -1;
572 return ret;
573}
574
575
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800576int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, os_time_t *val)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700577{
Hai Shalom81f62d82019-07-22 12:10:00 -0700578 const char *pos, *end;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700579 int year, month, day, hour, min, sec;
580
581 /*
582 * Time ::= CHOICE {
583 * utcTime UTCTime,
584 * generalTime GeneralizedTime
585 * }
586 *
587 * UTCTime: YYMMDDHHMMSSZ
588 * GeneralizedTime: YYYYMMDDHHMMSSZ
589 */
590
591 pos = (const char *) buf;
Hai Shalom81f62d82019-07-22 12:10:00 -0700592 end = pos + len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700593
594 switch (asn1_tag) {
595 case ASN1_TAG_UTCTIME:
596 if (len != 13 || buf[12] != 'Z') {
597 wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized "
598 "UTCTime format", buf, len);
599 return -1;
600 }
Hai Shalom81f62d82019-07-22 12:10:00 -0700601 year = parse_uint2(pos, end - pos);
602 if (year < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700603 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
604 "UTCTime year", buf, len);
605 return -1;
606 }
607 if (year < 50)
608 year += 2000;
609 else
610 year += 1900;
611 pos += 2;
612 break;
613 case ASN1_TAG_GENERALIZEDTIME:
614 if (len != 15 || buf[14] != 'Z') {
615 wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized "
616 "GeneralizedTime format", buf, len);
617 return -1;
618 }
Hai Shalom81f62d82019-07-22 12:10:00 -0700619 year = parse_uint4(pos, end - pos);
620 if (year < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700621 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
622 "GeneralizedTime year", buf, len);
623 return -1;
624 }
625 pos += 4;
626 break;
627 default:
628 wpa_printf(MSG_DEBUG, "X509: Expected UTCTime or "
629 "GeneralizedTime - found tag 0x%x", asn1_tag);
630 return -1;
631 }
632
Hai Shalom81f62d82019-07-22 12:10:00 -0700633 month = parse_uint2(pos, end - pos);
634 if (month < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700635 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
636 "(month)", buf, len);
637 return -1;
638 }
639 pos += 2;
640
Hai Shalom81f62d82019-07-22 12:10:00 -0700641 day = parse_uint2(pos, end - pos);
642 if (day < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700643 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
644 "(day)", buf, len);
645 return -1;
646 }
647 pos += 2;
648
Hai Shalom81f62d82019-07-22 12:10:00 -0700649 hour = parse_uint2(pos, end - pos);
650 if (hour < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700651 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
652 "(hour)", buf, len);
653 return -1;
654 }
655 pos += 2;
656
Hai Shalom81f62d82019-07-22 12:10:00 -0700657 min = parse_uint2(pos, end - pos);
658 if (min < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700659 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
660 "(min)", buf, len);
661 return -1;
662 }
663 pos += 2;
664
Hai Shalom81f62d82019-07-22 12:10:00 -0700665 sec = parse_uint2(pos, end - pos);
666 if (sec < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700667 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
668 "(sec)", buf, len);
669 return -1;
670 }
671
672 if (os_mktime(year, month, day, hour, min, sec, val) < 0) {
673 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to convert Time",
674 buf, len);
675 if (year < 1970) {
676 /*
677 * At least some test certificates have been configured
678 * to use dates prior to 1970. Set the date to
679 * beginning of 1970 to handle these case.
680 */
681 wpa_printf(MSG_DEBUG, "X509: Year=%d before epoch - "
682 "assume epoch as the time", year);
683 *val = 0;
684 return 0;
685 }
686 return -1;
687 }
688
689 return 0;
690}
691
692
693static int x509_parse_validity(const u8 *buf, size_t len,
694 struct x509_certificate *cert, const u8 **next)
695{
696 struct asn1_hdr hdr;
697 const u8 *pos;
698 size_t plen;
699
700 /*
701 * Validity ::= SEQUENCE {
702 * notBefore Time,
703 * notAfter Time
704 * }
705 *
706 * RFC 3280, 4.1.2.5:
707 * CAs conforming to this profile MUST always encode certificate
708 * validity dates through the year 2049 as UTCTime; certificate
709 * validity dates in 2050 or later MUST be encoded as GeneralizedTime.
710 */
711
712 if (asn1_get_next(buf, len, &hdr) < 0 ||
713 hdr.class != ASN1_CLASS_UNIVERSAL ||
714 hdr.tag != ASN1_TAG_SEQUENCE) {
715 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
716 "(Validity) - found class %d tag 0x%x",
717 hdr.class, hdr.tag);
718 return -1;
719 }
720 pos = hdr.payload;
721 plen = hdr.length;
722
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800723 if (plen > (size_t) (buf + len - pos))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700724 return -1;
725
726 *next = pos + plen;
727
728 if (asn1_get_next(pos, plen, &hdr) < 0 ||
729 hdr.class != ASN1_CLASS_UNIVERSAL ||
730 x509_parse_time(hdr.payload, hdr.length, hdr.tag,
731 &cert->not_before) < 0) {
732 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notBefore "
733 "Time", hdr.payload, hdr.length);
734 return -1;
735 }
736
737 pos = hdr.payload + hdr.length;
738 plen = *next - pos;
739
740 if (asn1_get_next(pos, plen, &hdr) < 0 ||
741 hdr.class != ASN1_CLASS_UNIVERSAL ||
742 x509_parse_time(hdr.payload, hdr.length, hdr.tag,
743 &cert->not_after) < 0) {
744 wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notAfter "
745 "Time", hdr.payload, hdr.length);
746 return -1;
747 }
748
749 wpa_printf(MSG_MSGDUMP, "X509: Validity: notBefore: %lu notAfter: %lu",
750 (unsigned long) cert->not_before,
751 (unsigned long) cert->not_after);
752
753 return 0;
754}
755
756
757static int x509_id_ce_oid(struct asn1_oid *oid)
758{
759 /* id-ce arc from X.509 for standard X.509v3 extensions */
760 return oid->len >= 4 &&
761 oid->oid[0] == 2 /* joint-iso-ccitt */ &&
762 oid->oid[1] == 5 /* ds */ &&
763 oid->oid[2] == 29 /* id-ce */;
764}
765
766
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -0800767static int x509_any_ext_key_usage_oid(struct asn1_oid *oid)
768{
769 return oid->len == 6 &&
770 x509_id_ce_oid(oid) &&
771 oid->oid[3] == 37 /* extKeyUsage */ &&
772 oid->oid[4] == 0 /* anyExtendedKeyUsage */;
773}
774
775
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700776static int x509_parse_ext_key_usage(struct x509_certificate *cert,
777 const u8 *pos, size_t len)
778{
779 struct asn1_hdr hdr;
780
781 /*
782 * KeyUsage ::= BIT STRING {
783 * digitalSignature (0),
784 * nonRepudiation (1),
785 * keyEncipherment (2),
786 * dataEncipherment (3),
787 * keyAgreement (4),
788 * keyCertSign (5),
789 * cRLSign (6),
790 * encipherOnly (7),
791 * decipherOnly (8) }
792 */
793
794 if (asn1_get_next(pos, len, &hdr) < 0 ||
795 hdr.class != ASN1_CLASS_UNIVERSAL ||
796 hdr.tag != ASN1_TAG_BITSTRING ||
797 hdr.length < 1) {
798 wpa_printf(MSG_DEBUG, "X509: Expected BIT STRING in "
799 "KeyUsage; found %d tag 0x%x len %d",
800 hdr.class, hdr.tag, hdr.length);
801 return -1;
802 }
803
804 cert->extensions_present |= X509_EXT_KEY_USAGE;
805 cert->key_usage = asn1_bit_string_to_long(hdr.payload, hdr.length);
806
807 wpa_printf(MSG_DEBUG, "X509: KeyUsage 0x%lx", cert->key_usage);
808
809 return 0;
810}
811
812
813static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,
814 const u8 *pos, size_t len)
815{
816 struct asn1_hdr hdr;
817 unsigned long value;
818 size_t left;
Hai Shalom81f62d82019-07-22 12:10:00 -0700819 const u8 *end_seq;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700820
821 /*
822 * BasicConstraints ::= SEQUENCE {
823 * cA BOOLEAN DEFAULT FALSE,
824 * pathLenConstraint INTEGER (0..MAX) OPTIONAL }
825 */
826
827 if (asn1_get_next(pos, len, &hdr) < 0 ||
828 hdr.class != ASN1_CLASS_UNIVERSAL ||
829 hdr.tag != ASN1_TAG_SEQUENCE) {
830 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
831 "BasicConstraints; found %d tag 0x%x",
832 hdr.class, hdr.tag);
833 return -1;
834 }
835
836 cert->extensions_present |= X509_EXT_BASIC_CONSTRAINTS;
837
838 if (hdr.length == 0)
839 return 0;
840
Hai Shalom81f62d82019-07-22 12:10:00 -0700841 end_seq = hdr.payload + hdr.length;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700842 if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
843 hdr.class != ASN1_CLASS_UNIVERSAL) {
844 wpa_printf(MSG_DEBUG, "X509: Failed to parse "
845 "BasicConstraints");
846 return -1;
847 }
848
849 if (hdr.tag == ASN1_TAG_BOOLEAN) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700850 cert->ca = hdr.payload[0];
851
Hai Shalom81f62d82019-07-22 12:10:00 -0700852 pos = hdr.payload + hdr.length;
853 if (pos >= end_seq) {
854 /* No optional pathLenConstraint */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700855 wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d",
856 cert->ca);
857 return 0;
858 }
Hai Shalom81f62d82019-07-22 12:10:00 -0700859 if (asn1_get_next(pos, end_seq - pos, &hdr) < 0 ||
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700860 hdr.class != ASN1_CLASS_UNIVERSAL) {
861 wpa_printf(MSG_DEBUG, "X509: Failed to parse "
862 "BasicConstraints");
863 return -1;
864 }
865 }
866
867 if (hdr.tag != ASN1_TAG_INTEGER) {
868 wpa_printf(MSG_DEBUG, "X509: Expected INTEGER in "
869 "BasicConstraints; found class %d tag 0x%x",
870 hdr.class, hdr.tag);
871 return -1;
872 }
873
874 pos = hdr.payload;
875 left = hdr.length;
876 value = 0;
877 while (left) {
878 value <<= 8;
879 value |= *pos++;
880 left--;
881 }
882
883 cert->path_len_constraint = value;
884 cert->extensions_present |= X509_EXT_PATH_LEN_CONSTRAINT;
885
886 wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d "
887 "pathLenConstraint=%lu",
888 cert->ca, cert->path_len_constraint);
889
890 return 0;
891}
892
893
894static int x509_parse_alt_name_rfc8222(struct x509_name *name,
895 const u8 *pos, size_t len)
896{
897 /* rfc822Name IA5String */
898 wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - rfc822Name", pos, len);
899 os_free(name->alt_email);
900 name->alt_email = os_zalloc(len + 1);
901 if (name->alt_email == NULL)
902 return -1;
903 os_memcpy(name->alt_email, pos, len);
904 if (os_strlen(name->alt_email) != len) {
905 wpa_printf(MSG_INFO, "X509: Reject certificate with "
906 "embedded NUL byte in rfc822Name (%s[NUL])",
907 name->alt_email);
908 os_free(name->alt_email);
909 name->alt_email = NULL;
910 return -1;
911 }
912 return 0;
913}
914
915
916static int x509_parse_alt_name_dns(struct x509_name *name,
917 const u8 *pos, size_t len)
918{
919 /* dNSName IA5String */
920 wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - dNSName", pos, len);
921 os_free(name->dns);
922 name->dns = os_zalloc(len + 1);
923 if (name->dns == NULL)
924 return -1;
925 os_memcpy(name->dns, pos, len);
926 if (os_strlen(name->dns) != len) {
927 wpa_printf(MSG_INFO, "X509: Reject certificate with "
928 "embedded NUL byte in dNSName (%s[NUL])",
929 name->dns);
930 os_free(name->dns);
931 name->dns = NULL;
932 return -1;
933 }
934 return 0;
935}
936
937
938static int x509_parse_alt_name_uri(struct x509_name *name,
939 const u8 *pos, size_t len)
940{
941 /* uniformResourceIdentifier IA5String */
942 wpa_hexdump_ascii(MSG_MSGDUMP,
943 "X509: altName - uniformResourceIdentifier",
944 pos, len);
945 os_free(name->uri);
946 name->uri = os_zalloc(len + 1);
947 if (name->uri == NULL)
948 return -1;
949 os_memcpy(name->uri, pos, len);
950 if (os_strlen(name->uri) != len) {
951 wpa_printf(MSG_INFO, "X509: Reject certificate with "
952 "embedded NUL byte in uniformResourceIdentifier "
953 "(%s[NUL])", name->uri);
954 os_free(name->uri);
955 name->uri = NULL;
956 return -1;
957 }
958 return 0;
959}
960
961
962static int x509_parse_alt_name_ip(struct x509_name *name,
963 const u8 *pos, size_t len)
964{
965 /* iPAddress OCTET STRING */
966 wpa_hexdump(MSG_MSGDUMP, "X509: altName - iPAddress", pos, len);
967 os_free(name->ip);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700968 name->ip = os_memdup(pos, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700969 if (name->ip == NULL)
970 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700971 name->ip_len = len;
972 return 0;
973}
974
975
976static int x509_parse_alt_name_rid(struct x509_name *name,
977 const u8 *pos, size_t len)
978{
979 char buf[80];
980
981 /* registeredID OBJECT IDENTIFIER */
982 if (asn1_parse_oid(pos, len, &name->rid) < 0)
983 return -1;
984
985 asn1_oid_to_str(&name->rid, buf, sizeof(buf));
986 wpa_printf(MSG_MSGDUMP, "X509: altName - registeredID: %s", buf);
987
988 return 0;
989}
990
991
992static int x509_parse_ext_alt_name(struct x509_name *name,
993 const u8 *pos, size_t len)
994{
995 struct asn1_hdr hdr;
996 const u8 *p, *end;
997
998 /*
999 * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
1000 *
1001 * GeneralName ::= CHOICE {
1002 * otherName [0] OtherName,
1003 * rfc822Name [1] IA5String,
1004 * dNSName [2] IA5String,
1005 * x400Address [3] ORAddress,
1006 * directoryName [4] Name,
1007 * ediPartyName [5] EDIPartyName,
1008 * uniformResourceIdentifier [6] IA5String,
1009 * iPAddress [7] OCTET STRING,
1010 * registeredID [8] OBJECT IDENTIFIER }
1011 *
1012 * OtherName ::= SEQUENCE {
1013 * type-id OBJECT IDENTIFIER,
1014 * value [0] EXPLICIT ANY DEFINED BY type-id }
1015 *
1016 * EDIPartyName ::= SEQUENCE {
1017 * nameAssigner [0] DirectoryString OPTIONAL,
1018 * partyName [1] DirectoryString }
1019 */
1020
1021 for (p = pos, end = pos + len; p < end; p = hdr.payload + hdr.length) {
1022 int res;
1023
1024 if (asn1_get_next(p, end - p, &hdr) < 0) {
1025 wpa_printf(MSG_DEBUG, "X509: Failed to parse "
1026 "SubjectAltName item");
1027 return -1;
1028 }
1029
1030 if (hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC)
1031 continue;
1032
1033 switch (hdr.tag) {
1034 case 1:
1035 res = x509_parse_alt_name_rfc8222(name, hdr.payload,
1036 hdr.length);
1037 break;
1038 case 2:
1039 res = x509_parse_alt_name_dns(name, hdr.payload,
1040 hdr.length);
1041 break;
1042 case 6:
1043 res = x509_parse_alt_name_uri(name, hdr.payload,
1044 hdr.length);
1045 break;
1046 case 7:
1047 res = x509_parse_alt_name_ip(name, hdr.payload,
1048 hdr.length);
1049 break;
1050 case 8:
1051 res = x509_parse_alt_name_rid(name, hdr.payload,
1052 hdr.length);
1053 break;
1054 case 0: /* TODO: otherName */
1055 case 3: /* TODO: x500Address */
1056 case 4: /* TODO: directoryName */
1057 case 5: /* TODO: ediPartyName */
1058 default:
1059 res = 0;
1060 break;
1061 }
1062 if (res < 0)
1063 return res;
1064 }
1065
1066 return 0;
1067}
1068
1069
1070static int x509_parse_ext_subject_alt_name(struct x509_certificate *cert,
1071 const u8 *pos, size_t len)
1072{
1073 struct asn1_hdr hdr;
1074
1075 /* SubjectAltName ::= GeneralNames */
1076
1077 if (asn1_get_next(pos, len, &hdr) < 0 ||
1078 hdr.class != ASN1_CLASS_UNIVERSAL ||
1079 hdr.tag != ASN1_TAG_SEQUENCE) {
1080 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
1081 "SubjectAltName; found %d tag 0x%x",
1082 hdr.class, hdr.tag);
1083 return -1;
1084 }
1085
1086 wpa_printf(MSG_DEBUG, "X509: SubjectAltName");
1087 cert->extensions_present |= X509_EXT_SUBJECT_ALT_NAME;
1088
1089 if (hdr.length == 0)
1090 return 0;
1091
1092 return x509_parse_ext_alt_name(&cert->subject, hdr.payload,
1093 hdr.length);
1094}
1095
1096
1097static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,
1098 const u8 *pos, size_t len)
1099{
1100 struct asn1_hdr hdr;
1101
1102 /* IssuerAltName ::= GeneralNames */
1103
1104 if (asn1_get_next(pos, len, &hdr) < 0 ||
1105 hdr.class != ASN1_CLASS_UNIVERSAL ||
1106 hdr.tag != ASN1_TAG_SEQUENCE) {
1107 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
1108 "IssuerAltName; found %d tag 0x%x",
1109 hdr.class, hdr.tag);
1110 return -1;
1111 }
1112
1113 wpa_printf(MSG_DEBUG, "X509: IssuerAltName");
1114 cert->extensions_present |= X509_EXT_ISSUER_ALT_NAME;
1115
1116 if (hdr.length == 0)
1117 return 0;
1118
1119 return x509_parse_ext_alt_name(&cert->issuer, hdr.payload,
1120 hdr.length);
1121}
1122
1123
Hai Shalomfdcde762020-04-02 11:19:20 -07001124static int x509_id_cert_policy_any_oid(struct asn1_oid *oid)
1125{
1126 return oid->len == 5 &&
1127 oid->oid[0] == 2 /* iso/itu-t */ &&
1128 oid->oid[1] == 5 /* X.500 Directory Services */ &&
1129 oid->oid[2] == 29 /* id-ce */ &&
1130 oid->oid[3] == 32 /* id-ce-certificate-policies */ &&
1131 oid->oid[4] == 0 /* anyPolicy */;
1132}
1133
1134
1135static int x509_id_wfa_oid(struct asn1_oid *oid)
1136{
1137 return oid->len >= 7 &&
1138 oid->oid[0] == 1 /* iso */ &&
1139 oid->oid[1] == 3 /* identified-organization */ &&
1140 oid->oid[2] == 6 /* dod */ &&
1141 oid->oid[3] == 1 /* internet */ &&
1142 oid->oid[4] == 4 /* private */ &&
1143 oid->oid[5] == 1 /* enterprise */ &&
1144 oid->oid[6] == 40808 /* WFA */;
1145}
1146
1147
1148static int x509_id_wfa_tod_oid(struct asn1_oid *oid)
1149{
1150 return oid->len >= 9 &&
1151 x509_id_wfa_oid(oid) &&
1152 oid->oid[7] == 1 &&
1153 oid->oid[8] == 3;
1154}
1155
1156
1157static int x509_id_wfa_tod_strict_oid(struct asn1_oid *oid)
1158{
1159 return oid->len == 10 &&
1160 x509_id_wfa_tod_oid(oid) &&
1161 oid->oid[9] == 1;
1162}
1163
1164
1165static int x509_id_wfa_tod_tofu_oid(struct asn1_oid *oid)
1166{
1167 return oid->len == 10 &&
1168 x509_id_wfa_tod_oid(oid) &&
1169 oid->oid[9] == 2;
1170}
1171
1172
1173static int x509_parse_ext_certificate_policies(struct x509_certificate *cert,
1174 const u8 *pos, size_t len)
1175{
1176 struct asn1_hdr hdr;
1177 const u8 *end;
1178
1179 /*
1180 * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
1181 *
1182 * PolicyInformation ::= SEQUENCE {
1183 * policyIdentifier CertPolicyId,
1184 * policyQualifiers SEQUENCE SIZE (1..MAX) OF
1185 * PolicyQualifierInfo OPTIONAL }
1186 *
1187 * CertPolicyId ::= OBJECT IDENTIFIER
1188 */
1189
1190 if (asn1_get_next(pos, len, &hdr) < 0 ||
1191 hdr.class != ASN1_CLASS_UNIVERSAL ||
1192 hdr.tag != ASN1_TAG_SEQUENCE) {
1193 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE (certificatePolicies) - found class %d tag 0x%x",
1194 hdr.class, hdr.tag);
1195 return -1;
1196 }
1197 if (hdr.length > pos + len - hdr.payload)
1198 return -1;
1199 pos = hdr.payload;
1200 end = pos + hdr.length;
1201
1202 wpa_hexdump(MSG_MSGDUMP, "X509: certificatePolicies", pos, end - pos);
1203
1204 while (pos < end) {
1205 const u8 *pol_end;
1206 struct asn1_oid oid;
1207 char buf[80];
1208
1209 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1210 hdr.class != ASN1_CLASS_UNIVERSAL ||
1211 hdr.tag != ASN1_TAG_SEQUENCE) {
1212 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE (PolicyInformation) - found class %d tag 0x%x",
1213 hdr.class, hdr.tag);
1214 return -1;
1215 }
1216 if (hdr.length > end - hdr.payload)
1217 return -1;
1218 pos = hdr.payload;
1219 pol_end = pos + hdr.length;
1220 wpa_hexdump(MSG_MSGDUMP, "X509: PolicyInformation",
1221 pos, pol_end - pos);
1222
1223 if (asn1_get_oid(pos, pol_end - pos, &oid, &pos))
1224 return -1;
1225 if (x509_id_cert_policy_any_oid(&oid)) {
1226 os_strlcpy(buf, "anyPolicy-STRICT", sizeof(buf));
1227 cert->certificate_policy |=
1228 X509_EXT_CERT_POLICY_ANY;
1229 } else if (x509_id_wfa_tod_strict_oid(&oid)) {
1230 os_strlcpy(buf, "TOD-STRICT", sizeof(buf));
1231 cert->certificate_policy |=
1232 X509_EXT_CERT_POLICY_TOD_STRICT;
1233 } else if (x509_id_wfa_tod_tofu_oid(&oid)) {
1234 os_strlcpy(buf, "TOD-TOFU", sizeof(buf));
1235 cert->certificate_policy |=
1236 X509_EXT_CERT_POLICY_TOD_TOFU;
1237 } else {
1238 asn1_oid_to_str(&oid, buf, sizeof(buf));
1239 }
1240 wpa_printf(MSG_DEBUG, "policyIdentifier: %s", buf);
1241
1242 pos = pol_end;
1243 }
1244
1245 cert->extensions_present |= X509_EXT_CERTIFICATE_POLICY;
1246
1247 return 0;
1248}
1249
1250
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001251static int x509_id_pkix_oid(struct asn1_oid *oid)
1252{
1253 return oid->len >= 7 &&
1254 oid->oid[0] == 1 /* iso */ &&
1255 oid->oid[1] == 3 /* identified-organization */ &&
1256 oid->oid[2] == 6 /* dod */ &&
1257 oid->oid[3] == 1 /* internet */ &&
1258 oid->oid[4] == 5 /* security */ &&
1259 oid->oid[5] == 5 /* mechanisms */ &&
1260 oid->oid[6] == 7 /* id-pkix */;
1261}
1262
1263
1264static int x509_id_kp_oid(struct asn1_oid *oid)
1265{
1266 /* id-kp */
1267 return oid->len >= 8 &&
1268 x509_id_pkix_oid(oid) &&
1269 oid->oid[7] == 3 /* id-kp */;
1270}
1271
1272
1273static int x509_id_kp_server_auth_oid(struct asn1_oid *oid)
1274{
1275 /* id-kp */
1276 return oid->len == 9 &&
1277 x509_id_kp_oid(oid) &&
1278 oid->oid[8] == 1 /* id-kp-serverAuth */;
1279}
1280
1281
1282static int x509_id_kp_client_auth_oid(struct asn1_oid *oid)
1283{
1284 /* id-kp */
1285 return oid->len == 9 &&
1286 x509_id_kp_oid(oid) &&
1287 oid->oid[8] == 2 /* id-kp-clientAuth */;
1288}
1289
1290
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001291static int x509_id_kp_ocsp_oid(struct asn1_oid *oid)
1292{
1293 /* id-kp */
1294 return oid->len == 9 &&
1295 x509_id_kp_oid(oid) &&
1296 oid->oid[8] == 9 /* id-kp-OCSPSigning */;
1297}
1298
1299
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001300static int x509_parse_ext_ext_key_usage(struct x509_certificate *cert,
1301 const u8 *pos, size_t len)
1302{
1303 struct asn1_hdr hdr;
1304 const u8 *end;
1305 struct asn1_oid oid;
1306
1307 /*
1308 * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
1309 *
1310 * KeyPurposeId ::= OBJECT IDENTIFIER
1311 */
1312
1313 if (asn1_get_next(pos, len, &hdr) < 0 ||
1314 hdr.class != ASN1_CLASS_UNIVERSAL ||
1315 hdr.tag != ASN1_TAG_SEQUENCE) {
1316 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
1317 "(ExtKeyUsageSyntax) - found class %d tag 0x%x",
1318 hdr.class, hdr.tag);
1319 return -1;
1320 }
1321 if (hdr.length > pos + len - hdr.payload)
1322 return -1;
1323 pos = hdr.payload;
1324 end = pos + hdr.length;
1325
1326 wpa_hexdump(MSG_MSGDUMP, "X509: ExtKeyUsageSyntax", pos, end - pos);
1327
1328 while (pos < end) {
1329 char buf[80];
1330
1331 if (asn1_get_oid(pos, end - pos, &oid, &pos))
1332 return -1;
1333 if (x509_any_ext_key_usage_oid(&oid)) {
1334 os_strlcpy(buf, "anyExtendedKeyUsage", sizeof(buf));
1335 cert->ext_key_usage |= X509_EXT_KEY_USAGE_ANY;
1336 } else if (x509_id_kp_server_auth_oid(&oid)) {
1337 os_strlcpy(buf, "id-kp-serverAuth", sizeof(buf));
1338 cert->ext_key_usage |= X509_EXT_KEY_USAGE_SERVER_AUTH;
1339 } else if (x509_id_kp_client_auth_oid(&oid)) {
1340 os_strlcpy(buf, "id-kp-clientAuth", sizeof(buf));
1341 cert->ext_key_usage |= X509_EXT_KEY_USAGE_CLIENT_AUTH;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001342 } else if (x509_id_kp_ocsp_oid(&oid)) {
1343 os_strlcpy(buf, "id-kp-OCSPSigning", sizeof(buf));
1344 cert->ext_key_usage |= X509_EXT_KEY_USAGE_OCSP;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001345 } else {
1346 asn1_oid_to_str(&oid, buf, sizeof(buf));
1347 }
1348 wpa_printf(MSG_DEBUG, "ExtKeyUsage KeyPurposeId: %s", buf);
1349 }
1350
1351 cert->extensions_present |= X509_EXT_EXT_KEY_USAGE;
1352
1353 return 0;
1354}
1355
1356
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001357static int x509_parse_extension_data(struct x509_certificate *cert,
1358 struct asn1_oid *oid,
1359 const u8 *pos, size_t len)
1360{
1361 if (!x509_id_ce_oid(oid))
1362 return 1;
1363
1364 /* TODO: add other extensions required by RFC 3280, Ch 4.2:
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001365 * name constraints (section 4.2.1.11)
1366 * policy constraints (section 4.2.1.12)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001367 * inhibit any-policy (section 4.2.1.15)
1368 */
1369 switch (oid->oid[3]) {
1370 case 15: /* id-ce-keyUsage */
1371 return x509_parse_ext_key_usage(cert, pos, len);
1372 case 17: /* id-ce-subjectAltName */
1373 return x509_parse_ext_subject_alt_name(cert, pos, len);
1374 case 18: /* id-ce-issuerAltName */
1375 return x509_parse_ext_issuer_alt_name(cert, pos, len);
1376 case 19: /* id-ce-basicConstraints */
1377 return x509_parse_ext_basic_constraints(cert, pos, len);
Hai Shalomfdcde762020-04-02 11:19:20 -07001378 case 32: /* id-ce-certificatePolicies */
1379 return x509_parse_ext_certificate_policies(cert, pos, len);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001380 case 37: /* id-ce-extKeyUsage */
1381 return x509_parse_ext_ext_key_usage(cert, pos, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001382 default:
1383 return 1;
1384 }
1385}
1386
1387
1388static int x509_parse_extension(struct x509_certificate *cert,
1389 const u8 *pos, size_t len, const u8 **next)
1390{
1391 const u8 *end;
1392 struct asn1_hdr hdr;
1393 struct asn1_oid oid;
1394 int critical_ext = 0, res;
1395 char buf[80];
1396
1397 /*
1398 * Extension ::= SEQUENCE {
1399 * extnID OBJECT IDENTIFIER,
1400 * critical BOOLEAN DEFAULT FALSE,
1401 * extnValue OCTET STRING
1402 * }
1403 */
1404
1405 if (asn1_get_next(pos, len, &hdr) < 0 ||
1406 hdr.class != ASN1_CLASS_UNIVERSAL ||
1407 hdr.tag != ASN1_TAG_SEQUENCE) {
1408 wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
1409 "Extensions: class %d tag 0x%x; expected SEQUENCE",
1410 hdr.class, hdr.tag);
1411 return -1;
1412 }
1413 pos = hdr.payload;
1414 *next = end = pos + hdr.length;
1415
1416 if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
1417 wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data for "
1418 "Extension (expected OID)");
1419 return -1;
1420 }
1421
1422 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1423 hdr.class != ASN1_CLASS_UNIVERSAL ||
1424 (hdr.tag != ASN1_TAG_BOOLEAN &&
1425 hdr.tag != ASN1_TAG_OCTETSTRING)) {
1426 wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
1427 "Extensions: class %d tag 0x%x; expected BOOLEAN "
1428 "or OCTET STRING", hdr.class, hdr.tag);
1429 return -1;
1430 }
1431
1432 if (hdr.tag == ASN1_TAG_BOOLEAN) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001433 critical_ext = hdr.payload[0];
1434 pos = hdr.payload;
1435 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1436 (hdr.class != ASN1_CLASS_UNIVERSAL &&
1437 hdr.class != ASN1_CLASS_PRIVATE) ||
1438 hdr.tag != ASN1_TAG_OCTETSTRING) {
1439 wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header "
1440 "in Extensions: class %d tag 0x%x; "
1441 "expected OCTET STRING",
1442 hdr.class, hdr.tag);
1443 return -1;
1444 }
1445 }
1446
1447 asn1_oid_to_str(&oid, buf, sizeof(buf));
1448 wpa_printf(MSG_DEBUG, "X509: Extension: extnID=%s critical=%d",
1449 buf, critical_ext);
1450 wpa_hexdump(MSG_MSGDUMP, "X509: extnValue", hdr.payload, hdr.length);
1451
1452 res = x509_parse_extension_data(cert, &oid, hdr.payload, hdr.length);
1453 if (res < 0)
1454 return res;
1455 if (res == 1 && critical_ext) {
1456 wpa_printf(MSG_INFO, "X509: Unknown critical extension %s",
1457 buf);
1458 return -1;
1459 }
1460
1461 return 0;
1462}
1463
1464
1465static int x509_parse_extensions(struct x509_certificate *cert,
1466 const u8 *pos, size_t len)
1467{
1468 const u8 *end;
1469 struct asn1_hdr hdr;
1470
1471 /* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension */
1472
1473 if (asn1_get_next(pos, len, &hdr) < 0 ||
1474 hdr.class != ASN1_CLASS_UNIVERSAL ||
1475 hdr.tag != ASN1_TAG_SEQUENCE) {
1476 wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data "
1477 "for Extensions: class %d tag 0x%x; "
1478 "expected SEQUENCE", hdr.class, hdr.tag);
1479 return -1;
1480 }
1481
1482 pos = hdr.payload;
1483 end = pos + hdr.length;
1484
1485 while (pos < end) {
1486 if (x509_parse_extension(cert, pos, end - pos, &pos)
1487 < 0)
1488 return -1;
1489 }
1490
1491 return 0;
1492}
1493
1494
1495static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
1496 struct x509_certificate *cert,
1497 const u8 **next)
1498{
1499 struct asn1_hdr hdr;
1500 const u8 *pos, *end;
1501 size_t left;
1502 char sbuf[128];
1503 unsigned long value;
Dmitry Shmidtd97138d2015-12-28 13:27:49 -08001504 const u8 *subject_dn;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001505
1506 /* tbsCertificate TBSCertificate ::= SEQUENCE */
1507 if (asn1_get_next(buf, len, &hdr) < 0 ||
1508 hdr.class != ASN1_CLASS_UNIVERSAL ||
1509 hdr.tag != ASN1_TAG_SEQUENCE) {
1510 wpa_printf(MSG_DEBUG, "X509: tbsCertificate did not start "
1511 "with a valid SEQUENCE - found class %d tag 0x%x",
1512 hdr.class, hdr.tag);
1513 return -1;
1514 }
1515 pos = hdr.payload;
1516 end = *next = pos + hdr.length;
1517
1518 /*
1519 * version [0] EXPLICIT Version DEFAULT v1
1520 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
1521 */
1522 if (asn1_get_next(pos, end - pos, &hdr) < 0)
1523 return -1;
1524 pos = hdr.payload;
1525
1526 if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC) {
1527 if (asn1_get_next(pos, end - pos, &hdr) < 0)
1528 return -1;
1529
1530 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
1531 hdr.tag != ASN1_TAG_INTEGER) {
1532 wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
1533 "version field - found class %d tag 0x%x",
1534 hdr.class, hdr.tag);
1535 return -1;
1536 }
1537 if (hdr.length != 1) {
1538 wpa_printf(MSG_DEBUG, "X509: Unexpected version field "
1539 "length %u (expected 1)", hdr.length);
1540 return -1;
1541 }
1542 pos = hdr.payload;
1543 left = hdr.length;
1544 value = 0;
1545 while (left) {
1546 value <<= 8;
1547 value |= *pos++;
1548 left--;
1549 }
1550
1551 cert->version = value;
1552 if (cert->version != X509_CERT_V1 &&
1553 cert->version != X509_CERT_V2 &&
1554 cert->version != X509_CERT_V3) {
1555 wpa_printf(MSG_DEBUG, "X509: Unsupported version %d",
1556 cert->version + 1);
1557 return -1;
1558 }
1559
1560 if (asn1_get_next(pos, end - pos, &hdr) < 0)
1561 return -1;
1562 } else
1563 cert->version = X509_CERT_V1;
1564 wpa_printf(MSG_MSGDUMP, "X509: Version X.509v%d", cert->version + 1);
1565
1566 /* serialNumber CertificateSerialNumber ::= INTEGER */
1567 if (hdr.class != ASN1_CLASS_UNIVERSAL ||
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001568 hdr.tag != ASN1_TAG_INTEGER ||
1569 hdr.length < 1 || hdr.length > X509_MAX_SERIAL_NUM_LEN) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001570 wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001571 "serialNumber; class=%d tag=0x%x length=%u",
1572 hdr.class, hdr.tag, hdr.length);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001573 return -1;
1574 }
1575
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001576 pos = hdr.payload + hdr.length;
1577 while (hdr.length > 0 && hdr.payload[0] == 0) {
1578 hdr.payload++;
1579 hdr.length--;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001580 }
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001581 os_memcpy(cert->serial_number, hdr.payload, hdr.length);
1582 cert->serial_number_len = hdr.length;
1583 wpa_hexdump(MSG_MSGDUMP, "X509: serialNumber", cert->serial_number,
1584 cert->serial_number_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001585
1586 /* signature AlgorithmIdentifier */
1587 if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature,
1588 &pos))
1589 return -1;
1590
1591 /* issuer Name */
1592 if (x509_parse_name(pos, end - pos, &cert->issuer, &pos))
1593 return -1;
1594 x509_name_string(&cert->issuer, sbuf, sizeof(sbuf));
1595 wpa_printf(MSG_MSGDUMP, "X509: issuer %s", sbuf);
1596
1597 /* validity Validity */
1598 if (x509_parse_validity(pos, end - pos, cert, &pos))
1599 return -1;
1600
1601 /* subject Name */
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001602 subject_dn = pos;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001603 if (x509_parse_name(pos, end - pos, &cert->subject, &pos))
1604 return -1;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001605 cert->subject_dn = os_malloc(pos - subject_dn);
1606 if (!cert->subject_dn)
1607 return -1;
1608 cert->subject_dn_len = pos - subject_dn;
1609 os_memcpy(cert->subject_dn, subject_dn, cert->subject_dn_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001610 x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
1611 wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf);
1612
1613 /* subjectPublicKeyInfo SubjectPublicKeyInfo */
1614 if (x509_parse_public_key(pos, end - pos, cert, &pos))
1615 return -1;
1616
1617 if (pos == end)
1618 return 0;
1619
1620 if (cert->version == X509_CERT_V1)
1621 return 0;
1622
1623 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1624 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
1625 wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
1626 " tag to parse optional tbsCertificate "
1627 "field(s); parsed class %d tag 0x%x",
1628 hdr.class, hdr.tag);
1629 return -1;
1630 }
1631
1632 if (hdr.tag == 1) {
1633 /* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL */
1634 wpa_printf(MSG_DEBUG, "X509: issuerUniqueID");
1635 /* TODO: parse UniqueIdentifier ::= BIT STRING */
1636
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -07001637 pos = hdr.payload + hdr.length;
1638 if (pos == end)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001639 return 0;
1640
1641 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1642 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
1643 wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
1644 " tag to parse optional tbsCertificate "
1645 "field(s); parsed class %d tag 0x%x",
1646 hdr.class, hdr.tag);
1647 return -1;
1648 }
1649 }
1650
1651 if (hdr.tag == 2) {
1652 /* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL */
1653 wpa_printf(MSG_DEBUG, "X509: subjectUniqueID");
1654 /* TODO: parse UniqueIdentifier ::= BIT STRING */
1655
Dmitry Shmidt5a1480c2014-05-12 09:46:02 -07001656 pos = hdr.payload + hdr.length;
1657 if (pos == end)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001658 return 0;
1659
1660 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1661 hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
1662 wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
1663 " tag to parse optional tbsCertificate "
1664 "field(s); parsed class %d tag 0x%x",
1665 hdr.class, hdr.tag);
1666 return -1;
1667 }
1668 }
1669
1670 if (hdr.tag != 3) {
1671 wpa_printf(MSG_DEBUG, "X509: Ignored unexpected "
1672 "Context-Specific tag %d in optional "
1673 "tbsCertificate fields", hdr.tag);
1674 return 0;
1675 }
1676
1677 /* extensions [3] EXPLICIT Extensions OPTIONAL */
1678
1679 if (cert->version != X509_CERT_V3) {
1680 wpa_printf(MSG_DEBUG, "X509: X.509%d certificate and "
1681 "Extensions data which are only allowed for "
1682 "version 3", cert->version + 1);
1683 return -1;
1684 }
1685
1686 if (x509_parse_extensions(cert, hdr.payload, hdr.length) < 0)
1687 return -1;
1688
1689 pos = hdr.payload + hdr.length;
1690 if (pos < end) {
1691 wpa_hexdump(MSG_DEBUG,
1692 "X509: Ignored extra tbsCertificate data",
1693 pos, end - pos);
1694 }
1695
1696 return 0;
1697}
1698
1699
1700static int x509_rsadsi_oid(struct asn1_oid *oid)
1701{
1702 return oid->len >= 4 &&
1703 oid->oid[0] == 1 /* iso */ &&
1704 oid->oid[1] == 2 /* member-body */ &&
1705 oid->oid[2] == 840 /* us */ &&
1706 oid->oid[3] == 113549 /* rsadsi */;
1707}
1708
1709
1710static int x509_pkcs_oid(struct asn1_oid *oid)
1711{
1712 return oid->len >= 5 &&
1713 x509_rsadsi_oid(oid) &&
1714 oid->oid[4] == 1 /* pkcs */;
1715}
1716
1717
1718static int x509_digest_oid(struct asn1_oid *oid)
1719{
1720 return oid->len >= 5 &&
1721 x509_rsadsi_oid(oid) &&
1722 oid->oid[4] == 2 /* digestAlgorithm */;
1723}
1724
1725
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001726int x509_sha1_oid(struct asn1_oid *oid)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001727{
1728 return oid->len == 6 &&
1729 oid->oid[0] == 1 /* iso */ &&
1730 oid->oid[1] == 3 /* identified-organization */ &&
1731 oid->oid[2] == 14 /* oiw */ &&
1732 oid->oid[3] == 3 /* secsig */ &&
1733 oid->oid[4] == 2 /* algorithms */ &&
1734 oid->oid[5] == 26 /* id-sha1 */;
1735}
1736
1737
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001738static int x509_sha2_oid(struct asn1_oid *oid)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001739{
1740 return oid->len == 9 &&
1741 oid->oid[0] == 2 /* joint-iso-itu-t */ &&
1742 oid->oid[1] == 16 /* country */ &&
1743 oid->oid[2] == 840 /* us */ &&
1744 oid->oid[3] == 1 /* organization */ &&
1745 oid->oid[4] == 101 /* gov */ &&
1746 oid->oid[5] == 3 /* csor */ &&
1747 oid->oid[6] == 4 /* nistAlgorithm */ &&
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001748 oid->oid[7] == 2 /* hashAlgs */;
1749}
1750
1751
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001752int x509_sha256_oid(struct asn1_oid *oid)
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001753{
1754 return x509_sha2_oid(oid) &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001755 oid->oid[8] == 1 /* sha256 */;
1756}
1757
1758
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001759int x509_sha384_oid(struct asn1_oid *oid)
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001760{
1761 return x509_sha2_oid(oid) &&
1762 oid->oid[8] == 2 /* sha384 */;
1763}
1764
1765
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001766int x509_sha512_oid(struct asn1_oid *oid)
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001767{
1768 return x509_sha2_oid(oid) &&
1769 oid->oid[8] == 3 /* sha512 */;
1770}
1771
1772
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001773/**
1774 * x509_certificate_parse - Parse a X.509 certificate in DER format
1775 * @buf: Pointer to the X.509 certificate in DER format
1776 * @len: Buffer length
1777 * Returns: Pointer to the parsed certificate or %NULL on failure
1778 *
1779 * Caller is responsible for freeing the returned certificate by calling
1780 * x509_certificate_free().
1781 */
1782struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
1783{
1784 struct asn1_hdr hdr;
1785 const u8 *pos, *end, *hash_start;
1786 struct x509_certificate *cert;
1787
1788 cert = os_zalloc(sizeof(*cert) + len);
1789 if (cert == NULL)
1790 return NULL;
1791 os_memcpy(cert + 1, buf, len);
1792 cert->cert_start = (u8 *) (cert + 1);
1793 cert->cert_len = len;
1794
1795 pos = buf;
1796 end = buf + len;
1797
1798 /* RFC 3280 - X.509 v3 certificate / ASN.1 DER */
1799
1800 /* Certificate ::= SEQUENCE */
1801 if (asn1_get_next(pos, len, &hdr) < 0 ||
1802 hdr.class != ASN1_CLASS_UNIVERSAL ||
1803 hdr.tag != ASN1_TAG_SEQUENCE) {
1804 wpa_printf(MSG_DEBUG, "X509: Certificate did not start with "
1805 "a valid SEQUENCE - found class %d tag 0x%x",
1806 hdr.class, hdr.tag);
1807 x509_certificate_free(cert);
1808 return NULL;
1809 }
1810 pos = hdr.payload;
1811
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001812 if (hdr.length > end - pos) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001813 x509_certificate_free(cert);
1814 return NULL;
1815 }
1816
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001817 if (hdr.length < end - pos) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001818 wpa_hexdump(MSG_MSGDUMP, "X509: Ignoring extra data after DER "
1819 "encoded certificate",
Dmitry Shmidtcc00d5d2015-05-04 10:34:12 -07001820 pos + hdr.length, end - (pos + hdr.length));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001821 end = pos + hdr.length;
1822 }
1823
1824 hash_start = pos;
1825 cert->tbs_cert_start = cert->cert_start + (hash_start - buf);
1826 if (x509_parse_tbs_certificate(pos, end - pos, cert, &pos)) {
1827 x509_certificate_free(cert);
1828 return NULL;
1829 }
1830 cert->tbs_cert_len = pos - hash_start;
1831
1832 /* signatureAlgorithm AlgorithmIdentifier */
1833 if (x509_parse_algorithm_identifier(pos, end - pos,
1834 &cert->signature_alg, &pos)) {
1835 x509_certificate_free(cert);
1836 return NULL;
1837 }
1838
1839 /* signatureValue BIT STRING */
1840 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1841 hdr.class != ASN1_CLASS_UNIVERSAL ||
1842 hdr.tag != ASN1_TAG_BITSTRING) {
1843 wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING "
1844 "(signatureValue) - found class %d tag 0x%x",
1845 hdr.class, hdr.tag);
1846 x509_certificate_free(cert);
1847 return NULL;
1848 }
1849 if (hdr.length < 1) {
1850 x509_certificate_free(cert);
1851 return NULL;
1852 }
1853 pos = hdr.payload;
1854 if (*pos) {
Hai Shalomb755a2a2020-04-23 21:49:02 -07001855 wpa_printf(MSG_DEBUG,
1856 "X509: BITSTRING (signatureValue) - %d unused bits",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001857 *pos);
1858 /* PKCS #1 v1.5 10.2.1:
1859 * It is an error if the length in bits of the signature S is
1860 * not a multiple of eight.
1861 */
1862 x509_certificate_free(cert);
1863 return NULL;
1864 }
1865 os_free(cert->sign_value);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001866 cert->sign_value = os_memdup(pos + 1, hdr.length - 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001867 if (cert->sign_value == NULL) {
1868 wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
1869 "signatureValue");
1870 x509_certificate_free(cert);
1871 return NULL;
1872 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001873 cert->sign_value_len = hdr.length - 1;
1874 wpa_hexdump(MSG_MSGDUMP, "X509: signature",
1875 cert->sign_value, cert->sign_value_len);
1876
1877 return cert;
1878}
1879
1880
1881/**
1882 * x509_certificate_check_signature - Verify certificate signature
1883 * @issuer: Issuer certificate
1884 * @cert: Certificate to be verified
1885 * Returns: 0 if cert has a valid signature that was signed by the issuer,
1886 * -1 if not
1887 */
1888int x509_certificate_check_signature(struct x509_certificate *issuer,
1889 struct x509_certificate *cert)
1890{
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001891 return x509_check_signature(issuer, &cert->signature,
1892 cert->sign_value, cert->sign_value_len,
1893 cert->tbs_cert_start, cert->tbs_cert_len);
1894}
1895
1896
1897int x509_check_signature(struct x509_certificate *issuer,
1898 struct x509_algorithm_identifier *signature,
1899 const u8 *sign_value, size_t sign_value_len,
1900 const u8 *signed_data, size_t signed_data_len)
1901{
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001902 struct crypto_public_key *pk;
1903 u8 *data;
1904 const u8 *pos, *end, *next, *da_end;
1905 size_t data_len;
1906 struct asn1_hdr hdr;
1907 struct asn1_oid oid;
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08001908 u8 hash[64];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001909 size_t hash_len;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001910 const u8 *addr[1] = { signed_data };
1911 size_t len[1] = { signed_data_len };
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001912
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001913 if (!x509_pkcs_oid(&signature->oid) ||
1914 signature->oid.len != 7 ||
1915 signature->oid.oid[5] != 1 /* pkcs-1 */) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001916 wpa_printf(MSG_DEBUG, "X509: Unrecognized signature "
1917 "algorithm");
1918 return -1;
1919 }
1920
1921 pk = crypto_public_key_import(issuer->public_key,
1922 issuer->public_key_len);
1923 if (pk == NULL)
1924 return -1;
1925
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001926 data_len = sign_value_len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001927 data = os_malloc(data_len);
1928 if (data == NULL) {
1929 crypto_public_key_free(pk);
1930 return -1;
1931 }
1932
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001933 if (crypto_public_key_decrypt_pkcs1(pk, sign_value,
1934 sign_value_len, data,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001935 &data_len) < 0) {
1936 wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature");
1937 crypto_public_key_free(pk);
1938 os_free(data);
1939 return -1;
1940 }
1941 crypto_public_key_free(pk);
1942
1943 wpa_hexdump(MSG_MSGDUMP, "X509: Signature data D", data, data_len);
1944
1945 /*
1946 * PKCS #1 v1.5, 10.1.2:
1947 *
1948 * DigestInfo ::= SEQUENCE {
1949 * digestAlgorithm DigestAlgorithmIdentifier,
1950 * digest Digest
1951 * }
1952 *
1953 * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
1954 *
1955 * Digest ::= OCTET STRING
1956 *
1957 */
1958 if (asn1_get_next(data, data_len, &hdr) < 0 ||
1959 hdr.class != ASN1_CLASS_UNIVERSAL ||
1960 hdr.tag != ASN1_TAG_SEQUENCE) {
1961 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
1962 "(DigestInfo) - found class %d tag 0x%x",
1963 hdr.class, hdr.tag);
1964 os_free(data);
1965 return -1;
1966 }
1967
1968 pos = hdr.payload;
1969 end = pos + hdr.length;
1970
1971 /*
1972 * X.509:
1973 * AlgorithmIdentifier ::= SEQUENCE {
1974 * algorithm OBJECT IDENTIFIER,
1975 * parameters ANY DEFINED BY algorithm OPTIONAL
1976 * }
1977 */
1978
1979 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
1980 hdr.class != ASN1_CLASS_UNIVERSAL ||
1981 hdr.tag != ASN1_TAG_SEQUENCE) {
1982 wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
1983 "(AlgorithmIdentifier) - found class %d tag 0x%x",
1984 hdr.class, hdr.tag);
1985 os_free(data);
1986 return -1;
1987 }
1988 da_end = hdr.payload + hdr.length;
1989
1990 if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) {
1991 wpa_printf(MSG_DEBUG, "X509: Failed to parse digestAlgorithm");
1992 os_free(data);
1993 return -1;
1994 }
1995
1996 if (x509_sha1_oid(&oid)) {
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001997 if (signature->oid.oid[6] != 5 /* sha-1WithRSAEncryption */) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001998 wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA1 "
1999 "does not match with certificate "
2000 "signatureAlgorithm (%lu)",
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002001 signature->oid.oid[6]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002002 os_free(data);
2003 return -1;
2004 }
2005 goto skip_digest_oid;
2006 }
2007
2008 if (x509_sha256_oid(&oid)) {
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002009 if (signature->oid.oid[6] !=
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002010 11 /* sha2561WithRSAEncryption */) {
2011 wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA256 "
2012 "does not match with certificate "
2013 "signatureAlgorithm (%lu)",
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002014 signature->oid.oid[6]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002015 os_free(data);
2016 return -1;
2017 }
2018 goto skip_digest_oid;
2019 }
2020
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002021 if (x509_sha384_oid(&oid)) {
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002022 if (signature->oid.oid[6] != 12 /* sha384WithRSAEncryption */) {
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002023 wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA384 "
2024 "does not match with certificate "
2025 "signatureAlgorithm (%lu)",
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002026 signature->oid.oid[6]);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002027 os_free(data);
2028 return -1;
2029 }
2030 goto skip_digest_oid;
2031 }
2032
2033 if (x509_sha512_oid(&oid)) {
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002034 if (signature->oid.oid[6] != 13 /* sha512WithRSAEncryption */) {
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002035 wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA512 "
2036 "does not match with certificate "
2037 "signatureAlgorithm (%lu)",
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002038 signature->oid.oid[6]);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002039 os_free(data);
2040 return -1;
2041 }
2042 goto skip_digest_oid;
2043 }
2044
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002045 if (!x509_digest_oid(&oid)) {
2046 wpa_printf(MSG_DEBUG, "X509: Unrecognized digestAlgorithm");
2047 os_free(data);
2048 return -1;
2049 }
2050 switch (oid.oid[5]) {
2051 case 5: /* md5 */
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002052 if (signature->oid.oid[6] != 4 /* md5WithRSAEncryption */) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002053 wpa_printf(MSG_DEBUG, "X509: digestAlgorithm MD5 does "
2054 "not match with certificate "
2055 "signatureAlgorithm (%lu)",
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002056 signature->oid.oid[6]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002057 os_free(data);
2058 return -1;
2059 }
2060 break;
2061 case 2: /* md2 */
2062 case 4: /* md4 */
2063 default:
2064 wpa_printf(MSG_DEBUG, "X509: Unsupported digestAlgorithm "
2065 "(%lu)", oid.oid[5]);
2066 os_free(data);
2067 return -1;
2068 }
2069
2070skip_digest_oid:
2071 /* Digest ::= OCTET STRING */
2072 pos = da_end;
2073 end = data + data_len;
2074
2075 if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
2076 hdr.class != ASN1_CLASS_UNIVERSAL ||
2077 hdr.tag != ASN1_TAG_OCTETSTRING) {
2078 wpa_printf(MSG_DEBUG, "X509: Expected OCTETSTRING "
2079 "(Digest) - found class %d tag 0x%x",
2080 hdr.class, hdr.tag);
2081 os_free(data);
2082 return -1;
2083 }
2084 wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest",
2085 hdr.payload, hdr.length);
2086
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002087 switch (signature->oid.oid[6]) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002088 case 4: /* md5WithRSAEncryption */
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002089 md5_vector(1, addr, len, hash);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002090 hash_len = 16;
2091 wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (MD5)",
2092 hash, hash_len);
2093 break;
2094 case 5: /* sha-1WithRSAEncryption */
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002095 sha1_vector(1, addr, len, hash);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002096 hash_len = 20;
2097 wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA1)",
2098 hash, hash_len);
2099 break;
2100 case 11: /* sha256WithRSAEncryption */
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002101 sha256_vector(1, addr, len, hash);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002102 hash_len = 32;
2103 wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)",
2104 hash, hash_len);
2105 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002106 case 12: /* sha384WithRSAEncryption */
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002107 sha384_vector(1, addr, len, hash);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002108 hash_len = 48;
2109 wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA384)",
2110 hash, hash_len);
2111 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002112 case 13: /* sha512WithRSAEncryption */
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002113 sha512_vector(1, addr, len, hash);
Dmitry Shmidtd7ff03d2015-12-04 14:49:35 -08002114 hash_len = 64;
2115 wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA512)",
2116 hash, hash_len);
2117 break;
2118 case 2: /* md2WithRSAEncryption */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002119 default:
2120 wpa_printf(MSG_INFO, "X509: Unsupported certificate signature "
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08002121 "algorithm (%lu)", signature->oid.oid[6]);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002122 os_free(data);
2123 return -1;
2124 }
2125
2126 if (hdr.length != hash_len ||
Dmitry Shmidtc2817022014-07-02 10:32:10 -07002127 os_memcmp_const(hdr.payload, hash, hdr.length) != 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002128 wpa_printf(MSG_INFO, "X509: Certificate Digest does not match "
2129 "with calculated tbsCertificate hash");
2130 os_free(data);
2131 return -1;
2132 }
2133
Dmitry Shmidt50b691d2014-05-21 14:01:45 -07002134 if (hdr.payload + hdr.length < data + data_len) {
2135 wpa_hexdump(MSG_INFO,
2136 "X509: Extra data after certificate signature hash",
2137 hdr.payload + hdr.length,
2138 data + data_len - hdr.payload - hdr.length);
2139 os_free(data);
2140 return -1;
2141 }
2142
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002143 os_free(data);
2144
2145 wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with "
2146 "calculated tbsCertificate hash");
2147
2148 return 0;
2149}
2150
2151
2152static int x509_valid_issuer(const struct x509_certificate *cert)
2153{
2154 if ((cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS) &&
2155 !cert->ca) {
2156 wpa_printf(MSG_DEBUG, "X509: Non-CA certificate used as an "
2157 "issuer");
2158 return -1;
2159 }
2160
2161 if (cert->version == X509_CERT_V3 &&
2162 !(cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS)) {
2163 wpa_printf(MSG_DEBUG, "X509: v3 CA certificate did not "
2164 "include BasicConstraints extension");
2165 return -1;
2166 }
2167
2168 if ((cert->extensions_present & X509_EXT_KEY_USAGE) &&
2169 !(cert->key_usage & X509_KEY_USAGE_KEY_CERT_SIGN)) {
2170 wpa_printf(MSG_DEBUG, "X509: Issuer certificate did not have "
2171 "keyCertSign bit in Key Usage");
2172 return -1;
2173 }
2174
2175 return 0;
2176}
2177
2178
2179/**
2180 * x509_certificate_chain_validate - Validate X.509 certificate chain
2181 * @trusted: List of trusted certificates
2182 * @chain: Certificate chain to be validated (first chain must be issued by
2183 * signed by the second certificate in the chain and so on)
2184 * @reason: Buffer for returning failure reason (X509_VALIDATE_*)
2185 * Returns: 0 if chain is valid, -1 if not
2186 */
2187int x509_certificate_chain_validate(struct x509_certificate *trusted,
2188 struct x509_certificate *chain,
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07002189 int *reason, int disable_time_checks)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002190{
2191 long unsigned idx;
2192 int chain_trusted = 0;
2193 struct x509_certificate *cert, *trust;
2194 char buf[128];
2195 struct os_time now;
2196
2197 *reason = X509_VALIDATE_OK;
2198
2199 wpa_printf(MSG_DEBUG, "X509: Validate certificate chain");
2200 os_get_time(&now);
2201
2202 for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
Dmitry Shmidtd97138d2015-12-28 13:27:49 -08002203 cert->issuer_trusted = 0;
Dmitry Shmidt29333592017-01-09 12:27:11 -08002204 x509_name_string(&cert->subject, buf, sizeof(buf));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002205 wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
2206
2207 if (chain_trusted)
2208 continue;
2209
Dmitry Shmidtc55524a2011-07-07 11:18:38 -07002210 if (!disable_time_checks &&
2211 ((unsigned long) now.sec <
2212 (unsigned long) cert->not_before ||
2213 (unsigned long) now.sec >
2214 (unsigned long) cert->not_after)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002215 wpa_printf(MSG_INFO, "X509: Certificate not valid "
2216 "(now=%lu not_before=%lu not_after=%lu)",
2217 now.sec, cert->not_before, cert->not_after);
2218 *reason = X509_VALIDATE_CERTIFICATE_EXPIRED;
2219 return -1;
2220 }
2221
2222 if (cert->next) {
2223 if (x509_name_compare(&cert->issuer,
2224 &cert->next->subject) != 0) {
2225 wpa_printf(MSG_DEBUG, "X509: Certificate "
2226 "chain issuer name mismatch");
2227 x509_name_string(&cert->issuer, buf,
Dmitry Shmidt29333592017-01-09 12:27:11 -08002228 sizeof(buf));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002229 wpa_printf(MSG_DEBUG, "X509: cert issuer: %s",
2230 buf);
2231 x509_name_string(&cert->next->subject, buf,
Dmitry Shmidt29333592017-01-09 12:27:11 -08002232 sizeof(buf));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002233 wpa_printf(MSG_DEBUG, "X509: next cert "
2234 "subject: %s", buf);
2235 *reason = X509_VALIDATE_CERTIFICATE_UNKNOWN;
2236 return -1;
2237 }
2238
2239 if (x509_valid_issuer(cert->next) < 0) {
2240 *reason = X509_VALIDATE_BAD_CERTIFICATE;
2241 return -1;
2242 }
2243
2244 if ((cert->next->extensions_present &
2245 X509_EXT_PATH_LEN_CONSTRAINT) &&
2246 idx > cert->next->path_len_constraint) {
2247 wpa_printf(MSG_DEBUG, "X509: pathLenConstraint"
2248 " not met (idx=%lu issuer "
2249 "pathLenConstraint=%lu)", idx,
2250 cert->next->path_len_constraint);
2251 *reason = X509_VALIDATE_BAD_CERTIFICATE;
2252 return -1;
2253 }
2254
2255 if (x509_certificate_check_signature(cert->next, cert)
2256 < 0) {
2257 wpa_printf(MSG_DEBUG, "X509: Invalid "
2258 "certificate signature within "
2259 "chain");
2260 *reason = X509_VALIDATE_BAD_CERTIFICATE;
2261 return -1;
2262 }
2263 }
2264
2265 for (trust = trusted; trust; trust = trust->next) {
2266 if (x509_name_compare(&cert->issuer, &trust->subject)
2267 == 0)
2268 break;
2269 }
2270
2271 if (trust) {
2272 wpa_printf(MSG_DEBUG, "X509: Found issuer from the "
2273 "list of trusted certificates");
2274 if (x509_valid_issuer(trust) < 0) {
2275 *reason = X509_VALIDATE_BAD_CERTIFICATE;
2276 return -1;
2277 }
2278
2279 if (x509_certificate_check_signature(trust, cert) < 0)
2280 {
2281 wpa_printf(MSG_DEBUG, "X509: Invalid "
2282 "certificate signature");
2283 *reason = X509_VALIDATE_BAD_CERTIFICATE;
2284 return -1;
2285 }
2286
2287 wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
2288 "found to complete the chain");
Dmitry Shmidtd97138d2015-12-28 13:27:49 -08002289 cert->issuer_trusted = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002290 chain_trusted = 1;
2291 }
2292 }
2293
2294 if (!chain_trusted) {
2295 wpa_printf(MSG_DEBUG, "X509: Did not find any of the issuers "
2296 "from the list of trusted certificates");
2297 if (trusted) {
2298 *reason = X509_VALIDATE_UNKNOWN_CA;
2299 return -1;
2300 }
2301 wpa_printf(MSG_DEBUG, "X509: Certificate chain validation "
2302 "disabled - ignore unknown CA issue");
2303 }
2304
2305 wpa_printf(MSG_DEBUG, "X509: Certificate chain valid");
2306
2307 return 0;
2308}
2309
2310
2311/**
2312 * x509_certificate_get_subject - Get a certificate based on Subject name
2313 * @chain: Certificate chain to search through
2314 * @name: Subject name to search for
2315 * Returns: Pointer to the certificate with the given Subject name or
2316 * %NULL on failure
2317 */
2318struct x509_certificate *
2319x509_certificate_get_subject(struct x509_certificate *chain,
2320 struct x509_name *name)
2321{
2322 struct x509_certificate *cert;
2323
2324 for (cert = chain; cert; cert = cert->next) {
2325 if (x509_name_compare(&cert->subject, name) == 0)
2326 return cert;
2327 }
2328 return NULL;
2329}
2330
2331
2332/**
2333 * x509_certificate_self_signed - Is the certificate self-signed?
2334 * @cert: Certificate
2335 * Returns: 1 if certificate is self-signed, 0 if not
2336 */
2337int x509_certificate_self_signed(struct x509_certificate *cert)
2338{
2339 return x509_name_compare(&cert->issuer, &cert->subject) == 0;
2340}