1 /* 2 * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <stdio.h> 11 #include <openssl/crypto.h> 12 #include <openssl/bio.h> 13 #include <openssl/x509.h> 14 #include <openssl/pem.h> 15 #include <openssl/err.h> 16 17 static STACK_OF(X509) *load_certs_from_file(const char *filename) 18 { 19 STACK_OF(X509) *certs; 20 BIO *bio; 21 X509 *x; 22 23 bio = BIO_new_file(filename, "r"); 24 25 if (bio == NULL) { 26 return NULL; 27 } 28 29 certs = sk_X509_new_null(); 30 if (certs == NULL) { 31 BIO_free(bio); 32 return NULL; 33 } 34 35 ERR_set_mark(); 36 do { 37 x = PEM_read_bio_X509(bio, NULL, 0, NULL); 38 if (x != NULL && !sk_X509_push(certs, x)) { 39 sk_X509_pop_free(certs, X509_free); 40 BIO_free(bio); 41 return NULL; 42 } else if (x == NULL) { 43 /* 44 * We probably just ran out of certs, so ignore any errors 45 * generated 46 */ 47 ERR_pop_to_mark(); 48 } 49 } while (x != NULL); 50 51 BIO_free(bio); 52 53 return certs; 54 } 55 56 /* 57 * Test for CVE-2015-1793 (Alternate Chains Certificate Forgery) 58 * 59 * Chain is as follows: 60 * 61 * rootCA (self-signed) 62 * | 63 * interCA 64 * | 65 * subinterCA subinterCA (self-signed) 66 * | | 67 * leaf ------------------ 68 * | 69 * bad 70 * 71 * rootCA, interCA, subinterCA, subinterCA (ss) all have CA=TRUE 72 * leaf and bad have CA=FALSE 73 * 74 * subinterCA and subinterCA (ss) have the same subject name and keys 75 * 76 * interCA (but not rootCA) and subinterCA (ss) are in the trusted store 77 * (roots.pem) 78 * leaf and subinterCA are in the untrusted list (untrusted.pem) 79 * bad is the certificate being verified (bad.pem) 80 * 81 * Versions vulnerable to CVE-2015-1793 will fail to detect that leaf has 82 * CA=FALSE, and will therefore incorrectly verify bad 83 * 84 */ 85 static int test_alt_chains_cert_forgery(const char *roots_f, 86 const char *untrusted_f, 87 const char *bad_f) 88 { 89 int ret = 0; 90 int i; 91 X509 *x = NULL; 92 STACK_OF(X509) *untrusted = NULL; 93 BIO *bio = NULL; 94 X509_STORE_CTX *sctx = NULL; 95 X509_STORE *store = NULL; 96 X509_LOOKUP *lookup = NULL; 97 98 store = X509_STORE_new(); 99 if (store == NULL) 100 goto err; 101 102 lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); 103 if (lookup == NULL) 104 goto err; 105 if(!X509_LOOKUP_load_file(lookup, roots_f, X509_FILETYPE_PEM)) 106 goto err; 107 108 untrusted = load_certs_from_file(untrusted_f); 109 110 if ((bio = BIO_new_file(bad_f, "r")) == NULL) 111 goto err; 112 113 if((x = PEM_read_bio_X509(bio, NULL, 0, NULL)) == NULL) 114 goto err; 115 116 sctx = X509_STORE_CTX_new(); 117 if (sctx == NULL) 118 goto err; 119 120 if (!X509_STORE_CTX_init(sctx, store, x, untrusted)) 121 goto err; 122 123 i = X509_verify_cert(sctx); 124 125 if (i == 0 && X509_STORE_CTX_get_error(sctx) == X509_V_ERR_INVALID_CA) { 126 /* This is the result we were expecting: Test passed */ 127 ret = 1; 128 } 129 err: 130 X509_STORE_CTX_free(sctx); 131 X509_free(x); 132 BIO_free(bio); 133 sk_X509_pop_free(untrusted, X509_free); 134 X509_STORE_free(store); 135 if (ret != 1) 136 ERR_print_errors_fp(stderr); 137 return ret; 138 } 139 140 int main(int argc, char **argv) 141 { 142 CRYPTO_set_mem_debug(1); 143 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); 144 145 if (argc != 4) { 146 fprintf(stderr, "usage: verify_extra_test roots.pem untrusted.pem bad.pem\n"); 147 return 1; 148 } 149 150 if (!test_alt_chains_cert_forgery(argv[1], argv[2], argv[3])) { 151 fprintf(stderr, "Test alt chains cert forgery failed\n"); 152 return 1; 153 } 154 155 #ifndef OPENSSL_NO_CRYPTO_MDEBUG 156 if (CRYPTO_mem_leaks_fp(stderr) <= 0) 157 return 1; 158 #endif 159 160 printf("PASS\n"); 161 return 0; 162 } 163