Selaa lähdekoodia

Merge pull request #5660 from haydenroche5/load_system_root_certs

Add support for wolfSSL_CTX_load_system_CA_certs on Windows and Mac.
David Garske 1 vuosi sitten
vanhempi
commit
3b33c962c4
7 muutettua tiedostoa jossa 292 lisäystä ja 97 poistoa
  1. 31 0
      CMakeLists.txt
  2. 38 9
      configure.ac
  3. 4 3
      doc/dox_comments/header_files/ssl.h
  4. 8 6
      examples/client/client.c
  5. 174 45
      src/ssl.c
  6. 26 34
      tests/api.c
  7. 11 0
      wolfssl/wolfcrypt/settings.h

+ 31 - 0
CMakeLists.txt

@@ -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>")
 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
         $<$<PLATFORM_ID:Windows>:ws2_32>)
+elseif(APPLE)
+    target_link_libraries(wolfssl PUBLIC
+        ${CORE_FOUNDATION_FRAMEWORK}
+        ${SECURITY_FRAMEWORK})
 else()
     # DH requires math (m) library
     target_link_libraries(wolfssl

+ 38 - 9
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 "---"
 

+ 4 - 3
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().
 

+ 8 - 6
examples/client/client.c

@@ -1318,7 +1318,7 @@ static const char* client_usage_msg[][70] = {
 #ifdef WOLFSSL_SRTP
         "--srtp <profile> (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

+ 174 - 45
src/ssl.c

@@ -162,6 +162,15 @@
 #endif
 #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:
  *     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)

+ 26 - 34
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;
 }

+ 11 - 0
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