Add support for wolfSSL_CTX_load_system_CA_certs on Windows and Mac.

Additionally, fix CMake build to add WOLFSSL_X86_64_BUILD when building for
x86_64.
This commit is contained in:
Hayden Roche
2022-10-03 07:40:10 -07:00
committed by Hayden Roche
parent cb5828235b
commit b50a786cb2
5 changed files with 218 additions and 81 deletions

View File

@@ -66,6 +66,18 @@ if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>") set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
endif() endif()
if(APPLE)
find_library(CORE_FOUNDATION_FRAMEWORK CoreFoundation)
if(NOT CORE_FOUNDATION_FRAMEWORK)
message(FATAL_ERROR "Couldn't find CoreFoundation framework.")
endif()
find_library(SECURITY_FRAMEWORK Security)
if(NOT SECURITY_FRAMEWORK)
message(FATAL_ERROR "Couldn't find Security framework.")
endif()
endif()
include(CheckIncludeFile) include(CheckIncludeFile)
check_include_file("arpa/inet.h" HAVE_ARPA_INET_H) check_include_file("arpa/inet.h" HAVE_ARPA_INET_H)
@@ -1526,6 +1538,10 @@ endif()
# TODO: - Fast huge math # TODO: - Fast huge math
if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64")
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_X86_64_BUILD")
endif()
# SP math all # SP math all
add_option("WOLFSSL_SP_MATH_ALL" add_option("WOLFSSL_SP_MATH_ALL"
"Enable Single Precision math implementation for full algorithm suite (default: enabled)" "Enable Single Precision math implementation for full algorithm suite (default: enabled)"
@@ -1900,6 +1916,10 @@ if(WIN32)
# For Windows link ws2_32 # For Windows link ws2_32
target_link_libraries(wolfssl PUBLIC target_link_libraries(wolfssl PUBLIC
$<$<PLATFORM_ID:Windows>:ws2_32>) $<$<PLATFORM_ID:Windows>:ws2_32>)
elseif(APPLE)
target_link_libraries(wolfssl PUBLIC
${CORE_FOUNDATION_FRAMEWORK}
${SECURITY_FRAMEWORK})
else() else()
# DH requires math (m) library # DH requires math (m) library
target_link_libraries(wolfssl target_link_libraries(wolfssl

View File

@@ -940,7 +940,6 @@ then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_ISSUER_NAMES" AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_ISSUER_NAMES"
fi fi
# liboqs # liboqs
ENABLED_LIBOQS="no" ENABLED_LIBOQS="no"
tryliboqsdir="" tryliboqsdir=""
@@ -7985,13 +7984,12 @@ then
AM_CFLAGS="$AM_CFLAGS -DHAVE___UINT128_T=1" AM_CFLAGS="$AM_CFLAGS -DHAVE___UINT128_T=1"
fi fi
LIB_SOCKET_NSL LIB_SOCKET_NSL
AX_HARDEN_CC_COMPILER_FLAGS AX_HARDEN_CC_COMPILER_FLAGS
# if mingw then link to ws2_32 for sockets
case $host_os in case $host_os in
mingw*) mingw*)
# if mingw then link to ws2_32 for sockets
LDFLAGS="$LDFLAGS -lws2_32" LDFLAGS="$LDFLAGS -lws2_32"
if test "$enable_shared" = "yes" if test "$enable_shared" = "yes"
then then
@@ -8001,6 +7999,10 @@ case $host_os in
MINGW_LIB_WARNING="yes" MINGW_LIB_WARNING="yes"
fi fi
fi ;; fi ;;
*darwin*)
# For Mac we need these frameworks to load system CA certs
LDFLAGS="$LDFLAGS -framework CoreFoundation -framework Security"
;;
esac esac
if test "$enable_shared" = "no"; then if test "$enable_shared" = "no"; then

View File

@@ -1267,12 +1267,13 @@ const char** wolfSSL_get_system_CA_dirs(word32* num);
\ingroup CertsKeys \ingroup CertsKeys
\brief This function attempts to load CA certificates into a WOLFSSL_CTX \brief This function attempts to load CA certificates into a WOLFSSL_CTX
from conventional CA cert directories, which is OS-dependent. from an OS-dependent CA certificate store. Loaded certificates will be
trusted.
\return WOLFSSL_SUCCESS on success. \return WOLFSSL_SUCCESS on success.
\return WOLFSSL_BAD_PATH if no system CA certs were loaded. \return WOLFSSL_BAD_PATH if no system CA certs were loaded.
\return WOLFSSL_NOT_IMPLEMENTED if the function isn't supported for the \return WOLFSSL_FAILURE for other failure types (e.g. Windows cert store
target OS. wasn't properly closed).
\param ctx pointer to the SSL context, created with wolfSSL_CTX_new(). \param ctx pointer to the SSL context, created with wolfSSL_CTX_new().

178
src/ssl.c
View File

@@ -162,6 +162,15 @@
#endif #endif
#endif /* !WOLFCRYPT_ONLY || OPENSSL_EXTRA */ #endif /* !WOLFCRYPT_ONLY || OPENSSL_EXTRA */
#ifdef _WIN32
#include <Wincrypt.h>
#pragma comment(lib, "crypt32")
#endif
#ifdef __APPLE__
# include <Security/SecTrustSettings.h>
#endif
/* /*
* OPENSSL_COMPATIBLE_DEFAULTS: * OPENSSL_COMPATIBLE_DEFAULTS:
* Enable default behaviour that is compatible with OpenSSL. For example * Enable default behaviour that is compatible with OpenSSL. For example
@@ -8041,7 +8050,119 @@ int wolfSSL_CTX_load_verify_locations(WOLFSSL_CTX* ctx, const char* file,
return WS_RETURN_CODE(ret,WOLFSSL_FAILURE); return WS_RETURN_CODE(ret,WOLFSSL_FAILURE);
} }
#ifndef _WIN32 #ifdef USE_WINDOWS_API
static int LoadSystemCaCertsWindows(WOLFSSL_CTX* ctx, byte* loaded)
{
int ret = WOLFSSL_SUCCESS;
word32 i;
HANDLE handle = NULL;
PCCERT_CONTEXT certCtx = NULL;
LPCSTR storeNames[2] = {"ROOT", "CA"};
HCRYPTPROV_LEGACY hProv = (HCRYPTPROV_LEGACY)NULL;
if (ctx == NULL || loaded == NULL) {
ret = WOLFSSL_FAILURE;
}
for (i = 0; ret == WOLFSSL_SUCCESS &&
i < sizeof(storeNames)/sizeof(*storeNames); ++i) {
handle = CertOpenSystemStoreA(hProv, storeNames[i]);
if (handle != NULL) {
while (certCtx = CertEnumCertificatesInStore(handle,
certCtx)) {
if (certCtx->dwCertEncodingType == X509_ASN_ENCODING) {
if (ProcessBuffer(ctx, certCtx->pbCertEncoded,
certCtx->cbCertEncoded, WOLFSSL_FILETYPE_ASN1,
CA_TYPE, NULL, NULL, 0,
GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) {
/*
* Set "loaded" as long as we've loaded one CA
* cert.
*/
*loaded = 1;
}
}
}
}
else {
WOLFSSL_MSG_EX("Failed to open cert store %s.", storeNames[i]);
}
if (handle != NULL && !CertCloseStore(handle, 0)) {
WOLFSSL_MSG_EX("Failed to close cert store %s.", storeNames[i]);
ret = WOLFSSL_FAILURE;
}
}
return ret;
}
#elif defined(__APPLE__)
static int LoadSystemCaCertsMac(WOLFSSL_CTX* ctx, byte* loaded)
{
int ret = WOLFSSL_SUCCESS;
word32 i;
const unsigned int trustDomains[] = {
kSecTrustSettingsDomainUser,
kSecTrustSettingsDomainAdmin,
kSecTrustSettingsDomainSystem
};
CFArrayRef certs;
OSStatus stat;
CFIndex numCerts;
CFDataRef der;
CFIndex j;
if (ctx == NULL || loaded == NULL) {
ret = WOLFSSL_FAILURE;
}
for (i = 0; ret == WOLFSSL_SUCCESS &&
i < sizeof(trustDomains)/sizeof(*trustDomains); ++i) {
stat = SecTrustSettingsCopyCertificates(trustDomains[i], &certs);
if (stat == errSecSuccess) {
numCerts = CFArrayGetCount(certs);
for (j = 0; j < numCerts; ++j) {
der = SecCertificateCopyData((SecCertificateRef)
CFArrayGetValueAtIndex(certs, j));
if (der != NULL) {
if (ProcessBuffer(ctx, CFDataGetBytePtr(der),
CFDataGetLength(der), WOLFSSL_FILETYPE_ASN1,
CA_TYPE, NULL, NULL, 0,
GET_VERIFY_SETTING_CTX(ctx)) == WOLFSSL_SUCCESS) {
/*
* Set "loaded" as long as we've loaded one CA
* cert.
*/
*loaded = 1;
}
CFRelease(der);
}
}
CFRelease(certs);
}
else if (stat == errSecNoTrustSettings) {
WOLFSSL_MSG_EX("No trust settings for domain %d, moving to next "
"domain.", trustDomains[i]);
}
else {
WOLFSSL_MSG_EX("SecTrustSettingsCopyCertificates failed with"
" status %d.", stat);
ret = WOLFSSL_FAILURE;
break;
}
}
return ret;
}
#else
/* Potential system CA certs directories on Linux distros. */ /* Potential system CA certs directories on Linux distros. */
static const char* systemCaDirs[] = { static const char* systemCaDirs[] = {
"/etc/ssl/certs", /* Debian, Ubuntu, Gentoo, others */ "/etc/ssl/certs", /* Debian, Ubuntu, Gentoo, others */
@@ -8063,24 +8184,17 @@ const char** wolfSSL_get_system_CA_dirs(word32* num)
return ret; return ret;
} }
#endif /* !_WIN32 */
int wolfSSL_CTX_load_system_CA_certs(WOLFSSL_CTX* ctx) static int LoadSystemCaCertsNix(WOLFSSL_CTX* ctx, byte* loaded) {
{ int ret = WOLFSSL_SUCCESS;
int ret;
#ifndef _WIN32
word32 i; word32 i;
byte loaded = 0;
#endif
WOLFSSL_ENTER("wolfSSL_CTX_load_system_CA_certs"); if (ctx == NULL || loaded == NULL) {
ret = WOLFSSL_FAILURE;
}
#ifdef _WIN32 for (i = 0; ret == WOLFSSL_SUCCESS &&
(void)ctx; i < sizeof(systemCaDirs)/sizeof(*systemCaDirs); ++i) {
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.", WOLFSSL_MSG_EX("Attempting to load system CA certs from %s.",
systemCaDirs[i]); systemCaDirs[i]);
/* /*
@@ -8096,20 +8210,35 @@ int wolfSSL_CTX_load_system_CA_certs(WOLFSSL_CTX* ctx)
else { else {
WOLFSSL_MSG_EX("Loaded CA certs from %s.", WOLFSSL_MSG_EX("Loaded CA certs from %s.",
systemCaDirs[i]); systemCaDirs[i]);
loaded = 1; *loaded = 1;
/* Stop searching after we've loaded one directory. */ /* Stop searching after we've loaded one directory. */
break; break;
} }
} }
return ret;
} }
if (loaded) { #endif
ret = WOLFSSL_SUCCESS;
} int wolfSSL_CTX_load_system_CA_certs(WOLFSSL_CTX* ctx)
else { {
int ret;
byte loaded = 0;
WOLFSSL_ENTER("wolfSSL_CTX_load_system_CA_certs");
#ifdef USE_WINDOWS_API
ret = LoadSystemCaCertsWindows(ctx, &loaded);
#elif defined(__APPLE__)
ret = LoadSystemCaCertsMac(ctx, &loaded);
#else
ret = LoadSystemCaCertsNix(ctx, &loaded);
#endif
if (ret == WOLFSSL_SUCCESS && !loaded) {
ret = WOLFSSL_BAD_PATH; ret = WOLFSSL_BAD_PATH;
} }
#endif
WOLFSSL_LEAVE("wolfSSL_CTX_load_system_CA_certs", ret); WOLFSSL_LEAVE("wolfSSL_CTX_load_system_CA_certs", ret);
@@ -16249,13 +16378,6 @@ cleanup:
*/ */
ret = WOLFSSL_SUCCESS; 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); WOLFSSL_LEAVE("wolfSSL_CTX_set_default_verify_paths", ret);

View File

@@ -1352,31 +1352,26 @@ static int test_wolfSSL_CTX_load_system_CA_certs(void)
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_WOLFSSL_CLIENT) #if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_WOLFSSL_CLIENT)
WOLFSSL_CTX* ctx; WOLFSSL_CTX* ctx;
byte dirValid = 0;
ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); ctx = wolfSSL_CTX_new(wolfSSLv23_client_method());
if (ctx == NULL) { if (ctx == NULL) {
fprintf(stderr, "wolfSSL_CTX_new failed.\n");
ret = -1; ret = -1;
} }
if (ret == 0) { if (ret == 0) {
#ifdef _WIN32 #if defined(USE_WINDOWS_API) || defined(__APPLE__)
if (wolfSSL_CTX_load_system_CA_certs(ctx) != WOLFSSL_NOT_IMPLEMENTED) { dirValid = 1;
ret = -1;
}
#ifdef OPENSSL_EXTRA
if (wolfSSL_CTX_set_default_verify_paths(ctx) != WOLFSSL_FAILURE) {
ret = -1;
}
#endif /* OPENSSL_EXTRA */
#else #else
word32 numDirs; word32 numDirs;
const char** caDirs = wolfSSL_get_system_CA_dirs(&numDirs); const char** caDirs = wolfSSL_get_system_CA_dirs(&numDirs);
if (caDirs == NULL || numDirs == 0) { if (caDirs == NULL || numDirs == 0) {
fprintf(stderr, "wolfSSL_get_system_CA_dirs failed.\n");
ret = -1; ret = -1;
} }
else { else {
ReadDirCtx dirCtx; ReadDirCtx dirCtx;
byte dirValid = 0;
word32 i; word32 i;
for (i = 0; i < numDirs; ++i) { for (i = 0; i < numDirs; ++i) {
@@ -1387,29 +1382,26 @@ static int test_wolfSSL_CTX_load_system_CA_certs(void)
break; break;
} }
} }
}
#endif
}
/* /*
* If the directory isn't empty, we should be able to load CA * If the directory isn't empty, we should be able to load CA
* certs from it. * certs from it. On Windows/Mac, we assume the CA cert stores are
* usable.
*/ */
if (dirValid && wolfSSL_CTX_load_system_CA_certs(ctx) != if (ret == 0 && dirValid && wolfSSL_CTX_load_system_CA_certs(ctx) !=
WOLFSSL_SUCCESS) { WOLFSSL_SUCCESS) {
fprintf(stderr, "wolfSSL_CTX_load_system_CA_certs failed.\n");
ret = -1; ret = -1;
} }
#ifdef OPENSSL_EXTRA #ifdef OPENSSL_EXTRA
/* if (ret == 0 &&
* Even if we don't have a valid directory to load system CA wolfSSL_CTX_set_default_verify_paths(ctx) != WOLFSSL_SUCCESS) {
* certs from, the OpenSSL compat layer function should return fprintf(stderr, "wolfSSL_CTX_set_default_verify_paths failed.\n");
* success.
*/
if (wolfSSL_CTX_set_default_verify_paths(ctx)
!= WOLFSSL_SUCCESS) {
ret = -1; ret = -1;
} }
#endif /* OPENSSL_EXTRA */ #endif /* OPENSSL_EXTRA */
}
#endif /* _WIN32 */
}
wolfSSL_CTX_free(ctx); wolfSSL_CTX_free(ctx);
#endif /* !NO_FILESYSTEM && !NO_CERTS && !NO_WOLFSSL_CLIENT */ #endif /* !NO_FILESYSTEM && !NO_CERTS && !NO_WOLFSSL_CLIENT */