Merge pull request #5626 from haydenroche5/load_system_root_certs

Add a function to load system CA certs into a WOLFSSL_CTX.
This commit is contained in:
David Garske
2022-09-29 11:03:26 -07:00
committed by GitHub
5 changed files with 250 additions and 6 deletions

View File

@ -1231,6 +1231,69 @@ int wolfSSL_CTX_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
int wolfSSL_CTX_load_verify_locations_ex(WOLFSSL_CTX* ctx, const char* file,
const char* path, unsigned int flags);
/*!
\ingroup CertsKeys
\brief This function returns a pointer to an array of strings representing
directories wolfSSL will search for system CA certs when
wolfSSL_CTX_load_system_CA_certs is called.
\return Valid pointer on success.
\return NULL pointer on failure.
\param num pointer to a word32 that will be populated with the length of the
array of strings.
_Example_
\code
WOLFSSL_CTX* ctx;
const char** dirs;
word32 numDirs;
dirs = wolfSSL_get_system_CA_dirs(&numDirs);
for (int i = 0; i < numDirs; ++i) {
printf("Potential system CA dir: %s\n", dirs[i]);
}
...
\endcode
\sa wolfSSL_CTX_load_system_CA_certs
\sa wolfSSL_CTX_load_verify_locations
\sa wolfSSL_CTX_load_verify_locations_ex
*/
const char** wolfSSL_get_system_CA_dirs(word32* num);
/*!
\ingroup CertsKeys
\brief This function attempts to load CA certificates into a WOLFSSL_CTX
from conventional CA cert directories, which is OS-dependent.
\return WOLFSSL_SUCCESS on success.
\return WOLFSSL_BAD_PATH if no system CA certs were loaded.
\return WOLFSSL_NOT_IMPLEMENTED if the function isn't supported for the
target OS.
\param ctx pointer to the SSL context, created with wolfSSL_CTX_new().
_Example_
\code
int ret = 0;
WOLFSSL_CTX* ctx;
...
ret = wolfSSL_CTX_load_system_CA_certs(ctx,);
if (ret != WOLFSSL_SUCCESS) {
// error loading system CA certs
}
...
\endcode
\sa wolfSSL_get_system_CA_dirs
\sa wolfSSL_CTX_load_verify_locations
\sa wolfSSL_CTX_load_verify_locations_ex
*/
int wolfSSL_CTX_load_system_CA_certs(WOLFSSL_CTX* ctx);
/*!
\ingroup Setup

113
src/ssl.c
View File

@ -8041,6 +8041,80 @@ int wolfSSL_CTX_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
return WS_RETURN_CODE(ret,WOLFSSL_FAILURE);
}
#ifndef _WIN32
/* Potential system CA certs directories on Linux distros. */
static const char* systemCaDirs[] = {
"/etc/ssl/certs", /* Debian, Ubuntu, Gentoo, others */
"/etc/pki/ca-trust/source/anchors", /* Fedora, RHEL */
"/etc/pki/tls/certs" /* Older RHEL */
};
const char** wolfSSL_get_system_CA_dirs(word32* num)
{
const char** ret;
if (num == NULL) {
ret = NULL;
}
else {
ret = systemCaDirs;
*num = sizeof(systemCaDirs)/sizeof(*systemCaDirs);
}
return ret;
}
#endif /* !_WIN32 */
int wolfSSL_CTX_load_system_CA_certs(WOLFSSL_CTX* ctx)
{
int ret;
#ifndef _WIN32
word32 i;
byte loaded = 0;
#endif
WOLFSSL_ENTER("wolfSSL_CTX_load_system_CA_certs");
#ifdef _WIN32
(void)ctx;
ret = WOLFSSL_NOT_IMPLEMENTED;
#else
if (ctx != NULL) {
for (i = 0; i < sizeof(systemCaDirs)/sizeof(*systemCaDirs); ++i) {
WOLFSSL_MSG_EX("Attempting to load system CA certs from %s.",
systemCaDirs[i]);
/*
* We want to keep trying to load more CAs even if one cert in
* the directory is bad and can't be used (e.g. if one is expired),
* so we use WOLFSSL_LOAD_FLAG_IGNORE_ERR.
*/
if (wolfSSL_CTX_load_verify_locations_ex(ctx, NULL, systemCaDirs[i],
WOLFSSL_LOAD_FLAG_IGNORE_ERR) != WOLFSSL_SUCCESS) {
WOLFSSL_MSG_EX("Failed to load CA certs from %s, trying "
"next possible location.", systemCaDirs[i]);
}
else {
WOLFSSL_MSG_EX("Loaded CA certs from %s.",
systemCaDirs[i]);
loaded = 1;
/* Stop searching after we've loaded one directory. */
break;
}
}
}
if (loaded) {
ret = WOLFSSL_SUCCESS;
}
else {
ret = WOLFSSL_BAD_PATH;
}
#endif
WOLFSSL_LEAVE("wolfSSL_CTX_load_system_CA_certs", ret);
return ret;
}
#ifdef WOLFSSL_TRUST_PEER_CERT
/* Used to specify a peer cert to match when connecting
@ -16152,15 +16226,42 @@ cleanup:
#ifdef OPENSSL_EXTRA
#ifndef NO_WOLFSSL_STUB
#ifndef NO_FILESYSTEM
/*
* This is an OpenSSL compatibility layer function, but it doesn't mirror
* the exact functionality of its OpenSSL counterpart. We don't support the
* notion of an "OpenSSL directory," nor do we support the environment
* variables SSL_CERT_DIR or SSL_CERT_FILE. This function is simply a
* wrapper around our native wolfSSL_CTX_load_system_CA_certs function. This
* function does conform to OpenSSL's return value conventions, though.
*/
int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx)
{
/* TODO:, not needed in goahead */
(void)ctx;
WOLFSSL_STUB("SSL_CTX_set_default_verify_paths");
return SSL_NOT_IMPLEMENTED;
int ret;
WOLFSSL_ENTER("wolfSSL_CTX_set_default_verify_paths");
ret = wolfSSL_CTX_load_system_CA_certs(ctx);
if (ret == WOLFSSL_BAD_PATH) {
/*
* OpenSSL doesn't treat the lack of a system CA cert directory as a
* failure. We do the same here.
*/
ret = WOLFSSL_SUCCESS;
}
else if (ret != WOLFSSL_SUCCESS) {
/*
* All other failure types map to WOLFSSL_FAILURE (0), same as
* OpenSSL.
*/
ret = WOLFSSL_FAILURE;
}
WOLFSSL_LEAVE("wolfSSL_CTX_set_default_verify_paths", ret);
return ret;
}
#endif
#endif /* !NO_FILESYSTEM */
#if defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256) \
&& !defined(WC_NO_RNG)

View File

@ -1346,6 +1346,77 @@ static int test_wolfSSL_CTX_load_verify_locations(void)
return 0;
}
static int test_wolfSSL_CTX_load_system_CA_certs(void)
{
int ret = 0;
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_WOLFSSL_CLIENT)
WOLFSSL_CTX* ctx;
ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
if (ctx == NULL) {
ret = -1;
}
if (ret == 0) {
#ifdef _WIN32
if (wolfSSL_CTX_load_system_CA_certs(ctx) != WOLFSSL_NOT_IMPLEMENTED) {
ret = -1;
}
#ifdef OPENSSL_EXTRA
if (wolfSSL_CTX_set_default_verify_paths(ctx) != WOLFSSL_FAILURE) {
ret = -1;
}
#endif /* OPENSSL_EXTRA */
#else
word32 numDirs;
const char** caDirs = wolfSSL_get_system_CA_dirs(&numDirs);
if (caDirs == NULL || numDirs == 0) {
ret = -1;
}
else {
ReadDirCtx dirCtx;
byte dirValid = 0;
word32 i;
for (i = 0; i < numDirs; ++i) {
if (wc_ReadDirFirst(&dirCtx, caDirs[i], NULL) == 0) {
/* Directory isn't empty. */
dirValid = 1;
wc_ReadDirClose(&dirCtx);
break;
}
}
/*
* If the directory isn't empty, we should be able to load CA
* certs from it.
*/
if (dirValid && wolfSSL_CTX_load_system_CA_certs(ctx) !=
WOLFSSL_SUCCESS) {
ret = -1;
}
#ifdef OPENSSL_EXTRA
/*
* Even if we don't have a valid directory to load system CA
* certs from, the OpenSSL compat layer function should return
* success.
*/
if (wolfSSL_CTX_set_default_verify_paths(ctx)
!= WOLFSSL_SUCCESS) {
ret = -1;
}
#endif /* OPENSSL_EXTRA */
}
#endif /* _WIN32 */
}
wolfSSL_CTX_free(ctx);
#endif /* !NO_FILESYSTEM && !NO_CERTS && !NO_WOLFSSL_CLIENT */
return ret;
}
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS)
static int test_cm_load_ca_buffer(const byte* cert_buf, size_t cert_sz, int file_type)
{
@ -59130,6 +59201,7 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wolfSSL_CTX_use_certificate_buffer),
TEST_DECL(test_wolfSSL_CTX_use_PrivateKey_file),
TEST_DECL(test_wolfSSL_CTX_load_verify_locations),
TEST_DECL(test_wolfSSL_CTX_load_system_CA_certs),
TEST_DECL(test_wolfSSL_CertManagerCheckOCSPResponse),
TEST_DECL(test_wolfSSL_CheckOCSPResponse),
TEST_DECL(test_wolfSSL_CertManagerLoadCABuffer),

View File

@ -267,6 +267,7 @@ typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS;
#else
#define SSL_CTX_load_verify_locations wolfSSL_CTX_load_verify_locations
#endif
#define SSL_CTX_set_default_verify_paths wolfSSL_CTX_set_default_verify_paths
#define SSL_CTX_use_certificate_chain_file wolfSSL_CTX_use_certificate_chain_file
#define SSL_CTX_use_RSAPrivateKey_file wolfSSL_CTX_use_RSAPrivateKey_file

View File

@ -1075,6 +1075,13 @@ WOLFSSL_API int wolfSSL_CTX_load_verify_locations_ex(
WOLFSSL_CTX* ctx, const char* file, const char* path, word32 flags);
WOLFSSL_ABI WOLFSSL_API int wolfSSL_CTX_load_verify_locations(
WOLFSSL_CTX* ctx, const char* file, const char* path);
#ifndef _WIN32
WOLFSSL_API const char** wolfSSL_get_system_CA_dirs(word32* num);
#endif /* !_WIN32 */
WOLFSSL_API int wolfSSL_CTX_load_system_CA_certs(WOLFSSL_CTX* ctx);
#ifdef OPENSSL_EXTRA
WOLFSSL_API int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx);
#endif /* OPENSSL_EXTRA */
#ifdef WOLFSSL_TRUST_PEER_CERT
WOLFSSL_API int wolfSSL_CTX_trust_peer_cert(
WOLFSSL_CTX* ctx, const char* file, int type);