1 | /* |
2 | * Copyright (c) 2007-2016, Cameron Rich |
3 | * |
4 | * All rights reserved. |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions are met: |
8 | * |
9 | * * Redistributions of source code must retain the above copyright notice, |
10 | * this list of conditions and the following disclaimer. |
11 | * * Redistributions in binary form must reproduce the above copyright notice, |
12 | * this list of conditions and the following disclaimer in the documentation |
13 | * and/or other materials provided with the distribution. |
14 | * * Neither the name of the axTLS project nor the names of its contributors |
15 | * may be used to endorse or promote products derived from this software |
16 | * without specific prior written permission. |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
22 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
23 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
25 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
26 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
27 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | */ |
30 | |
31 | /** |
32 | * @file x509.c |
33 | * |
34 | * Certificate processing. |
35 | */ |
36 | |
37 | #include <stdio.h> |
38 | #include <stdlib.h> |
39 | #include <string.h> |
40 | #include <time.h> |
41 | #include "os_port.h" |
42 | #include "crypto_misc.h" |
43 | |
44 | #ifdef CONFIG_SSL_CERT_VERIFICATION |
45 | static int x509_v3_subject_alt_name(const uint8_t *cert, int offset, |
46 | X509_CTX *x509_ctx); |
47 | static int x509_v3_basic_constraints(const uint8_t *cert, int offset, |
48 | X509_CTX *x509_ctx); |
49 | static int x509_v3_key_usage(const uint8_t *cert, int offset, |
50 | X509_CTX *x509_ctx); |
51 | |
52 | /** |
53 | * Retrieve the signature from a certificate. |
54 | */ |
55 | static const uint8_t *get_signature(const uint8_t *asn1_sig, int *len) |
56 | { |
57 | int offset = 0; |
58 | const uint8_t *ptr = NULL; |
59 | |
60 | if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 || |
61 | asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE)) |
62 | goto end_get_sig; |
63 | |
64 | if (asn1_sig[offset++] != ASN1_OCTET_STRING) |
65 | goto end_get_sig; |
66 | *len = get_asn1_length(asn1_sig, &offset); |
67 | ptr = &asn1_sig[offset]; /* all ok */ |
68 | |
69 | end_get_sig: |
70 | return ptr; |
71 | } |
72 | |
73 | #endif |
74 | |
75 | /** |
76 | * Construct a new x509 object. |
77 | * @return 0 if ok. < 0 if there was a problem. |
78 | */ |
79 | int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx) |
80 | { |
81 | int begin_tbs, end_tbs; |
82 | int ret = X509_NOT_OK, offset = 0, cert_size = 0; |
83 | int version = 0; |
84 | X509_CTX *x509_ctx; |
85 | #ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */ |
86 | BI_CTX *bi_ctx; |
87 | #endif |
88 | |
89 | *ctx = (X509_CTX *)calloc(1, sizeof(X509_CTX)); |
90 | x509_ctx = *ctx; |
91 | |
92 | /* get the certificate size */ |
93 | asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE); |
94 | |
95 | if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) |
96 | goto end_cert; |
97 | |
98 | begin_tbs = offset; /* start of the tbs */ |
99 | end_tbs = begin_tbs; /* work out the end of the tbs */ |
100 | asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE); |
101 | |
102 | if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) |
103 | goto end_cert; |
104 | |
105 | /* optional version */ |
106 | if (cert[offset] == ASN1_EXPLICIT_TAG && |
107 | asn1_version(cert, &offset, &version) == X509_NOT_OK) |
108 | goto end_cert; |
109 | |
110 | if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */ |
111 | asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0) |
112 | goto end_cert; |
113 | |
114 | /* make sure the signature is ok */ |
115 | if (asn1_signature_type(cert, &offset, x509_ctx)) |
116 | { |
117 | ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST; |
118 | goto end_cert; |
119 | } |
120 | |
121 | if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) || |
122 | asn1_validity(cert, &offset, x509_ctx) || |
123 | asn1_name(cert, &offset, x509_ctx->cert_dn) || |
124 | asn1_public_key(cert, &offset, x509_ctx)) |
125 | { |
126 | goto end_cert; |
127 | } |
128 | |
129 | #ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */ |
130 | bi_ctx = x509_ctx->rsa_ctx->bi_ctx; |
131 | |
132 | /* use the appropriate signature algorithm */ |
133 | switch (x509_ctx->sig_type) |
134 | { |
135 | case SIG_TYPE_MD5: |
136 | { |
137 | MD5_CTX md5_ctx; |
138 | uint8_t md5_dgst[MD5_SIZE]; |
139 | MD5_Init(&md5_ctx); |
140 | MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs); |
141 | MD5_Final(md5_dgst, &md5_ctx); |
142 | x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE); |
143 | } |
144 | break; |
145 | |
146 | case SIG_TYPE_SHA1: |
147 | { |
148 | SHA1_CTX sha_ctx; |
149 | uint8_t sha_dgst[SHA1_SIZE]; |
150 | SHA1_Init(&sha_ctx); |
151 | SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs); |
152 | SHA1_Final(sha_dgst, &sha_ctx); |
153 | x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE); |
154 | } |
155 | break; |
156 | |
157 | case SIG_TYPE_SHA256: |
158 | { |
159 | SHA256_CTX sha256_ctx; |
160 | uint8_t sha256_dgst[SHA256_SIZE]; |
161 | SHA256_Init(&sha256_ctx); |
162 | SHA256_Update(&sha256_ctx, &cert[begin_tbs], end_tbs-begin_tbs); |
163 | SHA256_Final(sha256_dgst, &sha256_ctx); |
164 | x509_ctx->digest = bi_import(bi_ctx, sha256_dgst, SHA256_SIZE); |
165 | } |
166 | break; |
167 | |
168 | case SIG_TYPE_SHA384: |
169 | { |
170 | SHA384_CTX sha384_ctx; |
171 | uint8_t sha384_dgst[SHA384_SIZE]; |
172 | SHA384_Init(&sha384_ctx); |
173 | SHA384_Update(&sha384_ctx, &cert[begin_tbs], end_tbs-begin_tbs); |
174 | SHA384_Final(sha384_dgst, &sha384_ctx); |
175 | x509_ctx->digest = bi_import(bi_ctx, sha384_dgst, SHA384_SIZE); |
176 | } |
177 | break; |
178 | |
179 | case SIG_TYPE_SHA512: |
180 | { |
181 | SHA512_CTX sha512_ctx; |
182 | uint8_t sha512_dgst[SHA512_SIZE]; |
183 | SHA512_Init(&sha512_ctx); |
184 | SHA512_Update(&sha512_ctx, &cert[begin_tbs], end_tbs-begin_tbs); |
185 | SHA512_Final(sha512_dgst, &sha512_ctx); |
186 | x509_ctx->digest = bi_import(bi_ctx, sha512_dgst, SHA512_SIZE); |
187 | } |
188 | break; |
189 | } |
190 | |
191 | if (version == 2 && asn1_next_obj(cert, &offset, ASN1_V3_DATA) > 0) |
192 | { |
193 | x509_v3_subject_alt_name(cert, offset, x509_ctx); |
194 | x509_v3_basic_constraints(cert, offset, x509_ctx); |
195 | x509_v3_key_usage(cert, offset, x509_ctx); |
196 | } |
197 | |
198 | offset = end_tbs; /* skip the rest of v3 data */ |
199 | if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || |
200 | asn1_signature(cert, &offset, x509_ctx)) |
201 | goto end_cert; |
202 | #endif |
203 | ret = X509_OK; |
204 | end_cert: |
205 | if (len) |
206 | { |
207 | *len = cert_size; |
208 | } |
209 | |
210 | if (ret) |
211 | { |
212 | #ifdef CONFIG_SSL_FULL_MODE |
213 | printf("Error: Invalid X509 ASN.1 file (%s)\n" , |
214 | x509_display_error(ret)); |
215 | #endif |
216 | x509_free(x509_ctx); |
217 | *ctx = NULL; |
218 | } |
219 | |
220 | return ret; |
221 | } |
222 | |
223 | #ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */ |
224 | static int x509_v3_subject_alt_name(const uint8_t *cert, int offset, |
225 | X509_CTX *x509_ctx) |
226 | { |
227 | if ((offset = asn1_is_subject_alt_name(cert, offset)) > 0) |
228 | { |
229 | x509_ctx->subject_alt_name_present = true; |
230 | x509_ctx->subject_alt_name_is_critical = |
231 | asn1_is_critical_ext(cert, &offset); |
232 | |
233 | if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) > 0) |
234 | { |
235 | int altlen; |
236 | |
237 | if ((altlen = asn1_next_obj(cert, &offset, ASN1_SEQUENCE)) > 0) |
238 | { |
239 | int endalt = offset + altlen; |
240 | int totalnames = 0; |
241 | |
242 | while (offset < endalt) |
243 | { |
244 | int type = cert[offset++]; |
245 | int dnslen = get_asn1_length(cert, &offset); |
246 | |
247 | if (type == ASN1_CONTEXT_DNSNAME) |
248 | { |
249 | x509_ctx->subject_alt_dnsnames = (char**) |
250 | realloc(x509_ctx->subject_alt_dnsnames, |
251 | (totalnames + 2) * sizeof(char*)); |
252 | x509_ctx->subject_alt_dnsnames[totalnames] = |
253 | (char*)malloc(dnslen + 1); |
254 | x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL; |
255 | memcpy(x509_ctx->subject_alt_dnsnames[totalnames], |
256 | cert + offset, dnslen); |
257 | x509_ctx->subject_alt_dnsnames[totalnames][dnslen] = 0; |
258 | totalnames++; |
259 | } |
260 | |
261 | offset += dnslen; |
262 | } |
263 | } |
264 | } |
265 | } |
266 | |
267 | return X509_OK; |
268 | } |
269 | |
270 | /** |
271 | * Basic constraints - see https://tools.ietf.org/html/rfc5280#page-39 |
272 | */ |
273 | static int x509_v3_basic_constraints(const uint8_t *cert, int offset, |
274 | X509_CTX *x509_ctx) |
275 | { |
276 | int ret = X509_OK; |
277 | |
278 | if ((offset = asn1_is_basic_constraints(cert, offset)) == 0) |
279 | goto end_contraints; |
280 | |
281 | x509_ctx->basic_constraint_present = true; |
282 | x509_ctx->basic_constraint_is_critical = |
283 | asn1_is_critical_ext(cert, &offset); |
284 | |
285 | if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) < 0 || |
286 | asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0 || |
287 | asn1_get_bool(cert, &offset, &x509_ctx->basic_constraint_cA) < 0 || |
288 | asn1_get_int(cert, &offset, |
289 | &x509_ctx->basic_constraint_pathLenConstraint) < 0) |
290 | { |
291 | ret = X509_NOT_OK; |
292 | } |
293 | |
294 | end_contraints: |
295 | return ret; |
296 | } |
297 | |
298 | /* |
299 | * Key usage - see https://tools.ietf.org/html/rfc5280#section-4.2.1.3 |
300 | */ |
301 | static int x509_v3_key_usage(const uint8_t *cert, int offset, |
302 | X509_CTX *x509_ctx) |
303 | { |
304 | int ret = X509_OK; |
305 | |
306 | if ((offset = asn1_is_key_usage(cert, offset)) == 0) |
307 | goto end_key_usage; |
308 | |
309 | x509_ctx->key_usage_present = true; |
310 | x509_ctx->key_usage_is_critical = asn1_is_critical_ext(cert, &offset); |
311 | |
312 | if (asn1_next_obj(cert, &offset, ASN1_OCTET_STRING) < 0 || |
313 | asn1_get_bit_string_as_int(cert, &offset, &x509_ctx->key_usage)) |
314 | { |
315 | ret = X509_NOT_OK; |
316 | } |
317 | |
318 | end_key_usage: |
319 | return ret; |
320 | } |
321 | #endif |
322 | |
323 | /** |
324 | * Free an X.509 object's resources. |
325 | */ |
326 | void x509_free(X509_CTX *x509_ctx) |
327 | { |
328 | X509_CTX *next; |
329 | int i; |
330 | |
331 | if (x509_ctx == NULL) /* if already null, then don't bother */ |
332 | return; |
333 | |
334 | for (i = 0; i < X509_NUM_DN_TYPES; i++) |
335 | { |
336 | free(x509_ctx->ca_cert_dn[i]); |
337 | free(x509_ctx->cert_dn[i]); |
338 | } |
339 | |
340 | free(x509_ctx->signature); |
341 | |
342 | #ifdef CONFIG_SSL_CERT_VERIFICATION |
343 | if (x509_ctx->digest) |
344 | { |
345 | bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest); |
346 | } |
347 | |
348 | if (x509_ctx->subject_alt_dnsnames) |
349 | { |
350 | for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i) |
351 | free(x509_ctx->subject_alt_dnsnames[i]); |
352 | |
353 | free(x509_ctx->subject_alt_dnsnames); |
354 | } |
355 | #endif |
356 | |
357 | RSA_free(x509_ctx->rsa_ctx); |
358 | next = x509_ctx->next; |
359 | free(x509_ctx); |
360 | x509_free(next); /* clear the chain */ |
361 | } |
362 | |
363 | #ifdef CONFIG_SSL_CERT_VERIFICATION |
364 | /** |
365 | * Take a signature and decrypt it. |
366 | */ |
367 | static bigint *sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, |
368 | bigint *modulus, bigint *pub_exp) |
369 | { |
370 | int i, size; |
371 | bigint *decrypted_bi, *dat_bi; |
372 | bigint *bir = NULL; |
373 | uint8_t *block = (uint8_t *)alloca(sig_len); |
374 | |
375 | /* decrypt */ |
376 | dat_bi = bi_import(ctx, sig, sig_len); |
377 | ctx->mod_offset = BIGINT_M_OFFSET; |
378 | |
379 | /* convert to a normal block */ |
380 | decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp); |
381 | |
382 | bi_export(ctx, decrypted_bi, block, sig_len); |
383 | ctx->mod_offset = BIGINT_M_OFFSET; |
384 | |
385 | i = 10; /* start at the first possible non-padded byte */ |
386 | while (block[i++] && i < sig_len); |
387 | size = sig_len - i; |
388 | |
389 | /* get only the bit we want */ |
390 | if (size > 0) |
391 | { |
392 | int len; |
393 | const uint8_t *sig_ptr = get_signature(&block[i], &len); |
394 | |
395 | if (sig_ptr) |
396 | { |
397 | bir = bi_import(ctx, sig_ptr, len); |
398 | } |
399 | } |
400 | |
401 | /* save a few bytes of memory */ |
402 | bi_clear_cache(ctx); |
403 | return bir; |
404 | } |
405 | |
406 | /** |
407 | * Do some basic checks on the certificate chain. |
408 | * |
409 | * Certificate verification consists of a number of checks: |
410 | * - The date of the certificate is after the start date. |
411 | * - The date of the certificate is before the finish date. |
412 | * - A root certificate exists in the certificate store. |
413 | * - That the certificate(s) are not self-signed. |
414 | * - The certificate chain is valid. |
415 | * - The signature of the certificate is valid. |
416 | * - Basic constraints |
417 | */ |
418 | int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert, |
419 | int *pathLenConstraint) |
420 | { |
421 | int ret = X509_OK, i = 0; |
422 | bigint *cert_sig; |
423 | X509_CTX *next_cert = NULL; |
424 | BI_CTX *ctx = NULL; |
425 | bigint *mod = NULL, *expn = NULL; |
426 | int match_ca_cert = 0; |
427 | struct timeval tv; |
428 | uint8_t is_self_signed = 0; |
429 | |
430 | if (cert == NULL) |
431 | { |
432 | ret = X509_VFY_ERROR_NO_TRUSTED_CERT; |
433 | goto end_verify; |
434 | } |
435 | |
436 | /* a self-signed certificate that is not in the CA store - use this |
437 | to check the signature */ |
438 | if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0) |
439 | { |
440 | is_self_signed = 1; |
441 | ctx = cert->rsa_ctx->bi_ctx; |
442 | mod = cert->rsa_ctx->m; |
443 | expn = cert->rsa_ctx->e; |
444 | } |
445 | |
446 | gettimeofday(&tv, NULL); |
447 | |
448 | /* check the not before date */ |
449 | if (tv.tv_sec < cert->not_before) |
450 | { |
451 | ret = X509_VFY_ERROR_NOT_YET_VALID; |
452 | goto end_verify; |
453 | } |
454 | |
455 | /* check the not after date */ |
456 | if (tv.tv_sec > cert->not_after) |
457 | { |
458 | ret = X509_VFY_ERROR_EXPIRED; |
459 | goto end_verify; |
460 | } |
461 | |
462 | if (cert->basic_constraint_present) |
463 | { |
464 | /* If the cA boolean is not asserted, |
465 | then the keyCertSign bit in the key usage extension MUST NOT be |
466 | asserted. */ |
467 | if (!cert->basic_constraint_cA && |
468 | IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_CERT_SIGN)) |
469 | { |
470 | ret = X509_VFY_ERROR_BASIC_CONSTRAINT; |
471 | goto end_verify; |
472 | } |
473 | |
474 | /* The pathLenConstraint field is meaningful only if the cA boolean is |
475 | asserted and the key usage extension, if present, asserts the |
476 | keyCertSign bit. In this case, it gives the maximum number of |
477 | non-self-issued intermediate certificates that may follow this |
478 | certificate in a valid certification path. */ |
479 | if (cert->basic_constraint_cA && |
480 | (!cert->key_usage_present || |
481 | IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_CERT_SIGN)) && |
482 | (cert->basic_constraint_pathLenConstraint+1) < *pathLenConstraint) |
483 | { |
484 | ret = X509_VFY_ERROR_BASIC_CONSTRAINT; |
485 | goto end_verify; |
486 | } |
487 | } |
488 | |
489 | next_cert = cert->next; |
490 | |
491 | /* last cert in the chain - look for a trusted cert */ |
492 | if (next_cert == NULL) |
493 | { |
494 | if (ca_cert_ctx != NULL) |
495 | { |
496 | /* go thru the CA store */ |
497 | while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) |
498 | { |
499 | /* the extension is present but the cA boolean is not |
500 | asserted, then the certified public key MUST NOT be used |
501 | to verify certificate signatures. */ |
502 | if (cert->basic_constraint_present && |
503 | !ca_cert_ctx->cert[i]->basic_constraint_cA) |
504 | continue; |
505 | |
506 | if (asn1_compare_dn(cert->ca_cert_dn, |
507 | ca_cert_ctx->cert[i]->cert_dn) == 0) |
508 | { |
509 | /* use this CA certificate for signature verification */ |
510 | match_ca_cert = true; |
511 | ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx; |
512 | mod = ca_cert_ctx->cert[i]->rsa_ctx->m; |
513 | expn = ca_cert_ctx->cert[i]->rsa_ctx->e; |
514 | |
515 | |
516 | break; |
517 | } |
518 | |
519 | i++; |
520 | } |
521 | } |
522 | |
523 | /* couldn't find a trusted cert (& let self-signed errors |
524 | be returned) */ |
525 | if (!match_ca_cert && !is_self_signed) |
526 | { |
527 | ret = X509_VFY_ERROR_NO_TRUSTED_CERT; |
528 | goto end_verify; |
529 | } |
530 | } |
531 | else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0) |
532 | { |
533 | /* check the chain */ |
534 | ret = X509_VFY_ERROR_INVALID_CHAIN; |
535 | goto end_verify; |
536 | } |
537 | else /* use the next certificate in the chain for signature verify */ |
538 | { |
539 | ctx = next_cert->rsa_ctx->bi_ctx; |
540 | mod = next_cert->rsa_ctx->m; |
541 | expn = next_cert->rsa_ctx->e; |
542 | } |
543 | |
544 | /* cert is self signed */ |
545 | if (!match_ca_cert && is_self_signed) |
546 | { |
547 | ret = X509_VFY_ERROR_SELF_SIGNED; |
548 | goto end_verify; |
549 | } |
550 | |
551 | /* check the signature */ |
552 | cert_sig = sig_verify(ctx, cert->signature, cert->sig_len, |
553 | bi_clone(ctx, mod), bi_clone(ctx, expn)); |
554 | |
555 | if (cert_sig && cert->digest) |
556 | { |
557 | if (bi_compare(cert_sig, cert->digest) != 0) |
558 | ret = X509_VFY_ERROR_BAD_SIGNATURE; |
559 | |
560 | |
561 | bi_free(ctx, cert_sig); |
562 | } |
563 | else |
564 | { |
565 | ret = X509_VFY_ERROR_BAD_SIGNATURE; |
566 | } |
567 | |
568 | if (ret) |
569 | goto end_verify; |
570 | |
571 | /* go down the certificate chain using recursion. */ |
572 | if (next_cert != NULL) |
573 | { |
574 | (*pathLenConstraint)++; /* don't include last certificate */ |
575 | ret = x509_verify(ca_cert_ctx, next_cert, pathLenConstraint); |
576 | } |
577 | |
578 | end_verify: |
579 | return ret; |
580 | } |
581 | #endif |
582 | |
583 | #if defined (CONFIG_SSL_FULL_MODE) |
584 | /** |
585 | * Used for diagnostics. |
586 | */ |
587 | static const char *not_part_of_cert = "<Not Part Of Certificate>" ; |
588 | void x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx) |
589 | { |
590 | if (cert == NULL) |
591 | return; |
592 | |
593 | printf("=== CERTIFICATE ISSUED TO ===\n" ); |
594 | printf("Common Name (CN):\t\t" ); |
595 | printf("%s\n" , cert->cert_dn[X509_COMMON_NAME] ? |
596 | cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert); |
597 | |
598 | printf("Organization (O):\t\t" ); |
599 | printf("%s\n" , cert->cert_dn[X509_ORGANIZATION] ? |
600 | cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert); |
601 | |
602 | if (cert->cert_dn[X509_ORGANIZATIONAL_UNIT]) |
603 | { |
604 | printf("Organizational Unit (OU):\t" ); |
605 | printf("%s\n" , cert->cert_dn[X509_ORGANIZATIONAL_UNIT]); |
606 | } |
607 | |
608 | if (cert->cert_dn[X509_LOCATION]) |
609 | { |
610 | printf("Location (L):\t\t\t" ); |
611 | printf("%s\n" , cert->cert_dn[X509_LOCATION]); |
612 | } |
613 | |
614 | if (cert->cert_dn[X509_COUNTRY]) |
615 | { |
616 | printf("Country (C):\t\t\t" ); |
617 | printf("%s\n" , cert->cert_dn[X509_COUNTRY]); |
618 | } |
619 | |
620 | if (cert->cert_dn[X509_STATE]) |
621 | { |
622 | printf("State (ST):\t\t\t" ); |
623 | printf("%s\n" , cert->cert_dn[X509_STATE]); |
624 | } |
625 | |
626 | if (cert->basic_constraint_present) |
627 | { |
628 | printf("Basic Constraints:\t\t%sCA:%s, pathlen:%d\n" , |
629 | cert->basic_constraint_is_critical ? |
630 | "critical, " : "" , |
631 | cert->basic_constraint_cA? "TRUE" : "FALSE" , |
632 | cert->basic_constraint_pathLenConstraint); |
633 | } |
634 | |
635 | if (cert->key_usage_present) |
636 | { |
637 | printf("Key Usage:\t\t\t%s" , cert->key_usage_is_critical ? |
638 | "critical, " : "" ); |
639 | bool has_started = false; |
640 | |
641 | if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_DIGITAL_SIGNATURE)) |
642 | { |
643 | printf("Digital Signature" ); |
644 | has_started = true; |
645 | } |
646 | |
647 | if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_NON_REPUDIATION)) |
648 | { |
649 | if (has_started) |
650 | printf(", " ); |
651 | |
652 | printf("Non Repudiation" ); |
653 | has_started = true; |
654 | } |
655 | |
656 | if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_ENCIPHERMENT)) |
657 | { |
658 | if (has_started) |
659 | printf(", " ); |
660 | |
661 | printf("Key Encipherment" ); |
662 | has_started = true; |
663 | } |
664 | |
665 | if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_DATA_ENCIPHERMENT)) |
666 | { |
667 | if (has_started) |
668 | printf(", " ); |
669 | |
670 | printf("Data Encipherment" ); |
671 | has_started = true; |
672 | } |
673 | |
674 | if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_AGREEMENT)) |
675 | { |
676 | if (has_started) |
677 | printf(", " ); |
678 | |
679 | printf("Key Agreement" ); |
680 | has_started = true; |
681 | } |
682 | |
683 | if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_KEY_CERT_SIGN)) |
684 | { |
685 | if (has_started) |
686 | printf(", " ); |
687 | |
688 | printf("Key Cert Sign" ); |
689 | has_started = true; |
690 | } |
691 | |
692 | if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_CRL_SIGN)) |
693 | { |
694 | if (has_started) |
695 | printf(", " ); |
696 | |
697 | printf("CRL Sign" ); |
698 | has_started = true; |
699 | } |
700 | |
701 | if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_ENCIPHER_ONLY)) |
702 | { |
703 | if (has_started) |
704 | printf(", " ); |
705 | |
706 | printf("Encipher Only" ); |
707 | has_started = true; |
708 | } |
709 | |
710 | if (IS_SET_KEY_USAGE_FLAG(cert, KEY_USAGE_DECIPHER_ONLY)) |
711 | { |
712 | if (has_started) |
713 | printf(", " ); |
714 | |
715 | printf("Decipher Only" ); |
716 | has_started = true; |
717 | } |
718 | |
719 | printf("\n" ); |
720 | } |
721 | |
722 | if (cert->subject_alt_name_present) |
723 | { |
724 | printf("Subject Alt Name:\t\t%s" , cert->subject_alt_name_is_critical |
725 | ? "critical, " : "" ); |
726 | if (cert->subject_alt_dnsnames) |
727 | { |
728 | int i = 0; |
729 | |
730 | while (cert->subject_alt_dnsnames[i]) |
731 | printf("%s " , cert->subject_alt_dnsnames[i++]); |
732 | } |
733 | printf("\n" ); |
734 | |
735 | } |
736 | |
737 | printf("=== CERTIFICATE ISSUED BY ===\n" ); |
738 | printf("Common Name (CN):\t\t" ); |
739 | printf("%s\n" , cert->ca_cert_dn[X509_COMMON_NAME] ? |
740 | cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert); |
741 | |
742 | printf("Organization (O):\t\t" ); |
743 | printf("%s\n" , cert->ca_cert_dn[X509_ORGANIZATION] ? |
744 | cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert); |
745 | |
746 | if (cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT]) |
747 | { |
748 | printf("Organizational Unit (OU):\t" ); |
749 | printf("%s\n" , cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT]); |
750 | } |
751 | |
752 | if (cert->ca_cert_dn[X509_LOCATION]) |
753 | { |
754 | printf("Location (L):\t\t\t" ); |
755 | printf("%s\n" , cert->ca_cert_dn[X509_LOCATION]); |
756 | } |
757 | |
758 | if (cert->ca_cert_dn[X509_COUNTRY]) |
759 | { |
760 | printf("Country (C):\t\t\t" ); |
761 | printf("%s\n" , cert->ca_cert_dn[X509_COUNTRY]); |
762 | } |
763 | |
764 | if (cert->ca_cert_dn[X509_STATE]) |
765 | { |
766 | printf("State (ST):\t\t\t" ); |
767 | printf("%s\n" , cert->ca_cert_dn[X509_STATE]); |
768 | } |
769 | |
770 | printf("Not Before:\t\t\t%s" , ctime(&cert->not_before)); |
771 | printf("Not After:\t\t\t%s" , ctime(&cert->not_after)); |
772 | printf("RSA bitsize:\t\t\t%d\n" , cert->rsa_ctx->num_octets*8); |
773 | printf("Sig Type:\t\t\t" ); |
774 | switch (cert->sig_type) |
775 | { |
776 | case SIG_TYPE_MD5: |
777 | printf("MD5\n" ); |
778 | break; |
779 | case SIG_TYPE_SHA1: |
780 | printf("SHA1\n" ); |
781 | break; |
782 | case SIG_TYPE_SHA256: |
783 | printf("SHA256\n" ); |
784 | break; |
785 | case SIG_TYPE_SHA384: |
786 | printf("SHA384\n" ); |
787 | break; |
788 | case SIG_TYPE_SHA512: |
789 | printf("SHA512\n" ); |
790 | break; |
791 | default: |
792 | printf("Unrecognized: %d\n" , cert->sig_type); |
793 | break; |
794 | } |
795 | |
796 | if (ca_cert_ctx) |
797 | { |
798 | int pathLenConstraint = 0; |
799 | printf("Verify:\t\t\t\t%s\n" , |
800 | x509_display_error(x509_verify(ca_cert_ctx, cert, |
801 | &pathLenConstraint))); |
802 | } |
803 | |
804 | #if 0 |
805 | print_blob("Signature" , cert->signature, cert->sig_len); |
806 | bi_print("Modulus" , cert->rsa_ctx->m); |
807 | bi_print("Pub Exp" , cert->rsa_ctx->e); |
808 | #endif |
809 | |
810 | if (ca_cert_ctx) |
811 | { |
812 | x509_print(cert->next, ca_cert_ctx); |
813 | } |
814 | |
815 | TTY_FLUSH(); |
816 | } |
817 | #endif |
818 | |
819 | const char * x509_display_error(int error) |
820 | { |
821 | switch (error) |
822 | { |
823 | case X509_OK: |
824 | return "Certificate verify successful" ; |
825 | |
826 | case X509_NOT_OK: |
827 | return "X509 not ok" ; |
828 | |
829 | case X509_VFY_ERROR_NO_TRUSTED_CERT: |
830 | return "No trusted cert is available" ; |
831 | |
832 | case X509_VFY_ERROR_BAD_SIGNATURE: |
833 | return "Bad signature" ; |
834 | |
835 | case X509_VFY_ERROR_NOT_YET_VALID: |
836 | return "Cert is not yet valid" ; |
837 | |
838 | case X509_VFY_ERROR_EXPIRED: |
839 | return "Cert has expired" ; |
840 | |
841 | case X509_VFY_ERROR_SELF_SIGNED: |
842 | return "Cert is self-signed" ; |
843 | |
844 | case X509_VFY_ERROR_INVALID_CHAIN: |
845 | return "Chain is invalid (check order of certs)" ; |
846 | |
847 | case X509_VFY_ERROR_UNSUPPORTED_DIGEST: |
848 | return "Unsupported digest" ; |
849 | |
850 | case X509_INVALID_PRIV_KEY: |
851 | return "Invalid private key" ; |
852 | |
853 | case X509_VFY_ERROR_BASIC_CONSTRAINT: |
854 | return "Basic constraint invalid" ; |
855 | |
856 | default: |
857 | return "Unknown" ; |
858 | } |
859 | } |
860 | //#endif /* CONFIG_SSL_FULL_MODE */ |
861 | |
862 | |