Files
wolfssl/tests/api/test_ossl_x509_str.c
T

2767 lines
102 KiB
C

/* test_ossl_x509_str.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <tests/unit.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#include <wolfssl/ssl.h>
#ifdef OPENSSL_EXTRA
#include <wolfssl/openssl/x509_vfy.h>
#include <wolfssl/openssl/pem.h>
#endif
#include <tests/api/api.h>
#include <tests/api/test_ossl_x509_str.h>
#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \
!defined(NO_ASN_TIME)
static int last_errcodes[10];
static int last_errdepths[10];
static int err_index = 0;
static int X509CallbackCount(int ok, X509_STORE_CTX *ctx)
{
if (!ok) {
if (err_index < 10) {
last_errcodes[err_index] = X509_STORE_CTX_get_error(ctx);
last_errdepths[err_index] = X509_STORE_CTX_get_error_depth(ctx);
err_index++;
} else {
/* Should not happen in test */
WOLFSSL_MSG("Error index overflow in X509CallbackCount");
err_index = 0;
}
}
/* Always return OK to allow verification to continue.*/
return 1;
}
#endif
int test_wolfSSL_X509_STORE_CTX_set_time(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
WOLFSSL_X509_STORE_CTX* ctx = NULL;
time_t c_time;
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
c_time = 365*24*60*60;
wolfSSL_X509_STORE_CTX_set_time(ctx, 0, c_time);
ExpectTrue((ctx->param->flags & WOLFSSL_USE_CHECK_TIME) ==
WOLFSSL_USE_CHECK_TIME);
ExpectTrue(ctx->param->check_time == c_time);
wolfSSL_X509_STORE_CTX_free(ctx);
#endif /* OPENSSL_EXTRA */
return EXPECT_RESULT();
}
int test_wolfSSL_X509_STORE_check_time(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && \
!defined(NO_ASN_TIME) && !defined(NO_RSA)
WOLFSSL_X509_STORE* store = NULL;
WOLFSSL_X509_STORE_CTX* ctx = NULL;
WOLFSSL_X509* ca = NULL;
WOLFSSL_X509* cert = NULL;
int ret;
time_t check_time;
const char* srvCertFile = "./certs/server-cert.pem";
const char* expiredCertFile = "./certs/test/expired/expired-cert.pem";
/* Set check_time to May 26, 2000 - should fail "not yet valid" check */
ExpectNotNull(store = wolfSSL_X509_STORE_new());
if (store != NULL) {
/* Load CA certificate - should validate with current time by default */
ExpectNotNull(ca = wolfSSL_X509_load_certificate_file(caCertFile,
SSL_FILETYPE_PEM));
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, ca), WOLFSSL_SUCCESS);
/* Set check_time to May 26, 2000 (timestamp: 959320800) */
check_time = (time_t)959320800; /* May 26, 2000 00:00:00 UTC */
store->param->check_time = check_time;
wolfSSL_X509_VERIFY_PARAM_set_flags(store->param,
WOLFSSL_USE_CHECK_TIME);
ExpectTrue(store->param->check_time == check_time);
ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(srvCertFile,
SSL_FILETYPE_PEM));
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, cert, NULL),
WOLFSSL_SUCCESS);
/* Verify that check_time was copied to context */
ExpectTrue((ctx->param->flags & WOLFSSL_USE_CHECK_TIME) ==
WOLFSSL_USE_CHECK_TIME);
ExpectTrue(ctx->param->check_time == check_time);
/* Verify certificate using the custom check_time - should fail because
* certificate is not yet valid (use before check fails) */
ret = wolfSSL_X509_verify_cert(ctx);
ExpectIntNE(ret, WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_X509_STORE_CTX_get_error(ctx),
WOLFSSL_X509_V_ERR_CERT_NOT_YET_VALID);
wolfSSL_X509_STORE_CTX_free(ctx);
ctx = NULL;
}
wolfSSL_X509_STORE_free(store);
store = NULL;
wolfSSL_X509_free(cert);
cert = NULL;
wolfSSL_X509_free(ca);
ca = NULL;
/* Verify without setting check_time - should work with current time */
ExpectNotNull(store = wolfSSL_X509_STORE_new());
if (store != NULL) {
ExpectNotNull(ca = wolfSSL_X509_load_certificate_file(caCertFile,
SSL_FILETYPE_PEM));
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, ca), WOLFSSL_SUCCESS);
ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(srvCertFile,
SSL_FILETYPE_PEM));
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, cert, NULL),
WOLFSSL_SUCCESS);
ret = wolfSSL_X509_verify_cert(ctx);
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
wolfSSL_X509_STORE_CTX_free(ctx);
ctx = NULL;
}
wolfSSL_X509_STORE_free(store);
store = NULL;
wolfSSL_X509_free(cert);
cert = NULL;
wolfSSL_X509_free(ca);
ca = NULL;
/* Test WOLFSSL_NO_CHECK_TIME flag with expired certificate */
ExpectNotNull(store = wolfSSL_X509_STORE_new());
if (store != NULL) {
/* Set NO_CHECK_TIME flag to skip time validation */
wolfSSL_X509_VERIFY_PARAM_set_flags(store->param,
WOLFSSL_NO_CHECK_TIME);
ExpectTrue((store->param->flags & WOLFSSL_NO_CHECK_TIME) ==
WOLFSSL_NO_CHECK_TIME);
/* Load expired certificate (self-signed) */
ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(expiredCertFile,
SSL_FILETYPE_PEM));
/* Add expired certificate as trusted CA (self-signed) */
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, cert), WOLFSSL_SUCCESS);
ExpectNotNull(ctx = wolfSSL_X509_STORE_CTX_new());
ExpectIntEQ(wolfSSL_X509_STORE_CTX_init(ctx, store, cert, NULL),
WOLFSSL_SUCCESS);
/* Verify expired certificate with NO_CHECK_TIME - should succeed
* because time validation is skipped */
ret = wolfSSL_X509_verify_cert(ctx);
ExpectIntEQ(ret, WOLFSSL_SUCCESS);
}
wolfSSL_X509_STORE_CTX_free(ctx);
ctx = NULL;
wolfSSL_X509_STORE_free(store);
store = NULL;
wolfSSL_X509_free(cert);
cert = NULL;
#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM)
err_index = 0;
ExpectNotNull(store = X509_STORE_new());
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectNotNull(ca = wolfSSL_X509_load_certificate_file(caCertFile,
SSL_FILETYPE_PEM));
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, ca), WOLFSSL_SUCCESS);
X509_STORE_set_verify_cb(store, X509CallbackCount);
ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(expiredCertFile,
SSL_FILETYPE_PEM));
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, cert, NULL), WOLFSSL_SUCCESS);
ExpectIntEQ(X509_verify_cert(ctx), WOLFSSL_SUCCESS);
/* while verifying the certificate, it should have two errors */
ExpectIntEQ(err_index, 2);
/* self-signed */
ExpectIntEQ(last_errcodes[err_index - 2],
WOLFSSL_X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
/* expired */
ExpectIntEQ(last_errcodes[err_index - 1],
WOLFSSL_X509_V_ERR_CERT_HAS_EXPIRED);
X509_STORE_CTX_free(ctx);
ctx = NULL;
X509_STORE_free(store);
store = NULL;
X509_free(cert);
cert = NULL;
X509_free(ca);
ca = NULL;
err_index = 0;
ExpectNotNull(store = X509_STORE_new());
/* Set NO_CHECK_TIME flag to skip time validation */
ExpectIntEQ(X509_VERIFY_PARAM_set_flags(store->param,
WOLFSSL_NO_CHECK_TIME), WOLFSSL_SUCCESS);
ExpectTrue((store->param->flags & WOLFSSL_NO_CHECK_TIME) ==
WOLFSSL_NO_CHECK_TIME);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectNotNull(ca = wolfSSL_X509_load_certificate_file(caCertFile,
SSL_FILETYPE_PEM));
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, ca), WOLFSSL_SUCCESS);
X509_STORE_set_verify_cb(store, X509CallbackCount);
ExpectNotNull(cert = wolfSSL_X509_load_certificate_file(expiredCertFile,
SSL_FILETYPE_PEM));
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, cert, NULL), WOLFSSL_SUCCESS);
ExpectIntEQ(X509_verify_cert(ctx), WOLFSSL_SUCCESS);
/* while verifying the certificate, it should have an error */
ExpectIntEQ(err_index, 1);
/* self-signed */
ExpectIntEQ(last_errcodes[err_index - 1],
WOLFSSL_X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
/* no expired because of no_check_time */
X509_STORE_CTX_free(ctx);
ctx = NULL;
X509_STORE_free(store);
store = NULL;
X509_free(cert);
cert = NULL;
X509_free(ca);
ca = NULL;
#endif
#endif /* OPENSSL_EXTRA && !NO_FILESYSTEM && !NO_ASN_TIME && !NO_RSA */
return EXPECT_RESULT();
}
int test_wolfSSL_X509_STORE_CTX_get0_store(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA)
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
X509_STORE_CTX* ctx_no_init = NULL;
ExpectNotNull((store = X509_STORE_new()));
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectNotNull(ctx_no_init = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, NULL, NULL), SSL_SUCCESS);
ExpectNull(X509_STORE_CTX_get0_store(NULL));
/* should return NULL if ctx has not bee initialized */
ExpectNull(X509_STORE_CTX_get0_store(ctx_no_init));
ExpectNotNull(X509_STORE_CTX_get0_store(ctx));
wolfSSL_X509_STORE_CTX_free(ctx);
wolfSSL_X509_STORE_CTX_free(ctx_no_init);
X509_STORE_free(store);
#endif /* OPENSSL_EXTRA */
return EXPECT_RESULT();
}
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
!defined(NO_FILESYSTEM) && !defined(NO_RSA)
static int verify_cb(int ok, X509_STORE_CTX *ctx)
{
(void) ok;
(void) ctx;
fprintf(stderr, "ENTER verify_cb\n");
return SSL_SUCCESS;
}
#endif
int test_wolfSSL_X509_STORE_CTX(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
!defined(NO_FILESYSTEM) && !defined(NO_RSA)
X509_STORE_CTX* ctx = NULL;
X509_STORE* str = NULL;
X509* x509 = NULL;
#ifdef OPENSSL_ALL
X509* x5092 = NULL;
STACK_OF(X509) *sk = NULL;
STACK_OF(X509) *sk2 = NULL;
STACK_OF(X509) *sk3 = NULL;
#endif
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectNotNull((str = wolfSSL_X509_STORE_new()));
ExpectNotNull((x509 =
wolfSSL_X509_load_certificate_file(svrCertFile, SSL_FILETYPE_PEM)));
ExpectIntEQ(X509_STORE_add_cert(str, x509), SSL_SUCCESS);
#ifdef OPENSSL_ALL
/* sk_X509_new only in OPENSSL_ALL */
sk = sk_X509_new_null();
ExpectNotNull(sk);
ExpectIntEQ(X509_STORE_CTX_init(ctx, str, x509, sk), SSL_SUCCESS);
#else
ExpectIntEQ(X509_STORE_CTX_init(ctx, str, x509, NULL), SSL_SUCCESS);
#endif
ExpectIntEQ(SSL_get_ex_data_X509_STORE_CTX_idx(), 0);
X509_STORE_CTX_set_error(ctx, -5);
X509_STORE_CTX_set_error(NULL, -5);
X509_STORE_CTX_free(ctx);
ctx = NULL;
#ifdef OPENSSL_ALL
sk_X509_pop_free(sk, NULL);
sk = NULL;
#endif
X509_STORE_free(str);
str = NULL;
X509_free(x509);
x509 = NULL;
ExpectNotNull(ctx = X509_STORE_CTX_new());
X509_STORE_CTX_set_verify_cb(ctx, verify_cb);
X509_STORE_CTX_free(ctx);
ctx = NULL;
#ifdef OPENSSL_ALL
/* test X509_STORE_CTX_get(1)_chain */
ExpectNotNull((x509 = X509_load_certificate_file(svrCertFile,
SSL_FILETYPE_PEM)));
ExpectNotNull((x5092 = X509_load_certificate_file(cliCertFile,
SSL_FILETYPE_PEM)));
ExpectNotNull((sk = sk_X509_new_null()));
ExpectIntEQ(sk_X509_push(sk, x509), 1);
if (EXPECT_FAIL()) {
X509_free(x509);
x509 = NULL;
}
ExpectNotNull((str = X509_STORE_new()));
ExpectNotNull((ctx = X509_STORE_CTX_new()));
ExpectIntEQ(X509_STORE_CTX_init(ctx, str, x5092, sk), 1);
ExpectNull((sk2 = X509_STORE_CTX_get_chain(NULL)));
ExpectNull((sk2 = X509_STORE_CTX_get_chain(ctx)));
ExpectNull((sk3 = X509_STORE_CTX_get1_chain(NULL)));
ExpectNull((sk3 = X509_STORE_CTX_get1_chain(ctx)));
X509_STORE_CTX_free(ctx);
ctx = NULL;
X509_STORE_free(str);
str = NULL;
/* CTX certs not freed yet */
X509_free(x5092);
x5092 = NULL;
sk_X509_pop_free(sk, NULL);
sk = NULL;
/* sk3 is dup so free here */
sk_X509_pop_free(sk3, NULL);
sk3 = NULL;
#endif
/* test X509_STORE_CTX_get/set_ex_data */
{
int i = 0, tmpData = 5;
void* tmpDataRet;
ExpectNotNull(ctx = X509_STORE_CTX_new());
#ifdef HAVE_EX_DATA
for (i = 0; i < MAX_EX_DATA; i++) {
ExpectIntEQ(X509_STORE_CTX_set_ex_data(ctx, i, &tmpData),
WOLFSSL_SUCCESS);
tmpDataRet = (int*)X509_STORE_CTX_get_ex_data(ctx, i);
ExpectNotNull(tmpDataRet);
ExpectIntEQ(tmpData, *(int*)tmpDataRet);
}
#else
ExpectIntEQ(X509_STORE_CTX_set_ex_data(ctx, i, &tmpData),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
tmpDataRet = (int*)X509_STORE_CTX_get_ex_data(ctx, i);
ExpectNull(tmpDataRet);
#endif
X509_STORE_CTX_free(ctx);
ctx = NULL;
}
/* test X509_STORE_get/set_ex_data */
{
int i = 0, tmpData = 99;
void* tmpDataRet;
ExpectNotNull(str = X509_STORE_new());
#ifdef HAVE_EX_DATA
for (i = 0; i < MAX_EX_DATA; i++) {
ExpectIntEQ(X509_STORE_set_ex_data(str, i, &tmpData),
WOLFSSL_SUCCESS);
tmpDataRet = (int*)X509_STORE_get_ex_data(str, i);
ExpectNotNull(tmpDataRet);
ExpectIntEQ(tmpData, *(int*)tmpDataRet);
}
#else
ExpectIntEQ(X509_STORE_set_ex_data(str, i, &tmpData),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
tmpDataRet = (int*)X509_STORE_get_ex_data(str, i);
ExpectNull(tmpDataRet);
#endif
X509_STORE_free(str);
str = NULL;
}
#endif /* defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
* !defined(NO_FILESYSTEM) && !defined(NO_RSA) */
return EXPECT_RESULT();
}
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
!defined(NO_FILESYSTEM) && !defined(NO_RSA)
typedef struct {
const char *caFile;
const char *caIntFile;
const char *caInt2File;
const char *leafFile;
X509 *x509Ca;
X509 *x509CaInt;
X509 *x509CaInt2;
X509 *x509Leaf;
STACK_OF(X509)* expectedChain;
} X509_STORE_test_data;
static X509 * test_wolfSSL_X509_STORE_CTX_ex_helper(const char *file)
{
XFILE fp = XBADFILE;
X509 *x = NULL;
fp = XFOPEN(file, "rb");
if (fp == NULL) {
return NULL;
}
x = PEM_read_X509(fp, 0, 0, 0);
XFCLOSE(fp);
return x;
}
static int test_wolfSSL_X509_STORE_CTX_ex1(X509_STORE_test_data *testData)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* chain = NULL;
int i = 0;
/* Test case 1, add X509 certs to store and verify */
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509Ca), 1);
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt), 1);
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1);
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx));
ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain));
for (i = 0; i < sk_X509_num(chain); i++) {
ExpectIntEQ(X509_cmp(sk_X509_value(chain, i),
sk_X509_value(testData->expectedChain, i)), 0);
}
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
return EXPECT_RESULT();
}
static int test_wolfSSL_X509_STORE_CTX_ex2(X509_STORE_test_data *testData)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* chain = NULL;
int i = 0;
/* Test case 2, add certs by filename to store and verify */
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_load_locations(
store, testData->caFile, NULL), 1);
ExpectIntEQ(X509_STORE_load_locations(
store, testData->caIntFile, NULL), 1);
ExpectIntEQ(X509_STORE_load_locations(
store, testData->caInt2File, NULL), 1);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1);
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx));
ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain));
for (i = 0; i < sk_X509_num(chain); i++) {
ExpectIntEQ(X509_cmp(sk_X509_value(chain, i),
sk_X509_value(testData->expectedChain, i)), 0);
}
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
return EXPECT_RESULT();
}
static int test_wolfSSL_X509_STORE_CTX_ex3(X509_STORE_test_data *testData)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* chain = NULL;
int i = 0;
/* Test case 3, mix and match X509 with files */
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt), 1);
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1);
ExpectIntEQ(X509_STORE_load_locations(
store, testData->caFile, NULL), 1);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1);
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx));
ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain));
for (i = 0; i < sk_X509_num(chain); i++) {
ExpectIntEQ(X509_cmp(sk_X509_value(chain, i),
sk_X509_value(testData->expectedChain, i)), 0);
}
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
return EXPECT_RESULT();
}
static int test_wolfSSL_X509_STORE_CTX_ex4(X509_STORE_test_data *testData)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* chain = NULL;
STACK_OF(X509)* inter = NULL;
int i = 0;
/* Test case 4, CA loaded by file, intermediates passed on init */
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_load_locations(
store, testData->caFile, NULL), 1);
ExpectNotNull(inter = sk_X509_new_null());
ExpectIntGE(sk_X509_push(inter, testData->x509CaInt), 1);
ExpectIntGE(sk_X509_push(inter, testData->x509CaInt2), 1);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, inter), 1);
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx));
ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain));
for (i = 0; i < sk_X509_num(chain); i++) {
ExpectIntEQ(X509_cmp(sk_X509_value(chain, i),
sk_X509_value(testData->expectedChain, i)), 0);
}
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(inter);
return EXPECT_RESULT();
}
static int test_wolfSSL_X509_STORE_CTX_ex5(X509_STORE_test_data *testData)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* chain = NULL;
STACK_OF(X509)* trusted = NULL;
int i = 0;
/* Test case 5, manually set trusted stack */
ExpectNotNull(store = X509_STORE_new());
ExpectNotNull(trusted = sk_X509_new_null());
ExpectIntGE(sk_X509_push(trusted, testData->x509Ca), 1);
ExpectIntGE(sk_X509_push(trusted, testData->x509CaInt), 1);
ExpectIntGE(sk_X509_push(trusted, testData->x509CaInt2), 1);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1);
X509_STORE_CTX_trusted_stack(ctx, trusted);
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx));
ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain));
for (i = 0; i < sk_X509_num(chain); i++) {
ExpectIntEQ(X509_cmp(sk_X509_value(chain, i),
sk_X509_value(testData->expectedChain, i)), 0);
}
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(trusted);
return EXPECT_RESULT();
}
static int test_wolfSSL_X509_STORE_CTX_ex6(X509_STORE_test_data *testData)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* chain = NULL;
STACK_OF(X509)* trusted = NULL;
STACK_OF(X509)* inter = NULL;
int i = 0;
/* Test case 6, manually set trusted stack will be unified with
* any intermediates provided on init */
ExpectNotNull(store = X509_STORE_new());
ExpectNotNull(trusted = sk_X509_new_null());
ExpectNotNull(inter = sk_X509_new_null());
ExpectIntGE(sk_X509_push(trusted, testData->x509Ca), 1);
ExpectIntGE(sk_X509_push(inter, testData->x509CaInt), 1);
ExpectIntGE(sk_X509_push(inter, testData->x509CaInt2), 1);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, inter), 1);
X509_STORE_CTX_trusted_stack(ctx, trusted);
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx));
ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain));
for (i = 0; i < sk_X509_num(chain); i++) {
ExpectIntEQ(X509_cmp(sk_X509_value(chain, i),
sk_X509_value(testData->expectedChain, i)), 0);
}
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(trusted);
sk_X509_free(inter);
return EXPECT_RESULT();
}
static int test_wolfSSL_X509_STORE_CTX_ex7(X509_STORE_test_data *testData)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* chain = NULL;
int i = 0;
/* Test case 7, certs added to store after ctx init are still used */
ExpectNotNull(store = X509_STORE_new());
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1);
ExpectIntNE(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1);
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt), 1);
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509Ca), 1);
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx));
ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain));
for (i = 0; i < sk_X509_num(chain); i++) {
ExpectIntEQ(X509_cmp(sk_X509_value(chain, i),
sk_X509_value(testData->expectedChain, i)), 0);
}
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
return EXPECT_RESULT();
}
static int test_wolfSSL_X509_STORE_CTX_ex8(X509_STORE_test_data *testData)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* chain = NULL;
int i = 0;
/* Test case 8, Only full chain verifies */
ExpectNotNull(store = X509_STORE_new());
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1);
ExpectIntNE(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1);
ExpectIntNE(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt), 1);
ExpectIntNE(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509Ca), 1);
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx));
ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain));
for (i = 0; i < sk_X509_num(chain); i++) {
ExpectIntEQ(X509_cmp(sk_X509_value(chain, i),
sk_X509_value(testData->expectedChain, i)), 0);
}
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
return EXPECT_RESULT();
}
static int test_wolfSSL_X509_STORE_CTX_ex9(X509_STORE_test_data *testData)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
X509_STORE_CTX* ctx2 = NULL;
STACK_OF(X509)* trusted = NULL;
/* Test case 9, certs added to store should not be reflected in ctx that
* has been manually set with a trusted stack, but are reflected in ctx
* that has not set trusted stack */
ExpectNotNull(store = X509_STORE_new());
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectNotNull(ctx2 = X509_STORE_CTX_new());
ExpectNotNull(trusted = sk_X509_new_null());
ExpectIntGE(sk_X509_push(trusted, testData->x509Ca), 1);
ExpectIntGE(sk_X509_push(trusted, testData->x509CaInt), 1);
ExpectIntGE(sk_X509_push(trusted, testData->x509CaInt2), 1);
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1);
ExpectIntEQ(X509_STORE_CTX_init(ctx2, store, testData->x509Leaf, NULL), 1);
ExpectIntNE(X509_verify_cert(ctx), 1);
ExpectIntNE(X509_verify_cert(ctx2), 1);
X509_STORE_CTX_trusted_stack(ctx, trusted);
/* CTX1 should now verify */
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectIntNE(X509_verify_cert(ctx2), 1);
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509Ca), 1);
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt), 1);
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1);
/* CTX2 should now verify */
ExpectIntEQ(X509_verify_cert(ctx2), 1);
X509_STORE_CTX_free(ctx);
X509_STORE_CTX_free(ctx2);
X509_STORE_free(store);
sk_X509_free(trusted);
return EXPECT_RESULT();
}
static int test_wolfSSL_X509_STORE_CTX_ex10(X509_STORE_test_data *testData)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* chain = NULL;
/* Test case 10, ensure partial chain flag works */
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt), 1);
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1);
/* Fails because chain is incomplete */
ExpectIntNE(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN), 1);
/* Partial chain now OK */
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx));
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
return EXPECT_RESULT();
}
static int test_wolfSSL_X509_STORE_CTX_ex11(X509_STORE_test_data *testData)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* chain = NULL;
/* Test case 11, test partial chain flag on ctx itself */
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt), 1);
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1);
/* Fails because chain is incomplete */
ExpectIntNE(X509_verify_cert(ctx), 1);
X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_PARTIAL_CHAIN);
/* Partial chain now OK */
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx));
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
return EXPECT_RESULT();
}
static int test_wolfSSL_X509_STORE_CTX_ex_partial_chain_neg(
X509_STORE_test_data *testData)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* untrusted = NULL;
/* Negative partial-chain test: with X509_V_FLAG_PARTIAL_CHAIN set, the
* intermediates are supplied ONLY as untrusted (passed through the
* X509_STORE_CTX_init "chain" argument and never added to the store).
* No certificate in the chain is in the store, so verification must
* fail. Pre-fix, wolfSSL_X509_verify_cert would incorrectly accept
* this chain because its partial-chain fallback only checked that some
* intermediate had been temporarily loaded into the CertManager, not
* that any chain certificate was actually trusted. */
ExpectNotNull(store = X509_STORE_new());
/* Intentionally do NOT add x509CaInt, x509CaInt2, or x509Ca. */
ExpectIntEQ(X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN), 1);
ExpectNotNull(untrusted = sk_X509_new_null());
ExpectIntGT(sk_X509_push(untrusted, testData->x509CaInt2), 0);
ExpectIntGT(sk_X509_push(untrusted, testData->x509CaInt), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, untrusted),
1);
/* Must NOT verify: partial-chain does not relax the trust requirement. */
ExpectIntNE(X509_verify_cert(ctx), 1);
/* Verify the failure is specifically due to missing trust anchor, not
* some unrelated error. */
ExpectIntEQ(X509_STORE_CTX_get_error(ctx),
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(untrusted);
return EXPECT_RESULT();
}
static int test_wolfSSL_X509_STORE_CTX_ex_partial_chain_mixed(
X509_STORE_test_data *testData)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* untrusted = NULL;
/* Mixed trusted-store + untrusted-chain partial-chain test: the store
* trusts an intermediate (x509CaInt2, the leaf's direct issuer), while
* an additional intermediate (x509CaInt) is supplied only as untrusted
* via the chain argument. With X509_V_FLAG_PARTIAL_CHAIN, verification
* must succeed by terminating at the trusted intermediate. This test
* exercises the snapshot-based trust check in X509StoreCertIsTrusted:
* the untrusted intermediate injected during verification must not be
* treated as a trust anchor, but the intermediate already in the store
* must be. */
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1);
ExpectIntEQ(X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN), 1);
ExpectNotNull(untrusted = sk_X509_new_null());
ExpectIntGT(sk_X509_push(untrusted, testData->x509CaInt), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, untrusted),
1);
/* Must verify: chain terminates at trusted intermediate in the store. */
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_OK);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(untrusted);
return EXPECT_RESULT();
}
static int test_wolfSSL_X509_STORE_CTX_ex_partial_chain_untrusted_terminal(
X509_STORE_test_data *testData)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* untrusted = NULL;
/* Partial-chain boundary test: the store trusts a CA (x509Ca) that is
* NOT reachable from the leaf given the supplied untrusted intermediates,
* and an untrusted intermediate (x509CaInt2) IS the terminal of the
* (truncated) chain. With X509_V_FLAG_PARTIAL_CHAIN set, verification
* must FAIL because the chain terminates at an untrusted certificate.
*
* This test specifically targets the snapshot-based trust check in
* X509StoreCertIsTrusted. Before addAllButSelfSigned injects
* x509CaInt2, origTrustedSk is snapshotted from the caller-trusted set
* and contains only x509Ca. When the chain terminates at x509CaInt2,
* the trust check consults origTrustedSk (not the mutated working
* stack) and correctly finds no match. A regression that consulted
* the post-injection working stack instead of the snapshot would
* incorrectly mark x509CaInt2 as trusted and cause verification to
* succeed. */
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, testData->x509Ca), 1);
ExpectIntEQ(X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN), 1);
/* Only x509CaInt2 supplied as untrusted; x509CaInt is intentionally
* withheld so the chain cannot actually reach the trusted x509Ca. */
ExpectNotNull(untrusted = sk_X509_new_null());
ExpectIntGT(sk_X509_push(untrusted, testData->x509CaInt2), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, untrusted),
1);
/* Must NOT verify: the chain terminal (x509CaInt2) is not in the
* original trust set, even though the store is non-empty. */
ExpectIntNE(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx),
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(untrusted);
return EXPECT_RESULT();
}
#ifdef HAVE_ECC
static int test_wolfSSL_X509_STORE_CTX_ex12(void)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* chain = NULL;
X509* rootEccX509 = NULL;
X509* badAkiX509 = NULL;
X509* ca1X509 = NULL;
const char* intCARootECCFile = "./certs/ca-ecc-cert.pem";
const char* intCA1ECCFile = "./certs/intermediate/ca-int-ecc-cert.pem";
const char* intCABadAKIECCFile = "./certs/intermediate/ca-ecc-bad-aki.pem";
/* Test case 12, multiple CAs with the same SKI including 1 with
intentionally bad/unregistered AKI. x509_verify_cert should still form a
valid chain using the valid CA, ignoring the bad CA. Developed from
customer provided reproducer. */
ExpectNotNull(store = X509_STORE_new());
ExpectNotNull(rootEccX509 = test_wolfSSL_X509_STORE_CTX_ex_helper(
intCARootECCFile));
ExpectIntEQ(X509_STORE_add_cert(store, rootEccX509), 1);
ExpectNotNull(badAkiX509 = test_wolfSSL_X509_STORE_CTX_ex_helper(
intCABadAKIECCFile));
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, badAkiX509, NULL), 1);
ExpectIntEQ(X509_verify_cert(ctx), 0);
X509_STORE_CTX_cleanup(ctx);
ExpectIntEQ(X509_STORE_add_cert(store, badAkiX509), 1);
ExpectNotNull(ca1X509 = test_wolfSSL_X509_STORE_CTX_ex_helper(
intCA1ECCFile));
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, ca1X509, NULL), 1);
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx));
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
X509_free(rootEccX509);
X509_free(badAkiX509);
X509_free(ca1X509);
return EXPECT_RESULT();
}
#endif
#endif
int test_wolfSSL_X509_STORE_CTX_ex(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
!defined(NO_FILESYSTEM) && !defined(NO_RSA)
X509_STORE_test_data testData;
XMEMSET((void *)&testData, 0, sizeof(X509_STORE_test_data));
testData.caFile = "./certs/ca-cert.pem";
testData.caIntFile = "./certs/intermediate/ca-int-cert.pem";
testData.caInt2File = "./certs/intermediate/ca-int2-cert.pem";
testData.leafFile = "./certs/intermediate/server-chain.pem";
ExpectNotNull(testData.x509Ca = \
test_wolfSSL_X509_STORE_CTX_ex_helper(testData.caFile));
ExpectNotNull(testData.x509CaInt = \
test_wolfSSL_X509_STORE_CTX_ex_helper(testData.caIntFile));
ExpectNotNull(testData.x509CaInt2 = \
test_wolfSSL_X509_STORE_CTX_ex_helper(testData.caInt2File));
ExpectNotNull(testData.x509Leaf = \
test_wolfSSL_X509_STORE_CTX_ex_helper(testData.leafFile));
ExpectNotNull(testData.expectedChain = sk_X509_new_null());
ExpectIntGE(sk_X509_push(testData.expectedChain, testData.x509Leaf), 1);
ExpectIntGE(sk_X509_push(testData.expectedChain, testData.x509CaInt2), 1);
ExpectIntGE(sk_X509_push(testData.expectedChain, testData.x509CaInt), 1);
ExpectIntGE(sk_X509_push(testData.expectedChain, testData.x509Ca), 1);
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex1(&testData), 1);
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex2(&testData), 1);
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex3(&testData), 1);
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex4(&testData), 1);
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex5(&testData), 1);
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex6(&testData), 1);
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex7(&testData), 1);
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex8(&testData), 1);
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex9(&testData), 1);
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex10(&testData), 1);
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex11(&testData), 1);
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex_partial_chain_neg(&testData), 1);
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex_partial_chain_mixed(&testData),
1);
ExpectIntEQ(
test_wolfSSL_X509_STORE_CTX_ex_partial_chain_untrusted_terminal(
&testData), 1);
#ifdef HAVE_ECC
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex12(), 1);
#endif
if(testData.x509Ca) {
X509_free(testData.x509Ca);
}
if(testData.x509CaInt) {
X509_free(testData.x509CaInt);
}
if(testData.x509CaInt2) {
X509_free(testData.x509CaInt2);
}
if(testData.x509Leaf) {
X509_free(testData.x509Leaf);
}
if (testData.expectedChain) {
sk_X509_free(testData.expectedChain);
}
#endif /* defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
* !defined(NO_FILESYSTEM) && !defined(NO_RSA) */
return EXPECT_RESULT();
}
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_CERTS) && \
!defined(NO_FILESYSTEM)
/* Regression: an untrusted intermediate supplied to wolfSSL_X509_verify_cert()
* via the X509_STORE_CTX_init "chain" argument must never be treated as a
* trust anchor. Verification may only succeed when the chain terminates at a
* certificate the caller actually trusts.
*
* leaf (CN=www.example.test) <- int-ca (CA) <- root-ca (self-signed)
*
* The attack sub-cases (empty trust store, a populated-but-wrong trust anchor,
* and a tampered intermediate signature) must all be rejected; the single- and
* two-intermediate chains that genuinely reach the trusted root must still
* verify. Certificates live in certs/intermediate/untrusted_anchor/.
*/
static X509* untrusted_inter_load(const char* file)
{
return X509_load_certificate_file(file, SSL_FILETYPE_PEM);
}
/* Positive control: leaf <- int-ca <- root with the genuine self-signed root
* trusted. Must verify - guards against a test that merely rejects
* everything. */
static int test_untrusted_inter_sanity(X509* leaf, X509* inter, X509* root)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* untrusted = NULL;
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, root), 1);
ExpectNotNull(untrusted = sk_X509_new_null());
ExpectIntGT(sk_X509_push(untrusted, inter), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, untrusted), 1);
/* Chain reaches the trusted root -> must verify. */
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_OK);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(untrusted);
return EXPECT_RESULT();
}
/* Positive control with two untrusted intermediates:
* leaf-deep <- int-ca2 <- int-ca <- root (root trusted).
* A legitimate multi-level chain that genuinely reaches the trusted root must
* still verify; guards against over-rejecting deeper chains. */
static int test_untrusted_inter_two_level(X509* leafDeep, X509* inter,
X509* inter2, X509* root)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* untrusted = NULL;
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, root), 1);
ExpectNotNull(untrusted = sk_X509_new_null());
ExpectIntGT(sk_X509_push(untrusted, inter), 0);
ExpectIntGT(sk_X509_push(untrusted, inter2), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leafDeep, untrusted), 1);
/* Two-level chain reaches the trusted root -> must verify. */
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_OK);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(untrusted);
return EXPECT_RESULT();
}
/* Empty trust store. The untrusted intermediate must not anchor the path -
* with nothing trusted, verification must fail. */
static int test_untrusted_inter_empty_store(X509* leaf, X509* inter)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* untrusted = NULL;
ExpectNotNull(store = X509_STORE_new());
/* Intentionally empty: no trusted certificates added. */
ExpectNotNull(untrusted = sk_X509_new_null());
ExpectIntGT(sk_X509_push(untrusted, inter), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, untrusted), 1);
/* No trust anchor exists -> rejected with "issuer not found". */
ExpectIntEQ(X509_verify_cert(ctx), 0);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx),
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(untrusted);
return EXPECT_RESULT();
}
/* Populated but wrong trust store. An unrelated self-signed root is trusted;
* it did not issue the intermediate, so verification must fail. */
static int test_untrusted_inter_wrong_anchor(X509* leaf, X509* inter,
X509* wrongRoot)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* untrusted = NULL;
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, wrongRoot), 1);
ExpectNotNull(untrusted = sk_X509_new_null());
ExpectIntGT(sk_X509_push(untrusted, inter), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, untrusted), 1);
/* Trusted root did not issue the intermediate -> "issuer not found". */
ExpectIntEQ(X509_verify_cert(ctx), 0);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx),
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(untrusted);
return EXPECT_RESULT();
}
/* Tampered intermediate signature. The real root is trusted but the
* intermediate's outer signature is corrupt, so it is not authentically
* signed - verification must fail. */
static int test_untrusted_inter_tampered(X509* leaf, X509* tamperedInter,
X509* root)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* untrusted = NULL;
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, root), 1);
ExpectNotNull(untrusted = sk_X509_new_null());
ExpectIntGT(sk_X509_push(untrusted, tamperedInter), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, untrusted), 1);
/* Intermediate is not authentically signed -> rejected. Assert only the
* rejection (error != X509_V_OK), not a specific code: wolfSSL currently
* surfaces the corrupt intermediate as "no valid issuer" rather than a
* signature-failure error, and pinning that quirk would turn a future
* error-reporting improvement into a spurious test failure. */
ExpectIntEQ(X509_verify_cert(ctx), 0);
ExpectIntNE(X509_STORE_CTX_get_error(ctx), X509_V_OK);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(untrusted);
return EXPECT_RESULT();
}
/* Reuse one store across a rejected verification followed immediately by a
* good one. The rejected attempt temporarily loads an intermediate into the
* store's CertManager and pushes the caller intermediates onto its working
* list; a failed check must clean both up so the store is left in a pristine
* state. Verifying a genuine chain on the same store right afterwards proves
* nothing stale was left behind. */
static int test_untrusted_inter_reused_store(X509* leaf, X509* inter,
X509* tamperedInter, X509* root)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* badChain = NULL;
STACK_OF(X509)* goodChain = NULL;
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, root), 1);
/* First: a chain that must be rejected (tampered intermediate signature).
* This is the path that loads the intermediate into the store. */
ExpectNotNull(badChain = sk_X509_new_null());
ExpectIntGT(sk_X509_push(badChain, tamperedInter), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, badChain), 1);
ExpectIntEQ(X509_verify_cert(ctx), 0);
ExpectIntNE(X509_STORE_CTX_get_error(ctx), X509_V_OK);
X509_STORE_CTX_free(ctx);
ctx = NULL;
/* Then: reuse the SAME store for the genuine chain. If the failed check
* left stale state behind (a temporarily-loaded intermediate or
* unrestored working list), this would misbehave. */
ExpectNotNull(goodChain = sk_X509_new_null());
ExpectIntGT(sk_X509_push(goodChain, inter), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, goodChain), 1);
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_OK);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(badChain);
sk_X509_free(goodChain);
return EXPECT_RESULT();
}
/* A verification that loads an intermediate must not leave it behind to anchor
* a later chain. Verify a genuine chain on the store (which temporarily loads
* the intermediate), then reuse the SAME store to verify the leaf alone with
* NO intermediate supplied: the leaf's issuer is not in the trusted store, so
* it must be rejected. If the first check left the intermediate loaded, this
* second one would wrongly succeed. */
static int test_untrusted_inter_no_stale_anchor(X509* leaf, X509* inter,
X509* root)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* chain = NULL;
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, root), 1);
/* First: genuine chain verifies (temporarily loads the intermediate). */
ExpectNotNull(chain = sk_X509_new_null());
ExpectIntGT(sk_X509_push(chain, inter), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, chain), 1);
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_OK);
X509_STORE_CTX_free(ctx);
ctx = NULL;
/* Then: reuse the SAME store, leaf alone, NO intermediate supplied. The
* leaf's issuer is not trusted, so this must be rejected. A stale
* intermediate left behind by the first check would wrongly anchor it. */
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, NULL), 1);
ExpectIntEQ(X509_verify_cert(ctx), 0);
ExpectIntNE(X509_STORE_CTX_get_error(ctx), X509_V_OK);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(chain);
return EXPECT_RESULT();
}
/* Depth exhaustion: a chain that cannot be walked to the trusted anchor within
* the configured path-building depth budget must be rejected,.
*
* leaf-deep <- int-ca2 <- int-ca <- root (root trusted)
*
* The chain is genuine and verifies at the default depth (covered by
* test_untrusted_inter_two_level); here the depth is capped below the chain
* length so the budget is consumed before the trusted root is reached. The
* fix must report it as "certificate chain too long". */
static int test_untrusted_inter_depth_exhaustion(X509* leafDeep, X509* inter,
X509* inter2, X509* root)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* untrusted = NULL;
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, root), 1);
ExpectNotNull(untrusted = sk_X509_new_null());
ExpectIntGT(sk_X509_push(untrusted, inter), 0);
ExpectIntGT(sk_X509_push(untrusted, inter2), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leafDeep, untrusted), 1);
/* Cap the path-building budget below the chain length so the walk runs
* out of depth before it can reach the trusted root. */
X509_STORE_CTX_set_depth(ctx, 1);
ExpectIntEQ(X509_verify_cert(ctx), 0);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx),
X509_V_ERR_CERT_CHAIN_TOO_LONG);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(untrusted);
return EXPECT_RESULT();
}
/* Intermediate-stack cleanup: the caller-supplied intermediates that the
* verifier temporarily appends to its working cert list must be removed from
* the exact stack they were added to once verification finishes. When a
* trusted_stack is in use (X509_STORE_CTX_set0_trusted_stack), they are
* appended to that caller-owned stack; if they are not removed again, a later
* verification reusing the stack/ctx would snapshot them as trust anchors.
*
* leaf <- int-ca <- root, with root supplied via the trusted_stack.
*
* Verify the chain (which reaches root in the trusted stack), then assert the
* trusted stack is left exactly as the caller supplied it: only root, with the
* injected intermediate removed again. */
static int test_untrusted_inter_trusted_stack_cleanup(X509* leaf, X509* inter,
X509* root)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* trusted = NULL;
STACK_OF(X509)* untrusted = NULL;
ExpectNotNull(store = X509_STORE_new());
ExpectNotNull(trusted = sk_X509_new_null());
ExpectIntGT(sk_X509_push(trusted, root), 0);
ExpectNotNull(untrusted = sk_X509_new_null());
ExpectIntGT(sk_X509_push(untrusted, inter), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, untrusted), 1);
X509_STORE_CTX_trusted_stack(ctx, trusted);
/* Chain reaches root in the trusted stack -> verifies. */
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_OK);
/* The trusted stack must be restored: the injected intermediate appended
* during verification must have been removed, leaving only root. */
ExpectIntEQ(sk_X509_num(trusted), 1);
ExpectPtrEq(sk_X509_value(trusted, 0), root);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(untrusted);
sk_X509_free(trusted);
return EXPECT_RESULT();
}
/* One mixed-candidate verification: leaf with both the tampered intermediate
* (broken outer signature, same subject as int-ca) and the genuine int-ca in
* the untrusted stack, in the given push order. The chain must verify - the
* verifier tries the candidates and recovers via X509VerifyCertSetupRetry when
* it hits the tampered one first. Only the return value is asserted: when the
* tampered candidate is tried first wolfSSL intentionally preserves its error
* code even though the chain recovers (see the "worst-seen error must persist"
* behaviour exercised by test_X509_STORE_InvalidCa), so the error after success
* is order-dependent and not asserted here. */
static int untrusted_inter_retry_one(X509_STORE* store, X509* leaf,
X509* first, X509* second)
{
EXPECT_DECLS;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* mixed = NULL;
ExpectNotNull(mixed = sk_X509_new_null());
ExpectIntGT(sk_X509_push(mixed, first), 0);
ExpectIntGT(sk_X509_push(mixed, second), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, mixed), 1);
ExpectIntEQ(X509_verify_cert(ctx), 1);
X509_STORE_CTX_free(ctx);
sk_X509_free(mixed);
return EXPECT_RESULT();
}
/* Retry path: when several caller-supplied candidates share a subject, the
* verifier tries one, fails, and retries with another
* (X509VerifyCertSetupRetry), moving entries through an internal "failed" list.
* Exercise BOTH push orderings so that, whichever order the verifier enumerates
* same-subject candidates, at least one ordering forces it to hit the tampered
* candidate first and recover. Then prove the store is left clean: a later
* verification on the same store with only the tampered intermediate must fail
* (no genuine int-ca left behind), and one with the genuine intermediate must
* still succeed. */
static int test_untrusted_inter_retry(X509* leaf, X509* inter,
X509* tamperedInter, X509* root)
{
EXPECT_DECLS;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* goodOnly = NULL;
STACK_OF(X509)* badOnly = NULL;
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, root), 1);
/* Both orderings verify and report X509_V_OK. */
ExpectIntEQ(untrusted_inter_retry_one(store, leaf, tamperedInter, inter), 1);
ExpectIntEQ(untrusted_inter_retry_one(store, leaf, inter, tamperedInter), 1);
/* Reuse the SAME store with only the tampered intermediate: must fail. If
* a retry above left the genuine int-ca behind in the store, this would
* wrongly succeed. */
ExpectNotNull(badOnly = sk_X509_new_null());
ExpectIntGT(sk_X509_push(badOnly, tamperedInter), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, badOnly), 1);
ExpectIntEQ(X509_verify_cert(ctx), 0);
ExpectIntNE(X509_STORE_CTX_get_error(ctx), X509_V_OK);
X509_STORE_CTX_free(ctx);
ctx = NULL;
/* Reuse the SAME store with the genuine intermediate: must still succeed,
* proving the retry left no stale state that breaks later verifications. */
ExpectNotNull(goodOnly = sk_X509_new_null());
ExpectIntGT(sk_X509_push(goodOnly, inter), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, goodOnly), 1);
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_OK);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(goodOnly);
sk_X509_free(badOnly);
return EXPECT_RESULT();
}
#endif /* OPENSSL_EXTRA && !NO_RSA && !NO_CERTS && !NO_FILESYSTEM */
int test_X509_verify_cert_untrusted_inter(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_CERTS) && \
!defined(NO_FILESYSTEM)
#define UA_CERT_DIR "./certs/intermediate/untrusted_anchor/"
X509* leaf = NULL;
X509* leafDeep = NULL;
X509* inter = NULL;
X509* inter2 = NULL;
X509* tamperedInter = NULL;
X509* root = NULL;
X509* wrongRoot = NULL;
int sanityRes = 0;
int twoLevelRes = 0;
int emptyStoreRes = 0;
int wrongAnchorRes = 0;
int tamperedRes = 0;
int reusedStoreRes = 0;
int noStaleRes = 0;
int depthExhaustRes = 0;
int trustedStackCleanupRes = 0;
int retryRes = 0;
ExpectNotNull(leaf = untrusted_inter_load(UA_CERT_DIR "leaf-cert.pem"));
ExpectNotNull(leafDeep =
untrusted_inter_load(UA_CERT_DIR "leaf-deep-cert.pem"));
ExpectNotNull(inter = untrusted_inter_load(UA_CERT_DIR "int-ca-cert.pem"));
ExpectNotNull(inter2 =
untrusted_inter_load(UA_CERT_DIR "int-ca2-cert.pem"));
ExpectNotNull(tamperedInter =
untrusted_inter_load(UA_CERT_DIR "int-ca-tampered-cert.pem"));
ExpectNotNull(root = untrusted_inter_load(UA_CERT_DIR "root-ca-cert.pem"));
ExpectNotNull(wrongRoot =
untrusted_inter_load(UA_CERT_DIR "alt-ca-cert.pem"));
/* Run every sub-case unconditionally - each reports its own result - so a
* regression in one does not mask the others. */
if (leaf != NULL && leafDeep != NULL && inter != NULL && inter2 != NULL &&
tamperedInter != NULL && root != NULL && wrongRoot != NULL) {
sanityRes = test_untrusted_inter_sanity(leaf, inter, root);
twoLevelRes = test_untrusted_inter_two_level(leafDeep, inter,
inter2, root);
emptyStoreRes = test_untrusted_inter_empty_store(leaf, inter);
wrongAnchorRes = test_untrusted_inter_wrong_anchor(leaf, inter,
wrongRoot);
tamperedRes = test_untrusted_inter_tampered(leaf, tamperedInter,
root);
reusedStoreRes = test_untrusted_inter_reused_store(leaf, inter,
tamperedInter, root);
noStaleRes = test_untrusted_inter_no_stale_anchor(leaf, inter,
root);
depthExhaustRes = test_untrusted_inter_depth_exhaustion(leafDeep,
inter, inter2, root);
trustedStackCleanupRes = test_untrusted_inter_trusted_stack_cleanup(
leaf, inter, root);
retryRes = test_untrusted_inter_retry(leaf, inter, tamperedInter, root);
ExpectIntEQ(sanityRes, 1);
ExpectIntEQ(twoLevelRes, 1);
ExpectIntEQ(emptyStoreRes, 1);
ExpectIntEQ(wrongAnchorRes, 1);
ExpectIntEQ(tamperedRes, 1);
ExpectIntEQ(reusedStoreRes, 1);
ExpectIntEQ(noStaleRes, 1);
ExpectIntEQ(depthExhaustRes, 1);
ExpectIntEQ(trustedStackCleanupRes, 1);
ExpectIntEQ(retryRes, 1);
}
X509_free(leaf);
X509_free(leafDeep);
X509_free(inter);
X509_free(inter2);
X509_free(tamperedInter);
X509_free(root);
X509_free(wrongRoot);
#undef UA_CERT_DIR
#endif /* OPENSSL_EXTRA && !NO_RSA && !NO_CERTS && !NO_FILESYSTEM */
return EXPECT_RESULT();
}
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_CERTS) && \
defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT) && \
!defined(NO_SHA256) && defined(USE_CERT_BUFFERS_2048) && \
!defined(NO_ASN_TIME) && !defined(ALLOW_INVALID_CERTSIGN)
/* Build a CA:TRUE intermediate signed by the 2048-bit test root
* (ca_cert_der_2048 / ca_key_der_2048). keyUsage == NULL omits the KeyUsage
* extension entirely. Returns the DER length, or <= 0 on failure. */
static int gen_ca_int_keyusage(byte* out, int outMax, RsaKey* subjKey,
RsaKey* caKey, WC_RNG* rng, const char* cn, const char* keyUsage)
{
Cert cert;
if (wc_InitCert(&cert) != 0)
return -1;
cert.isCA = 1;
cert.sigType = CTC_SHA256wRSA;
XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE - 1);
XSTRNCPY(cert.subject.org, "wolfSSL_test", CTC_NAME_SIZE - 1);
XSTRNCPY(cert.subject.commonName, cn, CTC_NAME_SIZE - 1);
if (wc_SetSubjectKeyIdFromPublicKey(&cert, subjKey, NULL) != 0)
return -1;
if (wc_SetAuthKeyIdFromCert(&cert, ca_cert_der_2048,
(int)sizeof_ca_cert_der_2048) != 0)
return -1;
if (keyUsage != NULL && wc_SetKeyUsage(&cert, keyUsage) != 0)
return -1;
if (wc_SetIssuerBuffer(&cert, ca_cert_der_2048,
(int)sizeof_ca_cert_der_2048) != 0)
return -1;
if (wc_MakeCert(&cert, out, (word32)outMax, subjKey, NULL, rng) < 0)
return -1;
return wc_SignCert(cert.bodySz, cert.sigType, out, (word32)outMax, caKey,
NULL, rng);
}
/* Build a leaf signed by the given intermediate (its DER + private key). */
static int gen_leaf_under_int(byte* out, int outMax, RsaKey* leafKey,
const byte* issuerDer, int issuerDerSz, RsaKey* issuerKey, WC_RNG* rng,
const char* cn)
{
Cert cert;
if (wc_InitCert(&cert) != 0)
return -1;
cert.isCA = 0;
cert.sigType = CTC_SHA256wRSA;
XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE - 1);
XSTRNCPY(cert.subject.org, "wolfSSL_test", CTC_NAME_SIZE - 1);
XSTRNCPY(cert.subject.commonName, cn, CTC_NAME_SIZE - 1);
if (wc_SetSubjectKeyIdFromPublicKey(&cert, leafKey, NULL) != 0)
return -1;
if (wc_SetAuthKeyIdFromCert(&cert, issuerDer, issuerDerSz) != 0)
return -1;
if (wc_SetKeyUsage(&cert, "digitalSignature") != 0)
return -1;
if (wc_SetIssuerBuffer(&cert, issuerDer, issuerDerSz) != 0)
return -1;
if (wc_MakeCert(&cert, out, (word32)outMax, leafKey, NULL, rng) < 0)
return -1;
return wc_SignCert(cert.bodySz, cert.sigType, out, (word32)outMax,
issuerKey, NULL, rng);
}
/* Verify "leaf <- intermediate <- root(ca-cert)" where the intermediate is
* supplied only as an untrusted candidate. Returns the X509_verify_cert()
* result (1 verified, 0 rejected) via *verifyRet. */
static int run_int_keyusage_case(const byte* intDer, int intSz,
const byte* leafDer, int leafSz, X509* root, int* verifyRet)
{
EXPECT_DECLS;
X509* inter = NULL;
X509* leaf = NULL;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* untrusted = NULL;
const byte* p;
p = intDer;
ExpectNotNull(inter = d2i_X509(NULL, &p, intSz));
p = leafDer;
ExpectNotNull(leaf = d2i_X509(NULL, &p, leafSz));
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, root), 1);
ExpectNotNull(untrusted = sk_X509_new_null());
ExpectIntGT(sk_X509_push(untrusted, inter), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, untrusted), 1);
if (verifyRet != NULL)
*verifyRet = X509_verify_cert(ctx);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(untrusted);
X509_free(leaf);
X509_free(inter);
return EXPECT_RESULT();
}
#endif
/* Regression: a chain-supplied (untrusted) intermediate that is CA:TRUE but
* whose KeyUsage extension does NOT assert keyCertSign must NOT be usable to
* sign the leaf - RFC 5280 4.2.1.3. Previously such an intermediate, added as
* a temporary CA during path building, was accepted as a signing CA.
*
* Conversely, an intermediate with NO KeyUsage extension implies all usages
* (including keyCertSign) and must still verify - the fix must not over-reject
* those. */
int test_X509_verify_cert_ca_no_keycertsign(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_CERTS) && \
defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT) && \
!defined(NO_SHA256) && defined(USE_CERT_BUFFERS_2048) && \
!defined(NO_ASN_TIME) && !defined(ALLOW_INVALID_CERTSIGN)
/* ALLOW_INVALID_CERTSIGN disables the keyCertSign enforcement that Case 1
* relies on, so the test is only meaningful when it is not defined. */
WC_RNG rng;
RsaKey caKey, intKey, leafKey;
int rngI = 0, caI = 0, intI = 0, leafI = 0;
word32 idx;
byte* intDer = NULL;
byte* leafDer = NULL;
int intSz = 0, leafSz = 0;
int verifyRet = -1;
const byte* p;
X509* root = NULL;
intDer = (byte*)XMALLOC(FOURK_BUF, NULL, DYNAMIC_TYPE_TMP_BUFFER);
leafDer = (byte*)XMALLOC(FOURK_BUF, NULL, DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(intDer);
ExpectNotNull(leafDer);
ExpectIntEQ(wc_InitRng(&rng), 0);
if (EXPECT_SUCCESS()) rngI = 1;
ExpectIntEQ(wc_InitRsaKey(&caKey, NULL), 0);
if (EXPECT_SUCCESS()) caI = 1;
idx = 0;
ExpectIntEQ(wc_RsaPrivateKeyDecode(ca_key_der_2048, &idx, &caKey,
sizeof_ca_key_der_2048), 0);
ExpectIntEQ(wc_InitRsaKey(&intKey, NULL), 0);
if (EXPECT_SUCCESS()) intI = 1;
idx = 0;
ExpectIntEQ(wc_RsaPrivateKeyDecode(server_key_der_2048, &idx, &intKey,
sizeof_server_key_der_2048), 0);
ExpectIntEQ(wc_InitRsaKey(&leafKey, NULL), 0);
if (EXPECT_SUCCESS()) leafI = 1;
idx = 0;
ExpectIntEQ(wc_RsaPrivateKeyDecode(client_key_der_2048, &idx, &leafKey,
sizeof_client_key_der_2048), 0);
p = ca_cert_der_2048;
ExpectNotNull(root = d2i_X509(NULL, &p, (int)sizeof_ca_cert_der_2048));
/* Case 1: intermediate CA WITHOUT keyCertSign -> verification must fail. */
ExpectIntGT((intSz = gen_ca_int_keyusage(intDer, FOURK_BUF, &intKey, &caKey,
&rng, "No keyCertSign Intermediate", "digitalSignature")), 0);
ExpectIntGT((leafSz = gen_leaf_under_int(leafDer, FOURK_BUF, &leafKey,
intDer, intSz, &intKey, &rng, "Leaf under bad int")), 0);
verifyRet = -1;
ExpectIntEQ(run_int_keyusage_case(intDer, intSz, leafDer, leafSz, root,
&verifyRet), 1);
ExpectIntNE(verifyRet, 1);
/* Case 2: intermediate CA with NO KeyUsage extension -> must verify. */
ExpectIntGT((intSz = gen_ca_int_keyusage(intDer, FOURK_BUF, &intKey, &caKey,
&rng, "No KeyUsage Intermediate", NULL)), 0);
ExpectIntGT((leafSz = gen_leaf_under_int(leafDer, FOURK_BUF, &leafKey,
intDer, intSz, &intKey, &rng, "Leaf under noKU int")), 0);
verifyRet = -1;
ExpectIntEQ(run_int_keyusage_case(intDer, intSz, leafDer, leafSz, root,
&verifyRet), 1);
ExpectIntEQ(verifyRet, 1);
X509_free(root);
if (rngI) wc_FreeRng(&rng);
if (caI) wc_FreeRsaKey(&caKey);
if (intI) wc_FreeRsaKey(&intKey);
if (leafI) wc_FreeRsaKey(&leafKey);
XFREE(intDer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(leafDer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return EXPECT_RESULT();
}
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_FILESYSTEM)
static int test_X509_STORE_untrusted_load_cert_to_stack(const char* filename,
STACK_OF(X509)* chain)
{
EXPECT_DECLS;
XFILE fp = XBADFILE;
X509* cert = NULL;
ExpectTrue((fp = XFOPEN(filename, "rb"))
!= XBADFILE);
ExpectNotNull(cert = PEM_read_X509(fp, 0, 0, 0 ));
if (fp != XBADFILE) {
XFCLOSE(fp);
fp = XBADFILE;
}
ExpectIntGT(sk_X509_push(chain, cert), 0);
if (EXPECT_FAIL())
X509_free(cert);
return EXPECT_RESULT();
}
static int test_X509_STORE_untrusted_certs(const char** filenames, int ret,
int err, int loadCA)
{
EXPECT_DECLS;
X509_STORE_CTX* ctx = NULL;
X509_STORE* str = NULL;
XFILE fp = XBADFILE;
X509* cert = NULL;
STACK_OF(X509)* untrusted = NULL;
ExpectTrue((fp = XFOPEN("./certs/intermediate/server-int-cert.pem", "rb"))
!= XBADFILE);
ExpectNotNull(cert = PEM_read_X509(fp, 0, 0, 0 ));
if (fp != XBADFILE) {
XFCLOSE(fp);
fp = XBADFILE;
}
ExpectNotNull(str = X509_STORE_new());
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectNotNull(untrusted = sk_X509_new_null());
ExpectIntEQ(X509_STORE_set_flags(str, 0), 1);
if (loadCA) {
ExpectIntEQ(X509_STORE_load_locations(str, "./certs/ca-cert.pem", NULL),
1);
}
for (; *filenames; filenames++) {
ExpectIntEQ(test_X509_STORE_untrusted_load_cert_to_stack(*filenames,
untrusted), TEST_SUCCESS);
}
ExpectIntEQ(X509_STORE_CTX_init(ctx, str, cert, untrusted), 1);
ExpectIntEQ(X509_verify_cert(ctx), ret);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), err);
X509_free(cert);
X509_STORE_free(str);
X509_STORE_CTX_free(ctx);
sk_X509_pop_free(untrusted, NULL);
return EXPECT_RESULT();
}
#endif
int test_X509_STORE_untrusted(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_FILESYSTEM)
const char* untrusted1[] = {
"./certs/intermediate/ca-int2-cert.pem",
NULL
};
const char* untrusted2[] = {
"./certs/intermediate/ca-int-cert.pem",
"./certs/intermediate/ca-int2-cert.pem",
NULL
};
const char* untrusted3[] = {
"./certs/intermediate/ca-int-cert.pem",
"./certs/intermediate/ca-int2-cert.pem",
"./certs/ca-cert.pem",
NULL
};
/* Adding unrelated certs that should be ignored */
const char* untrusted4[] = {
"./certs/client-ca.pem",
"./certs/intermediate/ca-int-cert.pem",
"./certs/server-cert.pem",
"./certs/intermediate/ca-int2-cert.pem",
NULL
};
/* Only immediate issuer in untrusted chain. Fails since can't build chain
* to loaded CA. */
ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted1, 0,
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, 1), TEST_SUCCESS);
/* Succeeds because path to loaded CA is available. */
ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted2, 1, 0, 1),
TEST_SUCCESS);
/* Root CA in untrusted chain is OK so long as CA has been loaded
* properly */
ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted3, 1, 0, 1),
TEST_SUCCESS);
/* Still needs properly loaded CA, while including it in untrusted
* list is not an error, it also doesn't count for verify */
ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted3, 0,
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, 0),
TEST_SUCCESS);
/* Succeeds because path to loaded CA is available. */
ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted4, 1, 0, 1),
TEST_SUCCESS);
#endif
return EXPECT_RESULT();
}
#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \
!defined(WOLFSSL_X509_STORE_ALLOW_NON_CA_INTERMEDIATE)
static int last_errcode;
static int last_errdepth;
static int X509Callback(int ok, X509_STORE_CTX *ctx)
{
if (!ok) {
last_errcode = X509_STORE_CTX_get_error(ctx);
last_errdepth = X509_STORE_CTX_get_error_depth(ctx);
}
/* Always return OK to allow verification to continue.*/
return 1;
}
#endif
int test_X509_STORE_InvalidCa(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \
!defined(WOLFSSL_X509_STORE_ALLOW_NON_CA_INTERMEDIATE)
const char* filename = "./certs/intermediate/ca_false_intermediate/"
"test_int_not_cacert.pem";
const char* srvfile = "./certs/intermediate/ca_false_intermediate/"
"test_sign_bynoca_srv.pem";
X509_STORE_CTX* ctx = NULL;
X509_STORE* str = NULL;
XFILE fp = XBADFILE;
X509* cert = NULL;
STACK_OF(X509)* untrusted = NULL;
last_errcode = 0;
last_errdepth = 0;
ExpectTrue((fp = XFOPEN(srvfile, "rb"))
!= XBADFILE);
ExpectNotNull(cert = PEM_read_X509(fp, 0, 0, 0 ));
if (fp != XBADFILE) {
XFCLOSE(fp);
fp = XBADFILE;
}
ExpectNotNull(str = X509_STORE_new());
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectNotNull(untrusted = sk_X509_new_null());
/* create cert chain stack */
ExpectIntEQ(test_X509_STORE_untrusted_load_cert_to_stack(filename,
untrusted), TEST_SUCCESS);
X509_STORE_set_verify_cb(str, X509Callback);
ExpectIntEQ(X509_STORE_load_locations(str,
"./certs/intermediate/ca_false_intermediate/test_ca.pem",
NULL), 1);
ExpectIntEQ(X509_STORE_CTX_init(ctx, str, cert, untrusted), 1);
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectIntEQ(last_errcode, X509_V_ERR_INVALID_CA);
(void)last_errdepth;
/* Defense in depth: ctx->error must not be clobbered back to X509_V_OK
* by the later successful verification of the intermediate against the
* trusted root. The worst-seen error must persist. */
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_ERR_INVALID_CA);
X509_free(cert);
X509_STORE_free(str);
X509_STORE_CTX_free(ctx);
sk_X509_pop_free(untrusted, NULL);
#endif
return EXPECT_RESULT();
}
int test_X509_STORE_InvalidCa_NoCallback(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \
!defined(WOLFSSL_X509_STORE_ALLOW_NON_CA_INTERMEDIATE)
const char* filename = "./certs/intermediate/ca_false_intermediate/"
"test_int_not_cacert.pem";
const char* srvfile = "./certs/intermediate/ca_false_intermediate/"
"test_sign_bynoca_srv.pem";
X509_STORE_CTX* ctx = NULL;
X509_STORE* str = NULL;
XFILE fp = XBADFILE;
X509* cert = NULL;
STACK_OF(X509)* untrusted = NULL;
ExpectTrue((fp = XFOPEN(srvfile, "rb"))
!= XBADFILE);
ExpectNotNull(cert = PEM_read_X509(fp, 0, 0, 0 ));
if (fp != XBADFILE) {
XFCLOSE(fp);
fp = XBADFILE;
}
ExpectNotNull(str = X509_STORE_new());
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectNotNull(untrusted = sk_X509_new_null());
/* Create cert chain stack with an intermediate that is CA:FALSE. */
ExpectIntEQ(test_X509_STORE_untrusted_load_cert_to_stack(filename,
untrusted), TEST_SUCCESS);
ExpectIntEQ(X509_STORE_load_locations(str,
"./certs/intermediate/ca_false_intermediate/test_ca.pem",
NULL), 1);
ExpectIntEQ(X509_STORE_CTX_init(ctx, str, cert, untrusted), 1);
/* No verify callback: verification must fail on CA:FALSE issuer. */
ExpectIntNE(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_ERR_INVALID_CA);
X509_free(cert);
X509_STORE_free(str);
X509_STORE_CTX_free(ctx);
sk_X509_pop_free(untrusted, NULL);
#endif
return EXPECT_RESULT();
}
int test_wolfSSL_X509_STORE_CTX_trusted_stack_cleanup(void)
{
int res = TEST_SKIPPED;
#if defined(OPENSSL_EXTRA)
X509_STORE_CTX_cleanup(NULL);
X509_STORE_CTX_trusted_stack(NULL, NULL);
res = TEST_SUCCESS;
#endif
return res;
}
int test_wolfSSL_X509_STORE_CTX_get_issuer(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_FILESYSTEM)
X509_STORE_CTX* ctx = NULL;
X509_STORE* str = NULL;
X509* x509Ca = NULL;
X509* x509Svr = NULL;
X509* issuer = NULL;
X509_NAME* caName = NULL;
X509_NAME* issuerName = NULL;
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectNotNull((str = wolfSSL_X509_STORE_new()));
ExpectNotNull((x509Ca =
wolfSSL_X509_load_certificate_file(caCertFile, SSL_FILETYPE_PEM)));
ExpectIntEQ(X509_STORE_add_cert(str, x509Ca), SSL_SUCCESS);
ExpectNotNull((x509Svr =
wolfSSL_X509_load_certificate_file(svrCertFile, SSL_FILETYPE_PEM)));
ExpectIntEQ(X509_STORE_CTX_init(ctx, str, x509Svr, NULL), SSL_SUCCESS);
/* Issuer0 is not set until chain is built for verification */
ExpectNull(X509_STORE_CTX_get0_current_issuer(NULL));
ExpectNull(issuer = X509_STORE_CTX_get0_current_issuer(ctx));
/* Issuer1 will use the store to make a new issuer */
ExpectIntEQ(X509_STORE_CTX_get1_issuer(&issuer, ctx, x509Svr), 1);
ExpectNotNull(issuer);
X509_free(issuer);
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectNotNull(issuer = X509_STORE_CTX_get0_current_issuer(ctx));
ExpectNotNull(caName = X509_get_subject_name(x509Ca));
ExpectNotNull(issuerName = X509_get_subject_name(issuer));
#ifdef WOLFSSL_SIGNER_DER_CERT
ExpectIntEQ(X509_NAME_cmp(caName, issuerName), 0);
#endif
X509_STORE_CTX_free(ctx);
X509_free(x509Svr);
X509_STORE_free(str);
X509_free(x509Ca);
#endif
return EXPECT_RESULT();
}
int test_wolfSSL_X509_STORE_set_flags(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
!defined(NO_FILESYSTEM) && !defined(NO_RSA)
X509_STORE* store = NULL;
X509* x509 = NULL;
ExpectNotNull((store = wolfSSL_X509_STORE_new()));
ExpectNotNull((x509 = wolfSSL_X509_load_certificate_file(svrCertFile,
WOLFSSL_FILETYPE_PEM)));
ExpectIntEQ(X509_STORE_add_cert(store, x509), WOLFSSL_SUCCESS);
#ifdef HAVE_CRL
ExpectIntEQ(X509_STORE_set_flags(store, WOLFSSL_CRL_CHECKALL),
WOLFSSL_SUCCESS);
#else
ExpectIntEQ(X509_STORE_set_flags(store, WOLFSSL_CRL_CHECKALL),
WC_NO_ERR_TRACE(NOT_COMPILED_IN));
#endif
wolfSSL_X509_free(x509);
wolfSSL_X509_STORE_free(store);
#endif /* defined(OPENSSL_EXTRA) && !defined(NO_CERTS) &&
* !defined(NO_FILESYSTEM) && !defined(NO_RSA) */
return EXPECT_RESULT();
}
int test_wolfSSL_X509_STORE(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_TLS) && \
!defined(NO_FILESYSTEM)
X509_STORE *store = NULL;
#ifdef HAVE_CRL
X509_STORE_CTX *storeCtx = NULL;
X509 *ca = NULL;
X509 *cert = NULL;
const char srvCert[] = "./certs/server-revoked-cert.pem";
const char caCert[] = "./certs/ca-cert.pem";
#ifndef WOLFSSL_CRL_ALLOW_MISSING_CDP
X509_CRL *crl = NULL;
const char crlPem[] = "./certs/crl/crl.revoked";
XFILE fp = XBADFILE;
#endif /* !WOLFSSL_CRL_ALLOW_MISSING_CDP */
ExpectNotNull(store = (X509_STORE *)X509_STORE_new());
ExpectNotNull((ca = wolfSSL_X509_load_certificate_file(caCert,
SSL_FILETYPE_PEM)));
ExpectIntEQ(X509_STORE_add_cert(store, ca), SSL_SUCCESS);
ExpectNotNull((cert = wolfSSL_X509_load_certificate_file(srvCert,
SSL_FILETYPE_PEM)));
ExpectNotNull((storeCtx = X509_STORE_CTX_new()));
ExpectIntEQ(X509_STORE_CTX_init(storeCtx, store, cert, NULL), SSL_SUCCESS);
ExpectIntEQ(X509_verify_cert(storeCtx), SSL_SUCCESS);
X509_STORE_free(store);
store = NULL;
X509_STORE_CTX_free(storeCtx);
storeCtx = NULL;
X509_free(cert);
cert = NULL;
X509_free(ca);
ca = NULL;
#ifndef WOLFSSL_CRL_ALLOW_MISSING_CDP
/* should fail to verify now after adding in CRL */
ExpectNotNull(store = (X509_STORE *)X509_STORE_new());
ExpectNotNull((ca = wolfSSL_X509_load_certificate_file(caCert,
SSL_FILETYPE_PEM)));
ExpectIntEQ(X509_STORE_add_cert(store, ca), SSL_SUCCESS);
ExpectTrue((fp = XFOPEN(crlPem, "rb")) != XBADFILE);
ExpectNotNull(crl = (X509_CRL *)PEM_read_X509_CRL(fp, (X509_CRL **)NULL,
NULL, NULL));
if (fp != XBADFILE)
XFCLOSE(fp);
ExpectIntEQ(X509_STORE_add_crl(store, crl), SSL_SUCCESS);
ExpectIntEQ(X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK),SSL_SUCCESS);
ExpectNotNull((storeCtx = X509_STORE_CTX_new()));
ExpectNotNull((cert = wolfSSL_X509_load_certificate_file(srvCert,
SSL_FILETYPE_PEM)));
ExpectIntEQ(X509_STORE_CTX_init(storeCtx, store, cert, NULL), SSL_SUCCESS);
ExpectIntNE(X509_verify_cert(storeCtx), SSL_SUCCESS);
ExpectIntEQ(X509_STORE_CTX_get_error(storeCtx),
WOLFSSL_X509_V_ERR_CERT_REVOKED);
X509_CRL_free(crl);
crl = NULL;
X509_STORE_free(store);
store = NULL;
X509_STORE_CTX_free(storeCtx);
storeCtx = NULL;
X509_free(cert);
cert = NULL;
X509_free(ca);
ca = NULL;
#endif /* !WOLFSSL_CRL_ALLOW_MISSING_CDP */
#endif /* HAVE_CRL */
#if !defined(WOLFCRYPT_ONLY) && !defined(NO_FILESYSTEM)
{
#if !defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)
SSL_CTX* ctx = NULL;
SSL* ssl = NULL;
int i;
for (i = 0; i < 2; i++) {
#ifndef NO_WOLFSSL_SERVER
ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_server_method()));
#else
ExpectNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
#endif
ExpectNotNull(store = (X509_STORE *)X509_STORE_new());
SSL_CTX_set_cert_store(ctx, store);
ExpectNotNull(store = (X509_STORE *)X509_STORE_new());
SSL_CTX_set_cert_store(ctx, store);
ExpectNotNull(store = (X509_STORE *)X509_STORE_new());
ExpectIntEQ(SSL_CTX_use_certificate_file(ctx, svrCertFile,
SSL_FILETYPE_PEM), SSL_SUCCESS);
ExpectIntEQ(SSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
SSL_FILETYPE_PEM), SSL_SUCCESS);
ExpectNotNull(ssl = SSL_new(ctx));
if (i == 0) {
ExpectIntEQ(SSL_set0_verify_cert_store(ssl, store),
SSL_SUCCESS);
}
else {
ExpectIntEQ(SSL_set1_verify_cert_store(ssl, store),
SSL_SUCCESS);
#ifdef OPENSSL_ALL
ExpectIntEQ(SSL_CTX_set1_verify_cert_store(ctx, store),
SSL_SUCCESS);
#endif
}
if (EXPECT_FAIL() || (i == 1)) {
X509_STORE_free(store);
store = NULL;
}
SSL_free(ssl);
ssl = NULL;
SSL_CTX_free(ctx);
ctx = NULL;
}
#endif /* !NO_WOLFSSL_CLIENT || !NO_WOLFSSL_SERVER */
}
#endif
#endif
return EXPECT_RESULT();
}
int test_wolfSSL_X509_STORE_load_locations(void)
{
EXPECT_DECLS;
#if (defined(OPENSSL_ALL) || defined(WOLFSSL_APACHE_HTTPD)) && \
!defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR) && !defined(NO_RSA) && \
!defined(NO_TLS)
SSL_CTX *ctx = NULL;
X509_STORE *store = NULL;
const char ca_file[] = "./certs/ca-cert.pem";
const char client_pem_file[] = "./certs/client-cert.pem";
const char client_der_file[] = "./certs/client-cert.der";
const char ecc_file[] = "./certs/ecc-key.pem";
const char certs_path[] = "./certs/";
const char bad_path[] = "./bad-path/";
#ifdef HAVE_CRL
const char crl_path[] = "./certs/crl/";
const char crl_file[] = "./certs/crl/crl.pem";
#endif
#ifndef NO_WOLFSSL_SERVER
ExpectNotNull(ctx = SSL_CTX_new(SSLv23_server_method()));
#else
ExpectNotNull(ctx = SSL_CTX_new(SSLv23_client_method()));
#endif
ExpectNotNull(store = SSL_CTX_get_cert_store(ctx));
ExpectIntEQ(wolfSSL_CertManagerLoadCA(store->cm, ca_file, NULL),
WOLFSSL_SUCCESS);
/* Test bad arguments */
ExpectIntEQ(X509_STORE_load_locations(NULL, ca_file, NULL),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(X509_STORE_load_locations(store, NULL, NULL),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(X509_STORE_load_locations(store, client_der_file, NULL),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(X509_STORE_load_locations(store, ecc_file, NULL),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
ExpectIntEQ(X509_STORE_load_locations(store, NULL, bad_path),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#ifdef HAVE_CRL
/* Test with CRL */
ExpectIntEQ(X509_STORE_load_locations(store, crl_file, NULL),
WOLFSSL_SUCCESS);
ExpectIntEQ(X509_STORE_load_locations(store, NULL, crl_path),
WOLFSSL_SUCCESS);
#endif
/* Test with CA */
ExpectIntEQ(X509_STORE_load_locations(store, ca_file, NULL),
WOLFSSL_SUCCESS);
/* Test with client_cert and certs path */
ExpectIntEQ(X509_STORE_load_locations(store, client_pem_file, NULL),
WOLFSSL_SUCCESS);
ExpectIntEQ(X509_STORE_load_locations(store, NULL, certs_path),
WOLFSSL_SUCCESS);
#if defined(XGETENV) && !defined(NO_GETENV) && defined(_POSIX_C_SOURCE) && \
_POSIX_C_SOURCE >= 200112L
ExpectIntEQ(wolfSSL_CTX_UnloadCAs(ctx), WOLFSSL_SUCCESS);
/* Test with env vars */
ExpectIntEQ(setenv("SSL_CERT_FILE", client_pem_file, 1), 0);
ExpectIntEQ(setenv("SSL_CERT_DIR", certs_path, 1), 0);
ExpectIntEQ(X509_STORE_set_default_paths(store), WOLFSSL_SUCCESS);
#endif
#if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE)
/* Clear nodes */
ERR_clear_error();
#endif
SSL_CTX_free(ctx);
#endif
return EXPECT_RESULT();
}
int test_X509_STORE_get0_objects(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_FILESYSTEM) && !defined(NO_TLS) && \
!defined(NO_WOLFSSL_DIR) && !defined(NO_RSA)
X509_STORE *store = NULL;
X509_STORE *store_cpy = NULL;
SSL_CTX *ctx = NULL;
X509_OBJECT *obj = NULL;
#ifdef HAVE_CRL
X509_OBJECT *objCopy = NULL;
#endif
STACK_OF(X509_OBJECT) *objs = NULL;
STACK_OF(X509_OBJECT) *objsCopy = NULL;
int i;
/* Setup store */
#ifndef NO_WOLFSSL_SERVER
ExpectNotNull(ctx = SSL_CTX_new(SSLv23_server_method()));
#else
ExpectNotNull(ctx = SSL_CTX_new(SSLv23_client_method()));
#endif
ExpectNotNull(store_cpy = X509_STORE_new());
ExpectNotNull(store = SSL_CTX_get_cert_store(ctx));
ExpectIntEQ(X509_STORE_load_locations(store, cliCertFile, NULL),
WOLFSSL_SUCCESS);
ExpectIntEQ(X509_STORE_load_locations(store, caCertFile, NULL),
WOLFSSL_SUCCESS);
ExpectIntEQ(X509_STORE_load_locations(store, svrCertFile, NULL),
WOLFSSL_SUCCESS);
#ifdef HAVE_CRL
ExpectIntEQ(X509_STORE_load_locations(store, NULL, crlPemDir),
WOLFSSL_SUCCESS);
#endif
/* Store ready */
/* Similar to HaProxy ssl_set_cert_crl_file use case */
ExpectNotNull(objs = X509_STORE_get0_objects(store));
#ifdef HAVE_CRL
#ifdef WOLFSSL_SIGNER_DER_CERT
ExpectIntEQ(sk_X509_OBJECT_num(objs), 4);
#else
ExpectIntEQ(sk_X509_OBJECT_num(objs), 1);
#endif
#else
#ifdef WOLFSSL_SIGNER_DER_CERT
ExpectIntEQ(sk_X509_OBJECT_num(objs), 3);
#else
ExpectIntEQ(sk_X509_OBJECT_num(objs), 0);
#endif
#endif
ExpectIntEQ(sk_X509_OBJECT_num(NULL), 0);
ExpectNull(sk_X509_OBJECT_value(NULL, 0));
ExpectNull(sk_X509_OBJECT_value(NULL, 1));
ExpectNull(sk_X509_OBJECT_value(objs, sk_X509_OBJECT_num(objs)));
ExpectNull(sk_X509_OBJECT_value(objs, sk_X509_OBJECT_num(objs) + 1));
#ifndef NO_WOLFSSL_STUB
ExpectNull(sk_X509_OBJECT_delete(objs, 0));
#endif
ExpectNotNull(objsCopy = sk_X509_OBJECT_deep_copy(objs, NULL, NULL));
ExpectIntEQ(sk_X509_OBJECT_num(objs), sk_X509_OBJECT_num(objsCopy));
for (i = 0; i < sk_X509_OBJECT_num(objs) && EXPECT_SUCCESS(); i++) {
obj = (X509_OBJECT*)sk_X509_OBJECT_value(objs, i);
#ifdef HAVE_CRL
objCopy = (X509_OBJECT*)sk_X509_OBJECT_value(objsCopy, i);
#endif
switch (X509_OBJECT_get_type(obj)) {
case X509_LU_X509:
{
X509* x509 = NULL;
X509_NAME *subj_name = NULL;
ExpectNull(X509_OBJECT_get0_X509_CRL(NULL));
ExpectNull(X509_OBJECT_get0_X509_CRL(obj));
ExpectNotNull(x509 = X509_OBJECT_get0_X509(obj));
ExpectIntEQ(X509_STORE_add_cert(store_cpy, x509), WOLFSSL_SUCCESS);
ExpectNotNull(subj_name = X509_get_subject_name(x509));
ExpectPtrEq(obj, X509_OBJECT_retrieve_by_subject(objs, X509_LU_X509,
subj_name));
break;
}
case X509_LU_CRL:
#ifdef HAVE_CRL
{
X509_CRL* crl = NULL;
ExpectNull(X509_OBJECT_get0_X509(NULL));
ExpectNull(X509_OBJECT_get0_X509(obj));
ExpectNotNull(crl = X509_OBJECT_get0_X509_CRL(obj));
ExpectIntEQ(X509_STORE_add_crl(store_cpy, crl), WOLFSSL_SUCCESS);
ExpectNotNull(crl = X509_OBJECT_get0_X509_CRL(objCopy));
break;
}
#endif
case X509_LU_NONE:
default:
Fail(("X509_OBJECT_get_type should return x509 or crl "
"(when built with crl support)"),
("Unrecognized X509_OBJECT type or none"));
}
}
X509_STORE_free(store_cpy);
SSL_CTX_free(ctx);
wolfSSL_sk_X509_OBJECT_free(NULL);
objs = NULL;
wolfSSL_sk_pop_free(objsCopy, NULL);
objsCopy = NULL;
ExpectNotNull(objs = wolfSSL_sk_X509_OBJECT_new());
ExpectIntEQ(wolfSSL_sk_X509_OBJECT_push(NULL, NULL), WOLFSSL_FAILURE);
ExpectIntEQ(wolfSSL_sk_X509_OBJECT_push(objs, NULL), WOLFSSL_FAILURE);
ExpectIntEQ(wolfSSL_sk_X509_OBJECT_push(NULL, obj), WOLFSSL_FAILURE);
ExpectNotNull(objsCopy = sk_X509_OBJECT_deep_copy(objs, NULL, NULL));
wolfSSL_sk_X509_OBJECT_free(objsCopy);
wolfSSL_sk_X509_OBJECT_free(objs);
#endif
return EXPECT_RESULT();
}
int test_wolfSSL_X509_STORE_get1_certs(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_SIGNER_DER_CERT) && \
!defined(NO_FILESYSTEM) && !defined(NO_RSA)
X509_STORE_CTX *storeCtx = NULL;
X509_STORE *store = NULL;
X509 *caX509 = NULL;
X509 *svrX509 = NULL;
X509_NAME *subject = NULL;
WOLF_STACK_OF(WOLFSSL_X509) *certs = NULL;
ExpectNotNull(caX509 = X509_load_certificate_file(caCertFile,
SSL_FILETYPE_PEM));
ExpectNotNull((svrX509 = wolfSSL_X509_load_certificate_file(svrCertFile,
SSL_FILETYPE_PEM)));
ExpectNotNull(storeCtx = X509_STORE_CTX_new());
ExpectNotNull(store = X509_STORE_new());
ExpectNotNull(subject = X509_get_subject_name(caX509));
/* Errors */
ExpectNull(X509_STORE_get1_certs(storeCtx, subject));
ExpectNull(X509_STORE_get1_certs(NULL, subject));
ExpectNull(X509_STORE_get1_certs(storeCtx, NULL));
ExpectIntEQ(X509_STORE_add_cert(store, caX509), SSL_SUCCESS);
ExpectIntEQ(X509_STORE_CTX_init(storeCtx, store, caX509, NULL),
SSL_SUCCESS);
/* Should find the cert */
ExpectNotNull(certs = X509_STORE_get1_certs(storeCtx, subject));
ExpectIntEQ(1, wolfSSL_sk_X509_num(certs));
sk_X509_pop_free(certs, NULL);
certs = NULL;
/* Should not find the cert */
ExpectNotNull(subject = X509_get_subject_name(svrX509));
ExpectNotNull(certs = X509_STORE_get1_certs(storeCtx, subject));
ExpectIntEQ(0, wolfSSL_sk_X509_num(certs));
sk_X509_pop_free(certs, NULL);
certs = NULL;
X509_STORE_free(store);
X509_STORE_CTX_free(storeCtx);
X509_free(svrX509);
X509_free(caX509);
#endif /* OPENSSL_EXTRA && WOLFSSL_SIGNER_DER_CERT && !NO_FILESYSTEM */
return EXPECT_RESULT();
}
#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_LOCAL_X509_STORE) && \
(defined(OPENSSL_ALL) || defined(WOLFSSL_QT)) && defined(HAVE_CRL)
static int test_wolfSSL_X509_STORE_set_get_crl_provider(X509_STORE_CTX* ctx,
X509_CRL** crl_out, X509* cert) {
X509_CRL *crl = NULL;
XFILE fp = XBADFILE;
char* cert_issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
int ret = 0;
(void)ctx;
if (cert_issuer == NULL)
return 0;
if ((fp = XFOPEN("certs/crl/crl.pem", "rb")) != XBADFILE) {
PEM_read_X509_CRL(fp, &crl, NULL, NULL);
XFCLOSE(fp);
if (crl != NULL) {
char* crl_issuer = X509_NAME_oneline(
X509_CRL_get_issuer(crl), NULL, 0);
if ((crl_issuer != NULL) &&
(XSTRCMP(cert_issuer, crl_issuer) == 0)) {
*crl_out = X509_CRL_dup(crl);
if (*crl_out != NULL)
ret = 1;
}
OPENSSL_free(crl_issuer);
}
}
X509_CRL_free(crl);
OPENSSL_free(cert_issuer);
return ret;
}
static int test_wolfSSL_X509_STORE_set_get_crl_provider2(X509_STORE_CTX* ctx,
X509_CRL** crl_out, X509* cert) {
(void)ctx;
(void)cert;
*crl_out = NULL;
return 1;
}
#ifndef NO_WOLFSSL_STUB
static int test_wolfSSL_X509_STORE_set_get_crl_check(X509_STORE_CTX* ctx,
X509_CRL* crl) {
(void)ctx;
(void)crl;
return 1;
}
#endif
static int test_wolfSSL_X509_STORE_set_get_crl_verify(int ok,
X509_STORE_CTX* ctx) {
int cert_error = X509_STORE_CTX_get_error(ctx);
X509_VERIFY_PARAM* param = X509_STORE_CTX_get0_param(ctx);
int flags = X509_VERIFY_PARAM_get_flags(param);
if ((flags & (X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL)) !=
(X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL)) {
/* Make sure the flags are set */
return 0;
}
/* Ignore CRL missing error */
#ifndef OPENSSL_COMPATIBLE_DEFAULTS
if (cert_error == WC_NO_ERR_TRACE(CRL_MISSING))
#else
if (cert_error == X509_V_ERR_UNABLE_TO_GET_CRL)
#endif
return 1;
return ok;
}
static int test_wolfSSL_X509_STORE_set_get_crl_ctx_ready(WOLFSSL_CTX* ctx)
{
EXPECT_DECLS;
X509_STORE* cert_store = NULL;
ExpectIntEQ(wolfSSL_CTX_EnableCRL(ctx, WOLFSSL_CRL_CHECKALL),
WOLFSSL_SUCCESS);
ExpectNotNull(cert_store = SSL_CTX_get_cert_store(ctx));
X509_STORE_set_get_crl(cert_store,
test_wolfSSL_X509_STORE_set_get_crl_provider);
#ifndef NO_WOLFSSL_STUB
X509_STORE_set_check_crl(cert_store,
test_wolfSSL_X509_STORE_set_get_crl_check);
#endif
return EXPECT_RESULT();
}
static int test_wolfSSL_X509_STORE_set_get_crl_ctx_ready2(WOLFSSL_CTX* ctx)
{
EXPECT_DECLS;
X509_STORE* cert_store = NULL;
X509_VERIFY_PARAM* param = NULL;
SSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, NULL);
ExpectIntEQ(wolfSSL_CTX_EnableCRL(ctx, WOLFSSL_CRL_CHECKALL),
WOLFSSL_SUCCESS);
ExpectNotNull(cert_store = SSL_CTX_get_cert_store(ctx));
X509_STORE_set_get_crl(cert_store,
test_wolfSSL_X509_STORE_set_get_crl_provider2);
#ifndef NO_WOLFSSL_STUB
X509_STORE_set_check_crl(cert_store,
test_wolfSSL_X509_STORE_set_get_crl_check);
#endif
X509_STORE_set_verify_cb(cert_store,
test_wolfSSL_X509_STORE_set_get_crl_verify);
ExpectNotNull(X509_STORE_get0_param(cert_store));
ExpectNotNull(param = X509_VERIFY_PARAM_new());
ExpectIntEQ(X509_VERIFY_PARAM_inherit(NULL, NULL) , WOLFSSL_SUCCESS);
ExpectIntEQ(X509_VERIFY_PARAM_inherit(param, NULL) , WOLFSSL_SUCCESS);
ExpectIntEQ(X509_VERIFY_PARAM_inherit(param,
X509_STORE_get0_param(cert_store)), WOLFSSL_SUCCESS);
ExpectIntEQ(X509_VERIFY_PARAM_inherit(param,
X509_STORE_get0_param(cert_store)), 1);
ExpectIntEQ(X509_VERIFY_PARAM_set_flags(
param, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL), 1);
ExpectIntEQ(X509_STORE_set1_param(cert_store, param), 1);
ExpectIntEQ(X509_STORE_set_flags(cert_store,
X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL), 1);
X509_VERIFY_PARAM_free(param);
return EXPECT_RESULT();
}
#endif
/* This test mimics the usage of the CRL provider in gRPC */
int test_wolfSSL_X509_STORE_set_get_crl(void)
{
EXPECT_DECLS;
#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_LOCAL_X509_STORE) && \
(defined(OPENSSL_ALL) || defined(WOLFSSL_QT)) && defined(HAVE_CRL)
test_ssl_cbf func_cb_client;
test_ssl_cbf func_cb_server;
XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));
func_cb_client.ctx_ready = test_wolfSSL_X509_STORE_set_get_crl_ctx_ready;
ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
&func_cb_server, NULL), TEST_SUCCESS);
XMEMSET(&func_cb_client, 0, sizeof(func_cb_client));
XMEMSET(&func_cb_server, 0, sizeof(func_cb_server));
func_cb_client.ctx_ready = test_wolfSSL_X509_STORE_set_get_crl_ctx_ready2;
ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&func_cb_client,
&func_cb_server, NULL), TEST_SUCCESS);
#endif
return EXPECT_RESULT();
}
int test_wolfSSL_X509_CA_num(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_FILESYSTEM) && \
defined(HAVE_ECC) && !defined(NO_RSA)
WOLFSSL_X509_STORE *store = NULL;
WOLFSSL_X509 *x509_1 = NULL;
WOLFSSL_X509 *x509_2 = NULL;
int ca_num = 0;
ExpectNotNull(store = wolfSSL_X509_STORE_new());
ExpectNotNull(x509_1 = wolfSSL_X509_load_certificate_file(svrCertFile,
WOLFSSL_FILETYPE_PEM));
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, x509_1), 1);
ExpectIntEQ(ca_num = wolfSSL_X509_CA_num(store), 1);
ExpectNotNull(x509_2 = wolfSSL_X509_load_certificate_file(eccCertFile,
WOLFSSL_FILETYPE_PEM));
ExpectIntEQ(wolfSSL_X509_STORE_add_cert(store, x509_2), 1);
ExpectIntEQ(ca_num = wolfSSL_X509_CA_num(store), 2);
wolfSSL_X509_free(x509_1);
wolfSSL_X509_free(x509_2);
wolfSSL_X509_STORE_free(store);
#endif
return EXPECT_RESULT();
}
/* Test of X509 store use outside of SSL context w/ CRL lookup (ALWAYS
* returns 0) */
int test_X509_STORE_No_SSL_CTX(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_ALL) && defined(WOLFSSL_CERT_GEN) && \
(defined(WOLFSSL_CERT_REQ) || defined(WOLFSSL_CERT_EXT)) && \
!defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR) && \
(defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) && \
defined(HAVE_CRL) && !defined(NO_RSA)
X509_STORE * store = NULL;
X509_STORE_CTX * storeCtx = NULL;
X509_CRL * crl = NULL;
X509 * ca = NULL;
X509 * cert = NULL;
const char cliCrlPem[] = "./certs/crl/cliCrl.pem";
const char srvCert[] = "./certs/server-cert.pem";
const char caCert[] = "./certs/ca-cert.pem";
const char caDir[] = "./certs/crl/hash_pem";
XFILE fp = XBADFILE;
X509_LOOKUP * lookup = NULL;
ExpectNotNull(store = (X509_STORE *)X509_STORE_new());
/* Set up store with CA */
ExpectNotNull((ca = wolfSSL_X509_load_certificate_file(caCert,
SSL_FILETYPE_PEM)));
ExpectIntEQ(X509_STORE_add_cert(store, ca), SSL_SUCCESS);
/* Add CRL lookup directory to store
* NOTE: test uses ./certs/crl/hash_pem/0fdb2da4.r0, which is a copy
* of crl.pem */
ExpectNotNull((lookup = X509_STORE_add_lookup(store,
X509_LOOKUP_hash_dir())));
ExpectIntEQ(X509_LOOKUP_ctrl(lookup, X509_L_ADD_DIR, caDir,
X509_FILETYPE_PEM, NULL), SSL_SUCCESS);
ExpectIntEQ(X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK),
SSL_SUCCESS);
/* Add CRL to store NOT containing the verified certificate, which
* forces use of the CRL lookup directory */
ExpectTrue((fp = XFOPEN(cliCrlPem, "rb")) != XBADFILE);
ExpectNotNull(crl = (X509_CRL *)PEM_read_X509_CRL(fp, (X509_CRL **)NULL,
NULL, NULL));
if (fp != XBADFILE)
XFCLOSE(fp);
ExpectIntEQ(X509_STORE_add_crl(store, crl), SSL_SUCCESS);
/* Create verification context outside of an SSL session */
ExpectNotNull((storeCtx = X509_STORE_CTX_new()));
ExpectNotNull((cert = wolfSSL_X509_load_certificate_file(srvCert,
SSL_FILETYPE_PEM)));
ExpectIntEQ(X509_STORE_CTX_init(storeCtx, store, cert, NULL), SSL_SUCCESS);
/* Perform verification, which should NOT indicate CRL missing due to the
* store CM's X509 store pointer being NULL */
ExpectIntNE(X509_verify_cert(storeCtx), WC_NO_ERR_TRACE(CRL_MISSING));
X509_CRL_free(crl);
X509_STORE_free(store);
X509_STORE_CTX_free(storeCtx);
X509_free(cert);
X509_free(ca);
#endif
return EXPECT_RESULT();
}
/* Test that SSL_CTX_set_cert_store propagates certificates (including
* non-self-signed intermediates) into the CertManager, and that certs
* added to the store after set_cert_store also reach the CertManager.
* Regression test for ZD 19760 / GitHub PR #8708.
*/
int test_wolfSSL_CTX_set_cert_store(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS)
SSL_CTX* ctx = NULL;
X509_STORE* store = NULL;
X509* rootCa = NULL;
X509* intCa = NULL;
X509* int2Ca = NULL;
X509_STORE_CTX* storeCtx = NULL;
X509* svrCert = NULL;
const char caCert[] = "./certs/ca-cert.pem";
const char intCaCert[] = "./certs/intermediate/ca-int-cert.pem";
const char int2CaCert[] = "./certs/intermediate/ca-int2-cert.pem";
const char svrIntCert[] = "./certs/intermediate/server-int-cert.pem";
/* --- Part 1: Add certs to store BEFORE set_cert_store ---
* Non-self-signed intermediates should be pushed into the CertManager
* when set_cert_store is called. */
ExpectNotNull(store = X509_STORE_new());
ExpectNotNull(rootCa = wolfSSL_X509_load_certificate_file(caCert,
SSL_FILETYPE_PEM));
ExpectNotNull(intCa = wolfSSL_X509_load_certificate_file(intCaCert,
SSL_FILETYPE_PEM));
ExpectNotNull(int2Ca = wolfSSL_X509_load_certificate_file(int2CaCert,
SSL_FILETYPE_PEM));
ExpectIntEQ(X509_STORE_add_cert(store, rootCa), SSL_SUCCESS);
ExpectIntEQ(X509_STORE_add_cert(store, intCa), SSL_SUCCESS);
ExpectIntEQ(X509_STORE_add_cert(store, int2Ca), SSL_SUCCESS);
ExpectNotNull(ctx = SSL_CTX_new(TLS_client_method()));
/* This should push intermediates from store->certs into the CM */
SSL_CTX_set_cert_store(ctx, store);
if (SSL_CTX_get_cert_store(ctx) != store) {
X509_STORE_free(store);
store = NULL;
}
/* After set_cert_store, store->certs and store->trusted should be NULLed
* to signal CTX ownership */
if ((store != NULL) && EXPECT_SUCCESS()) {
ExpectNull(store->certs);
ExpectNull(store->trusted);
}
/* Verify using CertManagerVerify - this only checks the CM, not the
* store's certs stack, so it proves the intermediates were pushed */
ExpectIntEQ(wolfSSL_CertManagerVerify(wolfSSL_CTX_GetCertManager(ctx),
svrIntCert, SSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
/* Also verify using X509_verify_cert for completeness */
ExpectNotNull(svrCert = wolfSSL_X509_load_certificate_file(svrIntCert,
SSL_FILETYPE_PEM));
ExpectNotNull(storeCtx = X509_STORE_CTX_new());
if (EXPECT_SUCCESS()) {
ExpectIntEQ(X509_STORE_CTX_init(storeCtx,
SSL_CTX_get_cert_store(ctx), svrCert, NULL), SSL_SUCCESS);
ExpectIntEQ(X509_verify_cert(storeCtx), SSL_SUCCESS);
}
X509_STORE_CTX_free(storeCtx);
storeCtx = NULL;
X509_free(svrCert);
svrCert = NULL;
SSL_CTX_free(ctx);
ctx = NULL;
/* store is freed by SSL_CTX_free */
store = NULL;
X509_free(rootCa);
rootCa = NULL;
X509_free(intCa);
intCa = NULL;
X509_free(int2Ca);
int2Ca = NULL;
/* --- Part 2: Add certs to store AFTER set_cert_store ---
* When store->certs is NULL (CTX-owned), X509_STORE_add_cert should
* route non-self-signed certs directly to the CertManager. */
ExpectNotNull(store = X509_STORE_new());
ExpectNotNull(ctx = SSL_CTX_new(TLS_client_method()));
/* Attach empty store first */
SSL_CTX_set_cert_store(ctx, store);
if (!EXPECT_SUCCESS()) {
X509_STORE_free(store);
}
/* Now add certs after ownership transfer */
ExpectNotNull(rootCa = wolfSSL_X509_load_certificate_file(caCert,
SSL_FILETYPE_PEM));
ExpectNotNull(intCa = wolfSSL_X509_load_certificate_file(intCaCert,
SSL_FILETYPE_PEM));
ExpectNotNull(int2Ca = wolfSSL_X509_load_certificate_file(int2CaCert,
SSL_FILETYPE_PEM));
ExpectIntEQ(X509_STORE_add_cert(store, rootCa), SSL_SUCCESS);
ExpectIntEQ(X509_STORE_add_cert(store, intCa), SSL_SUCCESS);
ExpectIntEQ(X509_STORE_add_cert(store, int2Ca), SSL_SUCCESS);
/* Verify that certs added after set_cert_store are in the CM */
ExpectIntEQ(wolfSSL_CertManagerVerify(wolfSSL_CTX_GetCertManager(ctx),
svrIntCert, SSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
SSL_CTX_free(ctx);
/* store freed by SSL_CTX_free */
X509_free(rootCa);
X509_free(intCa);
X509_free(int2Ca);
#endif
return EXPECT_RESULT();
}