1285327Sjkim/*
2285327Sjkim * Written by Matt Caswell for the OpenSSL project.
3285327Sjkim */
4285327Sjkim/* ====================================================================
5285327Sjkim * Copyright (c) 1998-2015 The OpenSSL Project.  All rights reserved.
6285327Sjkim *
7285327Sjkim * Redistribution and use in source and binary forms, with or without
8285327Sjkim * modification, are permitted provided that the following conditions
9285327Sjkim * are met:
10285327Sjkim *
11285327Sjkim * 1. Redistributions of source code must retain the above copyright
12285327Sjkim *    notice, this list of conditions and the following disclaimer.
13285327Sjkim *
14285327Sjkim * 2. Redistributions in binary form must reproduce the above copyright
15285327Sjkim *    notice, this list of conditions and the following disclaimer in
16285327Sjkim *    the documentation and/or other materials provided with the
17285327Sjkim *    distribution.
18285327Sjkim *
19285327Sjkim * 3. All advertising materials mentioning features or use of this
20285327Sjkim *    software must display the following acknowledgment:
21285327Sjkim *    "This product includes software developed by the OpenSSL Project
22285327Sjkim *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
23285327Sjkim *
24285327Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25285327Sjkim *    endorse or promote products derived from this software without
26285327Sjkim *    prior written permission. For written permission, please contact
27285327Sjkim *    openssl-core@openssl.org.
28285327Sjkim *
29285327Sjkim * 5. Products derived from this software may not be called "OpenSSL"
30285327Sjkim *    nor may "OpenSSL" appear in their names without prior written
31285327Sjkim *    permission of the OpenSSL Project.
32285327Sjkim *
33285327Sjkim * 6. Redistributions of any form whatsoever must retain the following
34285327Sjkim *    acknowledgment:
35285327Sjkim *    "This product includes software developed by the OpenSSL Project
36285327Sjkim *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
37285327Sjkim *
38285327Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39285327Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40285327Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41285327Sjkim * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
42285327Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43285327Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44285327Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45285327Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46285327Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47285327Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48285327Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49285327Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE.
50285327Sjkim * ====================================================================
51285327Sjkim *
52285327Sjkim * This product includes cryptographic software written by Eric Young
53285327Sjkim * (eay@cryptsoft.com).  This product includes software written by Tim
54285327Sjkim * Hudson (tjh@cryptsoft.com).
55285327Sjkim *
56285327Sjkim */
57285327Sjkim
58285327Sjkim#include <stdio.h>
59285327Sjkim#include <openssl/crypto.h>
60285327Sjkim#include <openssl/bio.h>
61285327Sjkim#include <openssl/x509.h>
62285327Sjkim#include <openssl/pem.h>
63285327Sjkim#include <openssl/err.h>
64285327Sjkim
65285327Sjkimstatic STACK_OF(X509) *load_certs_from_file(const char *filename)
66285327Sjkim{
67285327Sjkim    STACK_OF(X509) *certs;
68285327Sjkim    BIO *bio;
69285327Sjkim    X509 *x;
70285327Sjkim
71285327Sjkim    bio = BIO_new_file(filename, "r");
72285327Sjkim
73285327Sjkim    if (bio == NULL) {
74285327Sjkim        return NULL;
75285327Sjkim    }
76285327Sjkim
77285327Sjkim    certs = sk_X509_new_null();
78285327Sjkim    if (certs == NULL) {
79285327Sjkim        BIO_free(bio);
80285327Sjkim        return NULL;
81285327Sjkim    }
82285327Sjkim
83285327Sjkim    ERR_set_mark();
84285327Sjkim    do {
85285327Sjkim        x = PEM_read_bio_X509(bio, NULL, 0, NULL);
86285327Sjkim        if (x != NULL && !sk_X509_push(certs, x)) {
87285327Sjkim            sk_X509_pop_free(certs, X509_free);
88285327Sjkim            BIO_free(bio);
89285327Sjkim            return NULL;
90285327Sjkim        } else if (x == NULL) {
91285327Sjkim            /*
92285327Sjkim             * We probably just ran out of certs, so ignore any errors
93285327Sjkim             * generated
94285327Sjkim             */
95285327Sjkim            ERR_pop_to_mark();
96285327Sjkim        }
97285327Sjkim    } while (x != NULL);
98285327Sjkim
99285327Sjkim    BIO_free(bio);
100285327Sjkim
101285327Sjkim    return certs;
102285327Sjkim}
103285327Sjkim
104285327Sjkim/*
105285327Sjkim * Test for CVE-2015-1793 (Alternate Chains Certificate Forgery)
106285327Sjkim *
107285327Sjkim * Chain is as follows:
108285327Sjkim *
109285327Sjkim * rootCA (self-signed)
110285327Sjkim *   |
111285327Sjkim * interCA
112285327Sjkim *   |
113285327Sjkim * subinterCA       subinterCA (self-signed)
114285327Sjkim *   |                   |
115285327Sjkim * leaf ------------------
116285327Sjkim *   |
117285327Sjkim * bad
118285327Sjkim *
119285327Sjkim * rootCA, interCA, subinterCA, subinterCA (ss) all have CA=TRUE
120285327Sjkim * leaf and bad have CA=FALSE
121285327Sjkim *
122285327Sjkim * subinterCA and subinterCA (ss) have the same subject name and keys
123285327Sjkim *
124285327Sjkim * interCA (but not rootCA) and subinterCA (ss) are in the trusted store
125285327Sjkim * (roots.pem)
126285327Sjkim * leaf and subinterCA are in the untrusted list (untrusted.pem)
127285327Sjkim * bad is the certificate being verified (bad.pem)
128285327Sjkim *
129285327Sjkim * Versions vulnerable to CVE-2015-1793 will fail to detect that leaf has
130285327Sjkim * CA=FALSE, and will therefore incorrectly verify bad
131285327Sjkim *
132285327Sjkim */
133285327Sjkimstatic int test_alt_chains_cert_forgery(void)
134285327Sjkim{
135285327Sjkim    int ret = 0;
136285327Sjkim    int i;
137285327Sjkim    X509 *x = NULL;
138285327Sjkim    STACK_OF(X509) *untrusted = NULL;
139285327Sjkim    BIO *bio = NULL;
140285327Sjkim    X509_STORE_CTX *sctx = NULL;
141285327Sjkim    X509_STORE *store = NULL;
142285327Sjkim    X509_LOOKUP *lookup = NULL;
143285327Sjkim
144285327Sjkim    store = X509_STORE_new();
145285327Sjkim    if (store == NULL)
146285327Sjkim        goto err;
147285327Sjkim
148285327Sjkim    lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
149285327Sjkim    if (lookup == NULL)
150285327Sjkim        goto err;
151285327Sjkim    if(!X509_LOOKUP_load_file(lookup, "certs/roots.pem", X509_FILETYPE_PEM))
152285327Sjkim        goto err;
153285327Sjkim
154285327Sjkim    untrusted = load_certs_from_file("certs/untrusted.pem");
155285327Sjkim
156285327Sjkim    if ((bio = BIO_new_file("certs/bad.pem", "r")) == NULL)
157285327Sjkim        goto err;
158285327Sjkim
159285327Sjkim    if((x = PEM_read_bio_X509(bio, NULL, 0, NULL)) == NULL)
160285327Sjkim        goto err;
161285327Sjkim
162285327Sjkim    sctx = X509_STORE_CTX_new();
163285327Sjkim    if (sctx == NULL)
164285327Sjkim        goto err;
165285327Sjkim
166285327Sjkim    if (!X509_STORE_CTX_init(sctx, store, x, untrusted))
167285327Sjkim        goto err;
168285327Sjkim
169285327Sjkim    i = X509_verify_cert(sctx);
170285327Sjkim
171285327Sjkim    if(i == 0 && X509_STORE_CTX_get_error(sctx)
172285327Sjkim                 == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) {
173285327Sjkim        /* This is the result we were expecting: Test passed */
174285327Sjkim        ret = 1;
175285327Sjkim    }
176285327Sjkim err:
177285327Sjkim    X509_STORE_CTX_free(sctx);
178285327Sjkim    X509_free(x);
179285327Sjkim    BIO_free(bio);
180285327Sjkim    sk_X509_pop_free(untrusted, X509_free);
181285327Sjkim    X509_STORE_free(store);
182285327Sjkim    if (ret != 1)
183285327Sjkim        ERR_print_errors_fp(stderr);
184285327Sjkim    return ret;
185285327Sjkim}
186285327Sjkim
187285327Sjkimint main(void)
188285327Sjkim{
189285327Sjkim    CRYPTO_malloc_debug_init();
190285327Sjkim    CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL);
191285327Sjkim    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
192285327Sjkim
193285327Sjkim    ERR_load_crypto_strings();
194285327Sjkim    OpenSSL_add_all_digests();
195285327Sjkim
196285327Sjkim    if (!test_alt_chains_cert_forgery()) {
197285327Sjkim        fprintf(stderr, "Test alt chains cert forgery failed\n");
198285327Sjkim        return 1;
199285327Sjkim    }
200285327Sjkim
201285327Sjkim    EVP_cleanup();
202285327Sjkim    CRYPTO_cleanup_all_ex_data();
203285327Sjkim    ERR_remove_thread_state(NULL);
204285327Sjkim    ERR_free_strings();
205285327Sjkim    CRYPTO_mem_leaks_fp(stderr);
206285327Sjkim
207285327Sjkim    printf("PASS\n");
208285327Sjkim    return 0;
209285327Sjkim}
210