| 
									
										
										
										
											2015-07-02 07:15:56 +08:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2020-04-23 20:55:52 +08:00
										 |  |  |  * Copyright 2015-2020 The OpenSSL Project Authors. All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2015-07-02 07:15:56 +08:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-12-06 20:05:25 +08:00
										 |  |  |  * Licensed under the Apache License 2.0 (the "License").  You may not use | 
					
						
							| 
									
										
										
										
											2016-05-18 02:20:24 +08:00
										 |  |  |  * this file except in compliance with the License.  You can obtain a copy | 
					
						
							|  |  |  |  * in the file LICENSE in the source distribution or at | 
					
						
							|  |  |  |  * https://www.openssl.org/source/license.html
 | 
					
						
							| 
									
										
										
										
											2015-07-02 07:15:56 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							| 
									
										
										
										
											2019-04-01 09:21:53 +08:00
										 |  |  | #include <string.h>
 | 
					
						
							| 
									
										
										
										
											2015-07-02 07:15:56 +08:00
										 |  |  | #include <openssl/crypto.h>
 | 
					
						
							|  |  |  | #include <openssl/bio.h>
 | 
					
						
							|  |  |  | #include <openssl/x509.h>
 | 
					
						
							|  |  |  | #include <openssl/pem.h>
 | 
					
						
							|  |  |  | #include <openssl/err.h>
 | 
					
						
							| 
									
										
										
										
											2017-04-12 11:12:04 +08:00
										 |  |  | #include "testutil.h"
 | 
					
						
							| 
									
										
										
										
											2015-07-02 07:15:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-18 09:48:27 +08:00
										 |  |  | static const char *roots_f; | 
					
						
							|  |  |  | static const char *untrusted_f; | 
					
						
							|  |  |  | static const char *bad_f; | 
					
						
							| 
									
										
										
										
											2019-06-05 14:46:48 +08:00
										 |  |  | static const char *req_f; | 
					
						
							| 
									
										
										
										
											2017-07-18 09:48:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-02 07:15:56 +08:00
										 |  |  | static STACK_OF(X509) *load_certs_from_file(const char *filename) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     STACK_OF(X509) *certs; | 
					
						
							|  |  |  |     BIO *bio; | 
					
						
							|  |  |  |     X509 *x; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bio = BIO_new_file(filename, "r"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (bio == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     certs = sk_X509_new_null(); | 
					
						
							|  |  |  |     if (certs == NULL) { | 
					
						
							|  |  |  |         BIO_free(bio); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ERR_set_mark(); | 
					
						
							|  |  |  |     do { | 
					
						
							|  |  |  |         x = PEM_read_bio_X509(bio, NULL, 0, NULL); | 
					
						
							|  |  |  |         if (x != NULL && !sk_X509_push(certs, x)) { | 
					
						
							|  |  |  |             sk_X509_pop_free(certs, X509_free); | 
					
						
							|  |  |  |             BIO_free(bio); | 
					
						
							|  |  |  |             return NULL; | 
					
						
							|  |  |  |         } else if (x == NULL) { | 
					
						
							|  |  |  |             /*
 | 
					
						
							|  |  |  |              * We probably just ran out of certs, so ignore any errors | 
					
						
							|  |  |  |              * generated | 
					
						
							|  |  |  |              */ | 
					
						
							|  |  |  |             ERR_pop_to_mark(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } while (x != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     BIO_free(bio); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return certs; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Test for CVE-2015-1793 (Alternate Chains Certificate Forgery) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Chain is as follows: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * rootCA (self-signed) | 
					
						
							|  |  |  |  *   | | 
					
						
							|  |  |  |  * interCA | 
					
						
							|  |  |  |  *   | | 
					
						
							|  |  |  |  * subinterCA       subinterCA (self-signed) | 
					
						
							|  |  |  |  *   |                   | | 
					
						
							|  |  |  |  * leaf ------------------ | 
					
						
							|  |  |  |  *   | | 
					
						
							|  |  |  |  * bad | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * rootCA, interCA, subinterCA, subinterCA (ss) all have CA=TRUE | 
					
						
							|  |  |  |  * leaf and bad have CA=FALSE | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * subinterCA and subinterCA (ss) have the same subject name and keys | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * interCA (but not rootCA) and subinterCA (ss) are in the trusted store | 
					
						
							|  |  |  |  * (roots.pem) | 
					
						
							|  |  |  |  * leaf and subinterCA are in the untrusted list (untrusted.pem) | 
					
						
							|  |  |  |  * bad is the certificate being verified (bad.pem) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Versions vulnerable to CVE-2015-1793 will fail to detect that leaf has | 
					
						
							|  |  |  |  * CA=FALSE, and will therefore incorrectly verify bad | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-07-18 09:48:27 +08:00
										 |  |  | static int test_alt_chains_cert_forgery(void) | 
					
						
							| 
									
										
										
										
											2015-07-02 07:15:56 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     int ret = 0; | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  |     X509 *x = NULL; | 
					
						
							|  |  |  |     STACK_OF(X509) *untrusted = NULL; | 
					
						
							|  |  |  |     BIO *bio = NULL; | 
					
						
							|  |  |  |     X509_STORE_CTX *sctx = NULL; | 
					
						
							|  |  |  |     X509_STORE *store = NULL; | 
					
						
							|  |  |  |     X509_LOOKUP *lookup = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     store = X509_STORE_new(); | 
					
						
							|  |  |  |     if (store == NULL) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); | 
					
						
							|  |  |  |     if (lookup == NULL) | 
					
						
							|  |  |  |         goto err; | 
					
						
							| 
									
										
										
										
											2016-08-24 06:17:31 +08:00
										 |  |  |     if (!X509_LOOKUP_load_file(lookup, roots_f, X509_FILETYPE_PEM)) | 
					
						
							| 
									
										
										
										
											2015-07-02 07:15:56 +08:00
										 |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-04 23:04:33 +08:00
										 |  |  |     untrusted = load_certs_from_file(untrusted_f); | 
					
						
							| 
									
										
										
										
											2015-07-02 07:15:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-04 23:04:33 +08:00
										 |  |  |     if ((bio = BIO_new_file(bad_f, "r")) == NULL) | 
					
						
							| 
									
										
										
										
											2015-07-02 07:15:56 +08:00
										 |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-24 06:17:31 +08:00
										 |  |  |     if ((x = PEM_read_bio_X509(bio, NULL, 0, NULL)) == NULL) | 
					
						
							| 
									
										
										
										
											2015-07-02 07:15:56 +08:00
										 |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sctx = X509_STORE_CTX_new(); | 
					
						
							|  |  |  |     if (sctx == NULL) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!X509_STORE_CTX_init(sctx, store, x, untrusted)) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     i = X509_verify_cert(sctx); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-29 06:18:50 +08:00
										 |  |  |     if (i == 0 && X509_STORE_CTX_get_error(sctx) == X509_V_ERR_INVALID_CA) { | 
					
						
							| 
									
										
										
										
											2015-07-02 07:15:56 +08:00
										 |  |  |         /* This is the result we were expecting: Test passed */ | 
					
						
							|  |  |  |         ret = 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |  err: | 
					
						
							|  |  |  |     X509_STORE_CTX_free(sctx); | 
					
						
							|  |  |  |     X509_free(x); | 
					
						
							|  |  |  |     BIO_free(bio); | 
					
						
							|  |  |  |     sk_X509_pop_free(untrusted, X509_free); | 
					
						
							|  |  |  |     X509_STORE_free(store); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-18 21:22:36 +08:00
										 |  |  | static int test_store_ctx(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     X509_STORE_CTX *sctx = NULL; | 
					
						
							|  |  |  |     X509 *x = NULL; | 
					
						
							|  |  |  |     BIO *bio = NULL; | 
					
						
							|  |  |  |     int testresult = 0, ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bio = BIO_new_file(bad_f, "r"); | 
					
						
							|  |  |  |     if (bio == NULL) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     x = PEM_read_bio_X509(bio, NULL, 0, NULL); | 
					
						
							|  |  |  |     if (x == NULL) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sctx = X509_STORE_CTX_new(); | 
					
						
							|  |  |  |     if (sctx == NULL) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!X509_STORE_CTX_init(sctx, NULL, x, NULL)) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Verifying a cert where we have no trusted certs should fail */ | 
					
						
							|  |  |  |     ret = X509_verify_cert(sctx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (ret == 0) { | 
					
						
							|  |  |  |         /* This is the result we were expecting: Test passed */ | 
					
						
							|  |  |  |         testresult = 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  err: | 
					
						
							|  |  |  |     X509_STORE_CTX_free(sctx); | 
					
						
							|  |  |  |     X509_free(x); | 
					
						
							|  |  |  |     BIO_free(bio); | 
					
						
							|  |  |  |     return testresult; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 10:36:01 +08:00
										 |  |  | OPT_TEST_DECLARE_USAGE("roots.pem untrusted.pem bad.pem\n") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-11 06:10:29 +08:00
										 |  |  | static int test_distinguishing_id(void) | 
					
						
							| 
									
										
										
										
											2019-04-01 09:21:53 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     X509 *x = NULL; | 
					
						
							|  |  |  |     BIO *bio = NULL; | 
					
						
							|  |  |  |     int ret = 0; | 
					
						
							|  |  |  |     ASN1_OCTET_STRING *v = NULL, *v2 = NULL; | 
					
						
							| 
									
										
										
										
											2020-03-11 06:10:29 +08:00
										 |  |  |     char *distid = "this is an ID"; | 
					
						
							| 
									
										
										
										
											2019-04-01 09:21:53 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     bio = BIO_new_file(bad_f, "r"); | 
					
						
							|  |  |  |     if (bio == NULL) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     x = PEM_read_bio_X509(bio, NULL, 0, NULL); | 
					
						
							|  |  |  |     if (x == NULL) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     v = ASN1_OCTET_STRING_new(); | 
					
						
							|  |  |  |     if (v == NULL) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-11 06:10:29 +08:00
										 |  |  |     if (!ASN1_OCTET_STRING_set(v, (unsigned char *)distid, | 
					
						
							|  |  |  |                                (int)strlen(distid))) { | 
					
						
							| 
									
										
										
										
											2019-04-01 09:21:53 +08:00
										 |  |  |         ASN1_OCTET_STRING_free(v); | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-11 06:10:29 +08:00
										 |  |  |     X509_set0_distinguishing_id(x, v); | 
					
						
							| 
									
										
										
										
											2019-04-01 09:21:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-11 06:10:29 +08:00
										 |  |  |     v2 = X509_get0_distinguishing_id(x); | 
					
						
							| 
									
										
										
										
											2019-04-01 09:21:53 +08:00
										 |  |  |     if (!TEST_ptr(v2) | 
					
						
							|  |  |  |             || !TEST_int_eq(ASN1_OCTET_STRING_cmp(v, v2), 0)) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ret = 1; | 
					
						
							|  |  |  |  err: | 
					
						
							|  |  |  |     X509_free(x); | 
					
						
							|  |  |  |     BIO_free(bio); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-06-05 14:46:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-11 06:10:29 +08:00
										 |  |  | static int test_req_distinguishing_id(void) | 
					
						
							| 
									
										
										
										
											2019-06-05 14:46:48 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     X509_REQ *x = NULL; | 
					
						
							|  |  |  |     BIO *bio = NULL; | 
					
						
							|  |  |  |     int ret = 0; | 
					
						
							|  |  |  |     ASN1_OCTET_STRING *v = NULL, *v2 = NULL; | 
					
						
							| 
									
										
										
										
											2020-03-11 06:10:29 +08:00
										 |  |  |     char *distid = "this is an ID"; | 
					
						
							| 
									
										
										
										
											2019-06-05 14:46:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     bio = BIO_new_file(req_f, "r"); | 
					
						
							|  |  |  |     if (bio == NULL) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     x = PEM_read_bio_X509_REQ(bio, NULL, 0, NULL); | 
					
						
							|  |  |  |     if (x == NULL) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     v = ASN1_OCTET_STRING_new(); | 
					
						
							|  |  |  |     if (v == NULL) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-11 06:10:29 +08:00
										 |  |  |     if (!ASN1_OCTET_STRING_set(v, (unsigned char *)distid, | 
					
						
							|  |  |  |                                (int)strlen(distid))) { | 
					
						
							| 
									
										
										
										
											2019-06-05 14:46:48 +08:00
										 |  |  |         ASN1_OCTET_STRING_free(v); | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-11 06:10:29 +08:00
										 |  |  |     X509_REQ_set0_distinguishing_id(x, v); | 
					
						
							| 
									
										
										
										
											2019-06-05 14:46:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-11 06:10:29 +08:00
										 |  |  |     v2 = X509_REQ_get0_distinguishing_id(x); | 
					
						
							| 
									
										
										
										
											2019-06-05 14:46:48 +08:00
										 |  |  |     if (!TEST_ptr(v2) | 
					
						
							|  |  |  |             || !TEST_int_eq(ASN1_OCTET_STRING_cmp(v, v2), 0)) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ret = 1; | 
					
						
							|  |  |  |  err: | 
					
						
							|  |  |  |     X509_REQ_free(x); | 
					
						
							|  |  |  |     BIO_free(bio); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-04-01 09:21:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-18 09:48:27 +08:00
										 |  |  | int setup_tests(void) | 
					
						
							| 
									
										
										
										
											2015-07-02 07:15:56 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-01-30 23:30:17 +08:00
										 |  |  |     if (!test_skip_common_options()) { | 
					
						
							|  |  |  |         TEST_error("Error parsing test options\n"); | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-18 09:48:27 +08:00
										 |  |  |     if (!TEST_ptr(roots_f = test_get_argument(0)) | 
					
						
							|  |  |  |             || !TEST_ptr(untrusted_f = test_get_argument(1)) | 
					
						
							| 
									
										
										
										
											2019-06-05 14:46:48 +08:00
										 |  |  |             || !TEST_ptr(bad_f = test_get_argument(2)) | 
					
						
							|  |  |  |             || !TEST_ptr(req_f = test_get_argument(3))) | 
					
						
							| 
									
										
										
										
											2017-07-18 09:48:27 +08:00
										 |  |  |         return 0; | 
					
						
							| 
									
										
										
										
											2015-07-02 07:15:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-18 09:48:27 +08:00
										 |  |  |     ADD_TEST(test_alt_chains_cert_forgery); | 
					
						
							| 
									
										
										
										
											2018-04-18 21:22:36 +08:00
										 |  |  |     ADD_TEST(test_store_ctx); | 
					
						
							| 
									
										
										
										
											2020-03-11 06:10:29 +08:00
										 |  |  |     ADD_TEST(test_distinguishing_id); | 
					
						
							|  |  |  |     ADD_TEST(test_req_distinguishing_id); | 
					
						
							| 
									
										
										
										
											2017-07-18 09:48:27 +08:00
										 |  |  |     return 1; | 
					
						
							| 
									
										
										
										
											2015-07-02 07:15:56 +08:00
										 |  |  | } |