|  | /* | 
|  | * Written by Matt Caswell for the OpenSSL project. | 
|  | */ | 
|  | /* ==================================================================== | 
|  | * Copyright (c) 1998-2015 The OpenSSL Project.  All rights reserved. | 
|  | * | 
|  | * Redistribution and use in source and binary forms, with or without | 
|  | * modification, are permitted provided that the following conditions | 
|  | * are met: | 
|  | * | 
|  | * 1. Redistributions of source code must retain the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer. | 
|  | * | 
|  | * 2. Redistributions in binary form must reproduce the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer in | 
|  | *    the documentation and/or other materials provided with the | 
|  | *    distribution. | 
|  | * | 
|  | * 3. All advertising materials mentioning features or use of this | 
|  | *    software must display the following acknowledgment: | 
|  | *    "This product includes software developed by the OpenSSL Project | 
|  | *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)" | 
|  | * | 
|  | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | 
|  | *    endorse or promote products derived from this software without | 
|  | *    prior written permission. For written permission, please contact | 
|  | *    openssl-core@openssl.org. | 
|  | * | 
|  | * 5. Products derived from this software may not be called "OpenSSL" | 
|  | *    nor may "OpenSSL" appear in their names without prior written | 
|  | *    permission of the OpenSSL Project. | 
|  | * | 
|  | * 6. Redistributions of any form whatsoever must retain the following | 
|  | *    acknowledgment: | 
|  | *    "This product includes software developed by the OpenSSL Project | 
|  | *    for use in the OpenSSL Toolkit (http://www.openssl.org/)" | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | 
|  | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|  | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
|  | * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR | 
|  | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 
|  | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 
|  | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
|  | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | 
|  | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 
|  | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | 
|  | * OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | * ==================================================================== | 
|  | * | 
|  | * This product includes cryptographic software written by Eric Young | 
|  | * (eay@cryptsoft.com).  This product includes software written by Tim | 
|  | * Hudson (tjh@cryptsoft.com). | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <openssl/crypto.h> | 
|  | #include <openssl/bio.h> | 
|  | #include <openssl/x509.h> | 
|  | #include <openssl/pem.h> | 
|  | #include <openssl/err.h> | 
|  |  | 
|  | 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 | 
|  | * | 
|  | */ | 
|  | static int test_alt_chains_cert_forgery(const char *roots_f, | 
|  | const char *untrusted_f, | 
|  | const char *bad_f) | 
|  | { | 
|  | 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; | 
|  | if(!X509_LOOKUP_load_file(lookup, roots_f, X509_FILETYPE_PEM)) | 
|  | goto err; | 
|  |  | 
|  | untrusted = load_certs_from_file(untrusted_f); | 
|  |  | 
|  | if ((bio = BIO_new_file(bad_f, "r")) == NULL) | 
|  | goto err; | 
|  |  | 
|  | if((x = PEM_read_bio_X509(bio, NULL, 0, NULL)) == NULL) | 
|  | 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); | 
|  |  | 
|  | if(i == 0 && X509_STORE_CTX_get_error(sctx) == X509_V_ERR_INVALID_CA) { | 
|  | /* 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); | 
|  | if (ret != 1) | 
|  | ERR_print_errors_fp(stderr); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | int main(int argc, char **argv) | 
|  | { | 
|  | CRYPTO_set_mem_debug(1); | 
|  | CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); | 
|  |  | 
|  | if (argc != 4) { | 
|  | fprintf(stderr, "usage: verify_extra_test roots.pem untrusted.pem bad.pem\n"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | if (!test_alt_chains_cert_forgery(argv[1], argv[2], argv[3])) { | 
|  | fprintf(stderr, "Test alt chains cert forgery failed\n"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | #ifndef OPENSSL_NO_CRYPTO_MDEBUG | 
|  | if (CRYPTO_mem_leaks_fp(stderr) <= 0) | 
|  | return 1; | 
|  | #endif | 
|  |  | 
|  | printf("PASS\n"); | 
|  | return 0; | 
|  | } |