1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include <stdio.h> 11e1051a39Sopenharmony_ci#include <string.h> 12e1051a39Sopenharmony_ci#include <openssl/crypto.h> 13e1051a39Sopenharmony_ci#include <openssl/bio.h> 14e1051a39Sopenharmony_ci#include <openssl/x509.h> 15e1051a39Sopenharmony_ci#include <openssl/x509v3.h> 16e1051a39Sopenharmony_ci#include <openssl/pem.h> 17e1051a39Sopenharmony_ci#include <openssl/err.h> 18e1051a39Sopenharmony_ci#include "testutil.h" 19e1051a39Sopenharmony_ci 20e1051a39Sopenharmony_cistatic const char *certs_dir; 21e1051a39Sopenharmony_cistatic char *root_f = NULL; 22e1051a39Sopenharmony_cistatic char *roots_f = NULL; 23e1051a39Sopenharmony_cistatic char *untrusted_f = NULL; 24e1051a39Sopenharmony_cistatic char *bad_f = NULL; 25e1051a39Sopenharmony_cistatic char *req_f = NULL; 26e1051a39Sopenharmony_cistatic char *sroot_cert = NULL; 27e1051a39Sopenharmony_cistatic char *ca_cert = NULL; 28e1051a39Sopenharmony_cistatic char *ee_cert = NULL; 29e1051a39Sopenharmony_ci 30e1051a39Sopenharmony_ci#define load_cert_from_file(file) load_cert_pem(file, NULL) 31e1051a39Sopenharmony_ci 32e1051a39Sopenharmony_ci/*- 33e1051a39Sopenharmony_ci * Test for CVE-2015-1793 (Alternate Chains Certificate Forgery) 34e1051a39Sopenharmony_ci * 35e1051a39Sopenharmony_ci * Chain is as follows: 36e1051a39Sopenharmony_ci * 37e1051a39Sopenharmony_ci * rootCA (self-signed) 38e1051a39Sopenharmony_ci * | 39e1051a39Sopenharmony_ci * interCA 40e1051a39Sopenharmony_ci * | 41e1051a39Sopenharmony_ci * subinterCA subinterCA (self-signed) 42e1051a39Sopenharmony_ci * | | 43e1051a39Sopenharmony_ci * leaf ------------------ 44e1051a39Sopenharmony_ci * | 45e1051a39Sopenharmony_ci * bad 46e1051a39Sopenharmony_ci * 47e1051a39Sopenharmony_ci * rootCA, interCA, subinterCA, subinterCA (ss) all have CA=TRUE 48e1051a39Sopenharmony_ci * leaf and bad have CA=FALSE 49e1051a39Sopenharmony_ci * 50e1051a39Sopenharmony_ci * subinterCA and subinterCA (ss) have the same subject name and keys 51e1051a39Sopenharmony_ci * 52e1051a39Sopenharmony_ci * interCA (but not rootCA) and subinterCA (ss) are in the trusted store 53e1051a39Sopenharmony_ci * (roots.pem) 54e1051a39Sopenharmony_ci * leaf and subinterCA are in the untrusted list (untrusted.pem) 55e1051a39Sopenharmony_ci * bad is the certificate being verified (bad.pem) 56e1051a39Sopenharmony_ci * 57e1051a39Sopenharmony_ci * Versions vulnerable to CVE-2015-1793 will fail to detect that leaf has 58e1051a39Sopenharmony_ci * CA=FALSE, and will therefore incorrectly verify bad 59e1051a39Sopenharmony_ci * 60e1051a39Sopenharmony_ci */ 61e1051a39Sopenharmony_cistatic int test_alt_chains_cert_forgery(void) 62e1051a39Sopenharmony_ci{ 63e1051a39Sopenharmony_ci int ret = 0; 64e1051a39Sopenharmony_ci int i; 65e1051a39Sopenharmony_ci X509 *x = NULL; 66e1051a39Sopenharmony_ci STACK_OF(X509) *untrusted = NULL; 67e1051a39Sopenharmony_ci X509_STORE_CTX *sctx = NULL; 68e1051a39Sopenharmony_ci X509_STORE *store = NULL; 69e1051a39Sopenharmony_ci X509_LOOKUP *lookup = NULL; 70e1051a39Sopenharmony_ci 71e1051a39Sopenharmony_ci store = X509_STORE_new(); 72e1051a39Sopenharmony_ci if (store == NULL) 73e1051a39Sopenharmony_ci goto err; 74e1051a39Sopenharmony_ci 75e1051a39Sopenharmony_ci lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); 76e1051a39Sopenharmony_ci if (lookup == NULL) 77e1051a39Sopenharmony_ci goto err; 78e1051a39Sopenharmony_ci if (!X509_LOOKUP_load_file(lookup, roots_f, X509_FILETYPE_PEM)) 79e1051a39Sopenharmony_ci goto err; 80e1051a39Sopenharmony_ci 81e1051a39Sopenharmony_ci untrusted = load_certs_pem(untrusted_f); 82e1051a39Sopenharmony_ci 83e1051a39Sopenharmony_ci if ((x = load_cert_from_file(bad_f)) == NULL) 84e1051a39Sopenharmony_ci goto err; 85e1051a39Sopenharmony_ci 86e1051a39Sopenharmony_ci sctx = X509_STORE_CTX_new(); 87e1051a39Sopenharmony_ci if (sctx == NULL) 88e1051a39Sopenharmony_ci goto err; 89e1051a39Sopenharmony_ci 90e1051a39Sopenharmony_ci if (!X509_STORE_CTX_init(sctx, store, x, untrusted)) 91e1051a39Sopenharmony_ci goto err; 92e1051a39Sopenharmony_ci 93e1051a39Sopenharmony_ci i = X509_verify_cert(sctx); 94e1051a39Sopenharmony_ci 95e1051a39Sopenharmony_ci if (i == 0 && X509_STORE_CTX_get_error(sctx) == X509_V_ERR_INVALID_CA) { 96e1051a39Sopenharmony_ci /* This is the result we were expecting: Test passed */ 97e1051a39Sopenharmony_ci ret = 1; 98e1051a39Sopenharmony_ci } 99e1051a39Sopenharmony_ci err: 100e1051a39Sopenharmony_ci X509_STORE_CTX_free(sctx); 101e1051a39Sopenharmony_ci X509_free(x); 102e1051a39Sopenharmony_ci sk_X509_pop_free(untrusted, X509_free); 103e1051a39Sopenharmony_ci X509_STORE_free(store); 104e1051a39Sopenharmony_ci return ret; 105e1051a39Sopenharmony_ci} 106e1051a39Sopenharmony_ci 107e1051a39Sopenharmony_cistatic int test_distinguishing_id(void) 108e1051a39Sopenharmony_ci{ 109e1051a39Sopenharmony_ci X509 *x = NULL; 110e1051a39Sopenharmony_ci int ret = 0; 111e1051a39Sopenharmony_ci ASN1_OCTET_STRING *v = NULL, *v2 = NULL; 112e1051a39Sopenharmony_ci char *distid = "this is an ID"; 113e1051a39Sopenharmony_ci 114e1051a39Sopenharmony_ci x = load_cert_from_file(bad_f); 115e1051a39Sopenharmony_ci if (x == NULL) 116e1051a39Sopenharmony_ci goto err; 117e1051a39Sopenharmony_ci 118e1051a39Sopenharmony_ci v = ASN1_OCTET_STRING_new(); 119e1051a39Sopenharmony_ci if (v == NULL) 120e1051a39Sopenharmony_ci goto err; 121e1051a39Sopenharmony_ci 122e1051a39Sopenharmony_ci if (!ASN1_OCTET_STRING_set(v, (unsigned char *)distid, 123e1051a39Sopenharmony_ci (int)strlen(distid))) { 124e1051a39Sopenharmony_ci ASN1_OCTET_STRING_free(v); 125e1051a39Sopenharmony_ci goto err; 126e1051a39Sopenharmony_ci } 127e1051a39Sopenharmony_ci 128e1051a39Sopenharmony_ci X509_set0_distinguishing_id(x, v); 129e1051a39Sopenharmony_ci 130e1051a39Sopenharmony_ci v2 = X509_get0_distinguishing_id(x); 131e1051a39Sopenharmony_ci if (!TEST_ptr(v2) 132e1051a39Sopenharmony_ci || !TEST_int_eq(ASN1_OCTET_STRING_cmp(v, v2), 0)) 133e1051a39Sopenharmony_ci goto err; 134e1051a39Sopenharmony_ci 135e1051a39Sopenharmony_ci ret = 1; 136e1051a39Sopenharmony_ci err: 137e1051a39Sopenharmony_ci X509_free(x); 138e1051a39Sopenharmony_ci return ret; 139e1051a39Sopenharmony_ci} 140e1051a39Sopenharmony_ci 141e1051a39Sopenharmony_cistatic int test_req_distinguishing_id(void) 142e1051a39Sopenharmony_ci{ 143e1051a39Sopenharmony_ci X509_REQ *x = NULL; 144e1051a39Sopenharmony_ci BIO *bio = NULL; 145e1051a39Sopenharmony_ci int ret = 0; 146e1051a39Sopenharmony_ci ASN1_OCTET_STRING *v = NULL, *v2 = NULL; 147e1051a39Sopenharmony_ci char *distid = "this is an ID"; 148e1051a39Sopenharmony_ci 149e1051a39Sopenharmony_ci bio = BIO_new_file(req_f, "r"); 150e1051a39Sopenharmony_ci if (bio == NULL) 151e1051a39Sopenharmony_ci goto err; 152e1051a39Sopenharmony_ci 153e1051a39Sopenharmony_ci x = PEM_read_bio_X509_REQ(bio, NULL, 0, NULL); 154e1051a39Sopenharmony_ci if (x == NULL) 155e1051a39Sopenharmony_ci goto err; 156e1051a39Sopenharmony_ci 157e1051a39Sopenharmony_ci v = ASN1_OCTET_STRING_new(); 158e1051a39Sopenharmony_ci if (v == NULL) 159e1051a39Sopenharmony_ci goto err; 160e1051a39Sopenharmony_ci 161e1051a39Sopenharmony_ci if (!ASN1_OCTET_STRING_set(v, (unsigned char *)distid, 162e1051a39Sopenharmony_ci (int)strlen(distid))) { 163e1051a39Sopenharmony_ci ASN1_OCTET_STRING_free(v); 164e1051a39Sopenharmony_ci goto err; 165e1051a39Sopenharmony_ci } 166e1051a39Sopenharmony_ci 167e1051a39Sopenharmony_ci X509_REQ_set0_distinguishing_id(x, v); 168e1051a39Sopenharmony_ci 169e1051a39Sopenharmony_ci v2 = X509_REQ_get0_distinguishing_id(x); 170e1051a39Sopenharmony_ci if (!TEST_ptr(v2) 171e1051a39Sopenharmony_ci || !TEST_int_eq(ASN1_OCTET_STRING_cmp(v, v2), 0)) 172e1051a39Sopenharmony_ci goto err; 173e1051a39Sopenharmony_ci 174e1051a39Sopenharmony_ci ret = 1; 175e1051a39Sopenharmony_ci err: 176e1051a39Sopenharmony_ci X509_REQ_free(x); 177e1051a39Sopenharmony_ci BIO_free(bio); 178e1051a39Sopenharmony_ci return ret; 179e1051a39Sopenharmony_ci} 180e1051a39Sopenharmony_ci 181e1051a39Sopenharmony_cistatic int test_self_signed(const char *filename, int use_trusted, int expected) 182e1051a39Sopenharmony_ci{ 183e1051a39Sopenharmony_ci X509 *cert = load_cert_from_file(filename); /* may result in NULL */ 184e1051a39Sopenharmony_ci STACK_OF(X509) *trusted = sk_X509_new_null(); 185e1051a39Sopenharmony_ci X509_STORE_CTX *ctx = X509_STORE_CTX_new(); 186e1051a39Sopenharmony_ci int ret; 187e1051a39Sopenharmony_ci 188e1051a39Sopenharmony_ci ret = TEST_int_eq(X509_self_signed(cert, 1), expected); 189e1051a39Sopenharmony_ci 190e1051a39Sopenharmony_ci if (cert != NULL) { 191e1051a39Sopenharmony_ci if (use_trusted) 192e1051a39Sopenharmony_ci ret = ret && TEST_true(sk_X509_push(trusted, cert)); 193e1051a39Sopenharmony_ci ret = ret && TEST_true(X509_STORE_CTX_init(ctx, NULL, cert, NULL)); 194e1051a39Sopenharmony_ci X509_STORE_CTX_set0_trusted_stack(ctx, trusted); 195e1051a39Sopenharmony_ci ret = ret && TEST_int_eq(X509_verify_cert(ctx), expected); 196e1051a39Sopenharmony_ci } 197e1051a39Sopenharmony_ci 198e1051a39Sopenharmony_ci X509_STORE_CTX_free(ctx); 199e1051a39Sopenharmony_ci sk_X509_free(trusted); 200e1051a39Sopenharmony_ci X509_free(cert); 201e1051a39Sopenharmony_ci return ret; 202e1051a39Sopenharmony_ci} 203e1051a39Sopenharmony_ci 204e1051a39Sopenharmony_cistatic int test_self_signed_good(void) 205e1051a39Sopenharmony_ci{ 206e1051a39Sopenharmony_ci return test_self_signed(root_f, 1, 1); 207e1051a39Sopenharmony_ci} 208e1051a39Sopenharmony_ci 209e1051a39Sopenharmony_cistatic int test_self_signed_bad(void) 210e1051a39Sopenharmony_ci{ 211e1051a39Sopenharmony_ci return test_self_signed(bad_f, 1, 0); 212e1051a39Sopenharmony_ci} 213e1051a39Sopenharmony_ci 214e1051a39Sopenharmony_cistatic int test_self_signed_error(void) 215e1051a39Sopenharmony_ci{ 216e1051a39Sopenharmony_ci return test_self_signed("nonexistent file name", 1, -1); 217e1051a39Sopenharmony_ci} 218e1051a39Sopenharmony_ci 219e1051a39Sopenharmony_cistatic int test_store_ctx(void) 220e1051a39Sopenharmony_ci{ 221e1051a39Sopenharmony_ci /* Verifying a cert where we have no trusted certs should fail */ 222e1051a39Sopenharmony_ci return test_self_signed(bad_f, 0, 0); 223e1051a39Sopenharmony_ci} 224e1051a39Sopenharmony_ci 225e1051a39Sopenharmony_cistatic int do_test_purpose(int purpose, int expected) 226e1051a39Sopenharmony_ci{ 227e1051a39Sopenharmony_ci X509 *eecert = load_cert_from_file(ee_cert); /* may result in NULL */ 228e1051a39Sopenharmony_ci X509 *untrcert = load_cert_from_file(ca_cert); 229e1051a39Sopenharmony_ci X509 *trcert = load_cert_from_file(sroot_cert); 230e1051a39Sopenharmony_ci STACK_OF(X509) *trusted = sk_X509_new_null(); 231e1051a39Sopenharmony_ci STACK_OF(X509) *untrusted = sk_X509_new_null(); 232e1051a39Sopenharmony_ci X509_STORE_CTX *ctx = X509_STORE_CTX_new(); 233e1051a39Sopenharmony_ci int testresult = 0; 234e1051a39Sopenharmony_ci 235e1051a39Sopenharmony_ci if (!TEST_ptr(eecert) 236e1051a39Sopenharmony_ci || !TEST_ptr(untrcert) 237e1051a39Sopenharmony_ci || !TEST_ptr(trcert) 238e1051a39Sopenharmony_ci || !TEST_ptr(trusted) 239e1051a39Sopenharmony_ci || !TEST_ptr(untrusted) 240e1051a39Sopenharmony_ci || !TEST_ptr(ctx)) 241e1051a39Sopenharmony_ci goto err; 242e1051a39Sopenharmony_ci 243e1051a39Sopenharmony_ci 244e1051a39Sopenharmony_ci if (!TEST_true(sk_X509_push(trusted, trcert))) 245e1051a39Sopenharmony_ci goto err; 246e1051a39Sopenharmony_ci trcert = NULL; 247e1051a39Sopenharmony_ci if (!TEST_true(sk_X509_push(untrusted, untrcert))) 248e1051a39Sopenharmony_ci goto err; 249e1051a39Sopenharmony_ci untrcert = NULL; 250e1051a39Sopenharmony_ci 251e1051a39Sopenharmony_ci if (!TEST_true(X509_STORE_CTX_init(ctx, NULL, eecert, untrusted))) 252e1051a39Sopenharmony_ci goto err; 253e1051a39Sopenharmony_ci 254e1051a39Sopenharmony_ci if (!TEST_true(X509_STORE_CTX_set_purpose(ctx, purpose))) 255e1051a39Sopenharmony_ci goto err; 256e1051a39Sopenharmony_ci 257e1051a39Sopenharmony_ci /* 258e1051a39Sopenharmony_ci * X509_STORE_CTX_set0_trusted_stack() is bady named. Despite the set0 name 259e1051a39Sopenharmony_ci * we are still responsible for freeing trusted after we have finished with 260e1051a39Sopenharmony_ci * it. 261e1051a39Sopenharmony_ci */ 262e1051a39Sopenharmony_ci X509_STORE_CTX_set0_trusted_stack(ctx, trusted); 263e1051a39Sopenharmony_ci 264e1051a39Sopenharmony_ci if (!TEST_int_eq(X509_verify_cert(ctx), expected)) 265e1051a39Sopenharmony_ci goto err; 266e1051a39Sopenharmony_ci 267e1051a39Sopenharmony_ci testresult = 1; 268e1051a39Sopenharmony_ci err: 269e1051a39Sopenharmony_ci sk_X509_pop_free(trusted, X509_free); 270e1051a39Sopenharmony_ci sk_X509_pop_free(untrusted, X509_free); 271e1051a39Sopenharmony_ci X509_STORE_CTX_free(ctx); 272e1051a39Sopenharmony_ci X509_free(eecert); 273e1051a39Sopenharmony_ci X509_free(untrcert); 274e1051a39Sopenharmony_ci X509_free(trcert); 275e1051a39Sopenharmony_ci return testresult; 276e1051a39Sopenharmony_ci} 277e1051a39Sopenharmony_ci 278e1051a39Sopenharmony_cistatic int test_purpose_ssl_client(void) 279e1051a39Sopenharmony_ci{ 280e1051a39Sopenharmony_ci return do_test_purpose(X509_PURPOSE_SSL_CLIENT, 0); 281e1051a39Sopenharmony_ci} 282e1051a39Sopenharmony_ci 283e1051a39Sopenharmony_cistatic int test_purpose_ssl_server(void) 284e1051a39Sopenharmony_ci{ 285e1051a39Sopenharmony_ci return do_test_purpose(X509_PURPOSE_SSL_SERVER, 1); 286e1051a39Sopenharmony_ci} 287e1051a39Sopenharmony_ci 288e1051a39Sopenharmony_cistatic int test_purpose_any(void) 289e1051a39Sopenharmony_ci{ 290e1051a39Sopenharmony_ci return do_test_purpose(X509_PURPOSE_ANY, 1); 291e1051a39Sopenharmony_ci} 292e1051a39Sopenharmony_ci 293e1051a39Sopenharmony_ciOPT_TEST_DECLARE_USAGE("certs-dir\n") 294e1051a39Sopenharmony_ci 295e1051a39Sopenharmony_ciint setup_tests(void) 296e1051a39Sopenharmony_ci{ 297e1051a39Sopenharmony_ci if (!test_skip_common_options()) { 298e1051a39Sopenharmony_ci TEST_error("Error parsing test options\n"); 299e1051a39Sopenharmony_ci return 0; 300e1051a39Sopenharmony_ci } 301e1051a39Sopenharmony_ci 302e1051a39Sopenharmony_ci if (!TEST_ptr(certs_dir = test_get_argument(0))) 303e1051a39Sopenharmony_ci return 0; 304e1051a39Sopenharmony_ci 305e1051a39Sopenharmony_ci if (!TEST_ptr(root_f = test_mk_file_path(certs_dir, "rootCA.pem")) 306e1051a39Sopenharmony_ci || !TEST_ptr(roots_f = test_mk_file_path(certs_dir, "roots.pem")) 307e1051a39Sopenharmony_ci || !TEST_ptr(untrusted_f = test_mk_file_path(certs_dir, "untrusted.pem")) 308e1051a39Sopenharmony_ci || !TEST_ptr(bad_f = test_mk_file_path(certs_dir, "bad.pem")) 309e1051a39Sopenharmony_ci || !TEST_ptr(req_f = test_mk_file_path(certs_dir, "sm2-csr.pem")) 310e1051a39Sopenharmony_ci || !TEST_ptr(sroot_cert = test_mk_file_path(certs_dir, "sroot-cert.pem")) 311e1051a39Sopenharmony_ci || !TEST_ptr(ca_cert = test_mk_file_path(certs_dir, "ca-cert.pem")) 312e1051a39Sopenharmony_ci || !TEST_ptr(ee_cert = test_mk_file_path(certs_dir, "ee-cert.pem"))) 313e1051a39Sopenharmony_ci goto err; 314e1051a39Sopenharmony_ci 315e1051a39Sopenharmony_ci ADD_TEST(test_alt_chains_cert_forgery); 316e1051a39Sopenharmony_ci ADD_TEST(test_store_ctx); 317e1051a39Sopenharmony_ci ADD_TEST(test_distinguishing_id); 318e1051a39Sopenharmony_ci ADD_TEST(test_req_distinguishing_id); 319e1051a39Sopenharmony_ci ADD_TEST(test_self_signed_good); 320e1051a39Sopenharmony_ci ADD_TEST(test_self_signed_bad); 321e1051a39Sopenharmony_ci ADD_TEST(test_self_signed_error); 322e1051a39Sopenharmony_ci ADD_TEST(test_purpose_ssl_client); 323e1051a39Sopenharmony_ci ADD_TEST(test_purpose_ssl_server); 324e1051a39Sopenharmony_ci ADD_TEST(test_purpose_any); 325e1051a39Sopenharmony_ci return 1; 326e1051a39Sopenharmony_ci err: 327e1051a39Sopenharmony_ci cleanup_tests(); 328e1051a39Sopenharmony_ci return 0; 329e1051a39Sopenharmony_ci} 330e1051a39Sopenharmony_ci 331e1051a39Sopenharmony_civoid cleanup_tests(void) 332e1051a39Sopenharmony_ci{ 333e1051a39Sopenharmony_ci OPENSSL_free(root_f); 334e1051a39Sopenharmony_ci OPENSSL_free(roots_f); 335e1051a39Sopenharmony_ci OPENSSL_free(untrusted_f); 336e1051a39Sopenharmony_ci OPENSSL_free(bad_f); 337e1051a39Sopenharmony_ci OPENSSL_free(req_f); 338e1051a39Sopenharmony_ci OPENSSL_free(sroot_cert); 339e1051a39Sopenharmony_ci OPENSSL_free(ca_cert); 340e1051a39Sopenharmony_ci OPENSSL_free(ee_cert); 341e1051a39Sopenharmony_ci} 342