add ASN1_INTEGER type to d2i_test
[openssl.git] / test / verify_extra_test.c
1 /*
2  * Written by Matt Caswell for the OpenSSL project.
3  */
4 /* ====================================================================
5  * Copyright (c) 1998-2015 The OpenSSL Project.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. All advertising materials mentioning features or use of this
20  *    software must display the following acknowledgment:
21  *    "This product includes software developed by the OpenSSL Project
22  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
23  *
24  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25  *    endorse or promote products derived from this software without
26  *    prior written permission. For written permission, please contact
27  *    openssl-core@openssl.org.
28  *
29  * 5. Products derived from this software may not be called "OpenSSL"
30  *    nor may "OpenSSL" appear in their names without prior written
31  *    permission of the OpenSSL Project.
32  *
33  * 6. Redistributions of any form whatsoever must retain the following
34  *    acknowledgment:
35  *    "This product includes software developed by the OpenSSL Project
36  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
37  *
38  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
42  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49  * OF THE POSSIBILITY OF SUCH DAMAGE.
50  * ====================================================================
51  *
52  * This product includes cryptographic software written by Eric Young
53  * (eay@cryptsoft.com).  This product includes software written by Tim
54  * Hudson (tjh@cryptsoft.com).
55  *
56  */
57
58 #include <stdio.h>
59 #include <openssl/crypto.h>
60 #include <openssl/bio.h>
61 #include <openssl/x509.h>
62 #include <openssl/pem.h>
63 #include <openssl/err.h>
64
65 static STACK_OF(X509) *load_certs_from_file(const char *filename)
66 {
67     STACK_OF(X509) *certs;
68     BIO *bio;
69     X509 *x;
70
71     bio = BIO_new_file(filename, "r");
72
73     if (bio == NULL) {
74         return NULL;
75     }
76
77     certs = sk_X509_new_null();
78     if (certs == NULL) {
79         BIO_free(bio);
80         return NULL;
81     }
82
83     ERR_set_mark();
84     do {
85         x = PEM_read_bio_X509(bio, NULL, 0, NULL);
86         if (x != NULL && !sk_X509_push(certs, x)) {
87             sk_X509_pop_free(certs, X509_free);
88             BIO_free(bio);
89             return NULL;
90         } else if (x == NULL) {
91             /*
92              * We probably just ran out of certs, so ignore any errors
93              * generated
94              */
95             ERR_pop_to_mark();
96         }
97     } while (x != NULL);
98
99     BIO_free(bio);
100
101     return certs;
102 }
103
104 /*
105  * Test for CVE-2015-1793 (Alternate Chains Certificate Forgery)
106  *
107  * Chain is as follows:
108  *
109  * rootCA (self-signed)
110  *   |
111  * interCA
112  *   |
113  * subinterCA       subinterCA (self-signed)
114  *   |                   |
115  * leaf ------------------
116  *   |
117  * bad
118  *
119  * rootCA, interCA, subinterCA, subinterCA (ss) all have CA=TRUE
120  * leaf and bad have CA=FALSE
121  *
122  * subinterCA and subinterCA (ss) have the same subject name and keys
123  *
124  * interCA (but not rootCA) and subinterCA (ss) are in the trusted store
125  * (roots.pem)
126  * leaf and subinterCA are in the untrusted list (untrusted.pem)
127  * bad is the certificate being verified (bad.pem)
128  *
129  * Versions vulnerable to CVE-2015-1793 will fail to detect that leaf has
130  * CA=FALSE, and will therefore incorrectly verify bad
131  *
132  */
133 static int test_alt_chains_cert_forgery(const char *roots_f,
134                                         const char *untrusted_f,
135                                         const char *bad_f)
136 {
137     int ret = 0;
138     int i;
139     X509 *x = NULL;
140     STACK_OF(X509) *untrusted = NULL;
141     BIO *bio = NULL;
142     X509_STORE_CTX *sctx = NULL;
143     X509_STORE *store = NULL;
144     X509_LOOKUP *lookup = NULL;
145
146     store = X509_STORE_new();
147     if (store == NULL)
148         goto err;
149
150     lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
151     if (lookup == NULL)
152         goto err;
153     if(!X509_LOOKUP_load_file(lookup, roots_f, X509_FILETYPE_PEM))
154         goto err;
155
156     untrusted = load_certs_from_file(untrusted_f);
157
158     if ((bio = BIO_new_file(bad_f, "r")) == NULL)
159         goto err;
160
161     if((x = PEM_read_bio_X509(bio, NULL, 0, NULL)) == NULL)
162         goto err;
163
164     sctx = X509_STORE_CTX_new();
165     if (sctx == NULL)
166         goto err;
167
168     if (!X509_STORE_CTX_init(sctx, store, x, untrusted))
169         goto err;
170
171     i = X509_verify_cert(sctx);
172
173     if(i == 0 && X509_STORE_CTX_get_error(sctx) == X509_V_ERR_INVALID_CA) {
174         /* This is the result we were expecting: Test passed */
175         ret = 1;
176     }
177  err:
178     X509_STORE_CTX_free(sctx);
179     X509_free(x);
180     BIO_free(bio);
181     sk_X509_pop_free(untrusted, X509_free);
182     X509_STORE_free(store);
183     if (ret != 1)
184         ERR_print_errors_fp(stderr);
185     return ret;
186 }
187
188 int main(int argc, char **argv)
189 {
190     CRYPTO_set_mem_debug(1);
191     CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
192
193     if (argc != 4) {
194         fprintf(stderr, "usage: verify_extra_test roots.pem untrusted.pem bad.pem\n");
195         return 1;
196     }
197
198     if (!test_alt_chains_cert_forgery(argv[1], argv[2], argv[3])) {
199         fprintf(stderr, "Test alt chains cert forgery failed\n");
200         return 1;
201     }
202
203 #ifndef OPENSSL_NO_CRYPTO_MDEBUG
204     if (CRYPTO_mem_leaks_fp(stderr) <= 0)
205         return 1;
206 #endif
207
208     printf("PASS\n");
209     return 0;
210 }