Add a function to load system CA certs into a WOLFSSL_CTX.

This new function, wolfSSL_CTX_load_system_CA_certs, currently only supports
Linux-based OS's. It searches through conventional CA directories and once it
finds one, attempts to load CA certs from it. After the first directory is
found, we don't check the others.

This commit also adds a function wolfSSL_get_system_CA_dirs, which returns a
pointer to an array of directories where wolfSSL_CTX_load_system_CA_certs will
look for CA certs. This is used in a unit test, where we only want to expect
success if one of these directories actually exists on the test system.

Finally, this commit adds support for SSL_CTX_set_default_verify_paths to the
compatibility layer. It doesn't model the exact behavior of its OpenSSL
counterpart; it's mostly a wrapper around wolfSSL_CTX_load_system_CA_certs,
manipulating the return value of that function to conform to OpenSSL's
conventions.
This commit is contained in:
Hayden Roche
2022-09-22 15:18:15 -07:00
parent 9d9fa0132e
commit 8cae05348c
5 changed files with 250 additions and 6 deletions

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
@@ -15961,15 +16035,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)