diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a324692f..6724d03dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,18 @@ if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") set(CMAKE_CXX_ARCHIVE_FINISH " -no_warning_for_no_symbols -c ") 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) check_include_file("arpa/inet.h" HAVE_ARPA_INET_H) @@ -1528,6 +1540,10 @@ endif() # TODO: - Fast huge math +if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64") + list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_X86_64_BUILD") +endif() + # SP math all add_option("WOLFSSL_SP_MATH_ALL" "Enable Single Precision math implementation for full algorithm suite (default: enabled)" @@ -1654,6 +1670,17 @@ add_option("WOLFSSL_OPTFLAGS" "Enable default optimization CFLAGS for the compiler (default: enabled)" "yes" "yes;no") +add_option("WOLFSSL_SYS_CA_CERTS" + "Enable ability to load CA certs from OS (default: enabled)" + "yes" "yes;no") +if(WOLFSSL_SYS_CA_CERTS) + if(NOT WOLFSSL_FILESYSTEM) + message(FATAL_ERROR "Cannot use system CA certs without a filesystem.") + else() + list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SYS_CA_CERTS") + endif() +endif() + # FLAGS operations if(WOLFSSL_AESCCM) @@ -1902,6 +1929,10 @@ if(WIN32) # For Windows link ws2_32 target_link_libraries(wolfssl PUBLIC $<$:ws2_32>) +elseif(APPLE) + target_link_libraries(wolfssl PUBLIC + ${CORE_FOUNDATION_FRAMEWORK} + ${SECURITY_FRAMEWORK}) else() # DH requires math (m) library target_link_libraries(wolfssl diff --git a/configure.ac b/configure.ac index b4a64d555..d401392e8 100644 --- a/configure.ac +++ b/configure.ac @@ -940,7 +940,6 @@ then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_HAVE_ISSUER_NAMES" fi - # liboqs ENABLED_LIBOQS="no" tryliboqsdir="" @@ -1098,7 +1097,6 @@ AC_ARG_ENABLE([cryptonly], AS_IF([test "x$FIPS_VERSION" = "xrand"],[ENABLED_CRYPTONLY="yes"]) - # DTLS # DTLS is a prereq for the options mcast, sctp, and jni. Enabling any of those # without DTLS will also enable DTLS. @@ -7351,6 +7349,12 @@ AC_ARG_ENABLE([optflags], [ ENABLED_OPTFLAGS=yes ] ) +# Adds functionality to load CA certificates from the operating system. +AC_ARG_ENABLE([sys-ca-certs], + [AS_HELP_STRING([--enable-sys-ca-certs],[Enable ability to load CA certs from OS (default: enabled)])], + [ ENABLED_SYS_CA_CERTS=$enableval ], + [ ENABLED_SYS_CA_CERTS=yes ] + ) # check if should run the trusted peer certs test # (for now checking both C_FLAGS and C_EXTRA_FLAGS) @@ -7413,6 +7417,24 @@ esac # Update ENABLE_* variables # ################################################################################ +if test "x$ENABLED_LEANPSK" = "xyes" || test "x$ENABLED_CERTS" = "xno" || \ + test "x$ENABLED_ASN" = "xno" +then + ENABLED_CERTS=no + ENABLED_ASN=no +fi + +if test "x$ENABLED_SYS_CA_CERTS" = "xyes" +then + if test "x$ENABLED_FILESYSTEM" = "xno" + then + ENABLED_SYS_CA_CERTS="no" + elif test "x$ENABLED_CERTS" = "xno" + then + ENABLED_SYS_CA_CERTS="no" + fi +fi + if test "x$ENABLED_WOLFCLU" = "xyes" then if test "x$ENABLED_CERTGEN" = "xno" @@ -7626,6 +7648,14 @@ AS_IF([test "x$ENABLED_16BIT" = "xyes" && \ ################################################################################ # Update CFLAGS based on options # ################################################################################ +AS_IF([test "x$ENABLED_CERTS" = "xno"], + [AM_CFLAGS="$AM_CFLAGS -DNO_CERTS"]) + +AS_IF([test "x$ENABLED_ASN" = "xno"], + [AM_CFLAGS="$AM_CFLAGS -DNO_ASN"]) + +AS_IF([test "x$ENABLED_SYS_CA_CERTS" = "xyes"], + [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SYS_CA_CERTS"]) AS_IF([test "x$ENABLED_ALTNAMES" = "xyes"], [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ALT_NAMES"]) @@ -7899,11 +7929,6 @@ fi AS_IF([test "x$ENABLED_WOLFSSH" = "xyes"],[AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSL_WOLFSSH"]) -if test "x$ENABLED_CERTS" = "xno" || test "x$ENABLED_LEANPSK" = "xyes" || test "x$ENABLED_ASN" = "xno"; then - AM_CFLAGS="$AM_CFLAGS -DNO_ASN -DNO_CERTS" - ENABLED_ASN=no -fi - # only allow secure renegotiation info with TLSV12 and ASN if test "x$ENABLED_ASN" = "xno" || \ test "x$ENABLED_TLSV12" = "xno" || \ @@ -7989,13 +8014,12 @@ then AM_CFLAGS="$AM_CFLAGS -DHAVE___UINT128_T=1" fi - LIB_SOCKET_NSL AX_HARDEN_CC_COMPILER_FLAGS -# if mingw then link to ws2_32 for sockets case $host_os in mingw*) + # if mingw then link to ws2_32 for sockets LDFLAGS="$LDFLAGS -lws2_32" if test "$enable_shared" = "yes" then @@ -8005,6 +8029,10 @@ case $host_os in MINGW_LIB_WARNING="yes" fi fi ;; + *darwin*) + # For Mac we need these frameworks to load system CA certs + LDFLAGS="$LDFLAGS -framework CoreFoundation -framework Security" + ;; esac if test "$enable_shared" = "no"; then @@ -8667,6 +8695,7 @@ echo " * IoT-Safe: $ENABLED_IOTSAFE" echo " * IoT-Safe HWRNG: $ENABLED_IOTSAFE_HWRNG" echo " * NXP SE050: $ENABLED_SE050" echo " * PSA: $ENABLED_PSA" +echo " * System CA certs: $ENABLED_SYS_CA_CERTS" echo "" echo "---" diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index cb55ba00a..2f622f31d 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -1267,12 +1267,13 @@ 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. + from an OS-dependent CA certificate store. Loaded certificates will be + trusted. \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. + \return WOLFSSL_FAILURE for other failure types (e.g. Windows cert store + wasn't properly closed). \param ctx pointer to the SSL context, created with wolfSSL_CTX_new(). diff --git a/examples/client/client.c b/examples/client/client.c index 5c58e078b..c30aeb29d 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -1318,7 +1318,7 @@ static const char* client_usage_msg[][70] = { #ifdef WOLFSSL_SRTP "--srtp (default is SRTP_AES128_CM_SHA1_80)\n", /* 71 */ #endif -#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) +#ifdef WOLFSSL_SYS_CA_CERTS "--sys-ca-certs Load system CA certs for server cert verification\n", /* 72 */ #endif "\n" @@ -1767,7 +1767,7 @@ static void Usage(void) printf("%s", msg[++msgid]); /* more --pqc options */ printf("%s", msg[++msgid]); /* more --pqc options */ #endif -#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) +#ifdef WOLFSSL_SYS_CA_CERTS printf("%s", msg[++msgid]); /* --sys-ca-certs */ #endif #ifdef WOLFSSL_SRTP @@ -1903,7 +1903,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #ifdef WOLFSSL_DTLS_CID {"cid", 2, 262}, #endif /* WOLFSSL_DTLS_CID */ +#ifdef WOLFSSL_SYS_CA_CERTS { "sys-ca-certs", 0, 263 }, +#endif { 0, 0, 0 } }; #endif @@ -2013,7 +2015,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) char* pqcAlg = NULL; int exitWithRet = 0; int loadCertKeyIntoSSLObj = 0; -#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) +#ifdef WOLFSSL_SYS_CA_CERTS byte loadSysCaCerts = 0; #endif @@ -2716,7 +2718,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) pqcAlg = myoptarg; break; #endif -#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) +#ifdef WOLFSSL_SYS_CA_CERTS case 263: loadSysCaCerts = 1; break; @@ -2977,12 +2979,12 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) } #endif -#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) +#ifdef WOLFSSL_SYS_CA_CERTS if (loadSysCaCerts && wolfSSL_CTX_load_system_CA_certs(ctx) != WOLFSSL_SUCCESS) { err_sys("wolfSSL_CTX_load_system_CA_certs failed"); } -#endif +#endif /* WOLFSSL_SYS_CA_CERTS */ if (minVersion != CLIENT_INVALID_VERSION) { #ifdef WOLFSSL_DTLS diff --git a/src/ssl.c b/src/ssl.c index b486345cf..cf30c5baa 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -162,6 +162,15 @@ #endif #endif /* !WOLFCRYPT_ONLY || OPENSSL_EXTRA */ +#ifdef _WIN32 +#include +#pragma comment(lib, "crypt32") +#endif + +#ifdef __APPLE__ +# include +#endif + /* * OPENSSL_COMPATIBLE_DEFAULTS: * Enable default behaviour that is compatible with OpenSSL. For example @@ -174,6 +183,9 @@ * ClientCache by default for backwards compatibility. This define will * make wolfSSL_get_session return a reference to ssl->session. The returned * pointer will be freed with the related WOLFSSL object. + * WOLFSSL_SYS_CA_CERTS + * Enables ability to load system CA certs from the OS via + * wolfSSL_CTX_load_system_CA_certs. */ #define WOLFSSL_EVP_INCLUDED @@ -8040,7 +8052,121 @@ int wolfSSL_CTX_load_verify_locations(WOLFSSL_CTX* ctx, const char* file, return WS_RETURN_CODE(ret,WOLFSSL_FAILURE); } -#ifndef _WIN32 +#ifdef WOLFSSL_SYS_CA_CERTS + +#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. */ static const char* systemCaDirs[] = { "/etc/ssl/certs", /* Debian, Ubuntu, Gentoo, others */ @@ -8062,59 +8188,69 @@ const char** wolfSSL_get_system_CA_dirs(word32* num) return ret; } -#endif /* !_WIN32 */ + +static int LoadSystemCaCertsNix(WOLFSSL_CTX* ctx, byte* loaded) { + int ret = WOLFSSL_SUCCESS; + word32 i; + + if (ctx == NULL || loaded == NULL) { + ret = WOLFSSL_FAILURE; + } + + for (i = 0; ret == WOLFSSL_SUCCESS && + 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; + } + } + + return ret; +} + +#endif 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; +#ifdef USE_WINDOWS_API + ret = LoadSystemCaCertsWindows(ctx, &loaded); +#elif defined(__APPLE__) + ret = LoadSystemCaCertsMac(ctx, &loaded); #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; - } - } - } + ret = LoadSystemCaCertsNix(ctx, &loaded); +#endif - if (loaded) { - ret = WOLFSSL_SUCCESS; - } - else { + if (ret == WOLFSSL_SUCCESS && !loaded) { ret = WOLFSSL_BAD_PATH; } -#endif WOLFSSL_LEAVE("wolfSSL_CTX_load_system_CA_certs", ret); return ret; } +#endif /* WOLFSSL_SYS_CA_CERTS */ + #ifdef WOLFSSL_TRUST_PEER_CERT /* Used to specify a peer cert to match when connecting ctx : the ctx structure to load in peer cert @@ -16225,7 +16361,7 @@ cleanup: #ifdef OPENSSL_EXTRA - #ifndef NO_FILESYSTEM + #ifdef WOLFSSL_SYS_CA_CERTS /* * This is an OpenSSL compatibility layer function, but it doesn't mirror * the exact functionality of its OpenSSL counterpart. We don't support the @@ -16248,19 +16384,12 @@ cleanup: */ 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 /* !NO_FILESYSTEM */ + #endif /* WOLFSSL_SYS_CA_CERTS */ #if defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256) \ && !defined(WC_NO_RNG) diff --git a/tests/api.c b/tests/api.c index e99e3e5e0..02bc7e0be 100644 --- a/tests/api.c +++ b/tests/api.c @@ -1350,33 +1350,28 @@ static int test_wolfSSL_CTX_load_system_CA_certs(void) { int ret = 0; -#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_WOLFSSL_CLIENT) +#if defined(WOLFSSL_SYS_CA_CERTS) && !defined(NO_WOLFSSL_CLIENT) WOLFSSL_CTX* ctx; + byte dirValid = 0; ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); if (ctx == NULL) { + fprintf(stderr, "wolfSSL_CTX_new failed.\n"); 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 + #if defined(USE_WINDOWS_API) || defined(__APPLE__) + dirValid = 1; + #else word32 numDirs; const char** caDirs = wolfSSL_get_system_CA_dirs(&numDirs); if (caDirs == NULL || numDirs == 0) { + fprintf(stderr, "wolfSSL_get_system_CA_dirs failed.\n"); ret = -1; } else { ReadDirCtx dirCtx; - byte dirValid = 0; word32 i; for (i = 0; i < numDirs; ++i) { @@ -1387,32 +1382,29 @@ static int test_wolfSSL_CTX_load_system_CA_certs(void) 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 */ + #endif } + /* + * If the directory isn't empty, we should be able to load CA + * certs from it. On Windows/Mac, we assume the CA cert stores are + * usable. + */ + if (ret == 0 && dirValid && wolfSSL_CTX_load_system_CA_certs(ctx) != + WOLFSSL_SUCCESS) { + fprintf(stderr, "wolfSSL_CTX_load_system_CA_certs failed.\n"); + ret = -1; + } +#ifdef OPENSSL_EXTRA + if (ret == 0 && + wolfSSL_CTX_set_default_verify_paths(ctx) != WOLFSSL_SUCCESS) { + fprintf(stderr, "wolfSSL_CTX_set_default_verify_paths failed.\n"); + ret = -1; + } +#endif /* OPENSSL_EXTRA */ wolfSSL_CTX_free(ctx); -#endif /* !NO_FILESYSTEM && !NO_CERTS && !NO_WOLFSSL_CLIENT */ +#endif /* WOLFSSL_SYS_CA_CERTS && !NO_WOLFSSL_CLIENT */ return ret; } diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index dbf000605..3b0e889a3 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -2857,6 +2857,17 @@ extern void uITRON4_free(void *p) ; #define WOLFSSL_ASYNC_IO #endif +#ifdef WOLFSSL_SYS_CA_CERTS + #ifdef NO_FILESYSTEM + #warning "Turning off WOLFSSL_SYS_CA_CERTS b/c NO_FILESYSTEM is defined." + #undef WOLFSSL_SYS_CA_CERTS + #endif + #ifdef NO_CERTS + #warning "Turning off WOLFSSL_SYS_CA_CERTS b/c NO_CERTS is defined." + #undef WOLFSSL_SYS_CA_CERTS + #endif +#endif /* WOLFSSL_SYS_CA_CERTS */ + #ifdef __cplusplus } /* extern "C" */ #endif