✓ProveIt
Examples / Report #3973090 Saved analysis

CVE-2026-82208: wolfSSL CA-cache hit overrides callback

curl · 2026-08-2717.8s analysis · $0.023 in model calls

What the report claims

curl can silently reinstall a cached CA store after an SSL_CTX_FUNCTION callback replaces it, causing a callback-selected trust store to be bypassed when CA caching is enabled.

Compare with curl's recorded outcome

Known vulnerability

A real vulnerability: CVE-2026-82208 wolfSSL CA-cache hit overrides callback

Shown for comparison after analysis. The pipeline did not see this label.

ProveIt's finding

Code supports the claim

The code supports the reported flaw. A maintainer should review its impact and decide what to do next.

Why this finding?
  • The release version (curl-8_21_0) shows Curl_wssl_setup_x509_store() does not set wssl->x509_store_setup on cache hits, while master (b73a4f00b2a6) does at line 801 via commit ed0338befd.
  • The flaw allows a cached CA store to silently override a CURLOPT_SSL_CTX_FUNCTION callback's store, bypassing the application's trust policy — a clear security impact.
  • Reproduction steps are specific, actionable, and match the code path in the vulnerable releases.
  • The fix is in master but not in any released version (8.9.1–8.21.0), so the vulnerability exists in production releases.
How this analysis ran 5 claims · 9 citations verified

Checked against curl master on 2026-08-27 (b73a4f00b2a6). Dev evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.

1 · Grounding
partially grounded
no model · 10 references checked out, 1 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 2128 tokens · $0.0002
3 · Evidence
7 code snippets
real curl source at b73a4f00b2a6 · 3 docs via Tavily
4 · Judgment
Nemotron-3-Ultra-550b-a55b
16486 tokens · 13.7s · $0.0228
5 · Receipts
9 of 9 citations verified
every citation must point at code the judge was shown
Review a draft reply to the reporter

Edit and verify before sending.

Thank you for the detailed report. The issue is confirmed in releases 8.9.1 through 8.21.0: Curl_wssl_setup_x509_store() in lib/vtls/wolfssl.c does not set wssl->x509_store_setup on cache hits, allowing a cached store to overwrite a CURLOPT_SSL_CTX_FUNCTION callback's store. The fix (commit ed0338befd) is in master but not yet released. We will include it in the next release. Your reproduction steps are clear and will be used for verification.

Inspect all claims and source code 5 claims · 7 code excerpts

Report claims

C1flaw supported

Curl_wssl_setup_x509_store() installs a cached X509 store but does not set wssl->x509_store_setup = TRUE

Read the reasoning

The claim accurately describes the vulnerable releases (8.9.1–8.21.0). The release code shows the flag is not set on cache hits; master already contains the fix.

C2location supported

in lib/vtls/wolfssl.c

Read the reasoning

File location confirmed in both master and release versions.

C3trigger supported

CA caching is enabled and an CURLOPT_SSL_CTX_FUNCTION callback replaces the trust store

Read the reasoning

CA caching is controlled by CURLOPT_CA_CACHE_TIMEOUT (ca_cache_timeout). The callback CURLOPT_SSL_CTX_FUNCTION is a documented curl option that can replace the wolfSSL context's cert store.

C4impact supported

a certificate trusted by the cached store but rejected by the callback-selected store is then incorrectly accepted

Read the reasoning

In vulnerable releases, the missing flag allows a second Curl_wssl_setup_x509_store() invocation during handshake to overwrite the callback's store with the cached store, causing incorrect acceptance.

C5reproduction supported

use a multi handle, set CURLOPT_CAINFO to CA A, set a nonzero CURLOPT_CA_CACHE_TIMEOUT, make a first transfer to populate the cache, then a second transfer with a callback that replaces the store with only CA B

Read the reasoning

Reproduction steps are concrete and map to the code path: first transfer populates cache (cache miss → wssl_populate_x509_store sets flag), second transfer with callback hits cache but flag remains false in vulnerable code, allowing overwrite.

Deterministic checks that failed

  • symbol CTX_get_cert_store() does not exist in curl at b73a4f00b2a6 or in any release since 7.50
Read the original report (excerpt)

Full report on HackerOne ↗

## Summary With the wolfSSL backend, when CA caching is enabled and an `CURLOPT_SSL_CTX_FUNCTION` callback replaces the trust store, curl can silently reinstall the cached store after the callback returns. A certificate trusted by the cached store but rejected by the callback-selected store is then incorrectly accepted. ## Root cause `Curl_wssl_setup_x509_store()` in `lib/vtls/wolfssl.c` installs a cached X509 store but does not set `wssl->x509_store_setup = TRUE`. That flag is only set inside `wssl_populate_x509_store()`, which runs on cache misses. The sequence on a cache hit: 1. Before invoking the callback, `wssl_connect_step1()` calls `Curl_wssl_setup_x509_store()` — cached store A is installed, flag stays `false`. 2. The `CURLOPT_SSL_CTX_FUNCTION` callback runs and replaces store A with store B. 3. During the handshake, the still-false flag causes `Curl_wssl_setup_x509_store()` to run again. It finds `CTX_get_cert_store() != cached_store` (the callback changed it), so it reinstalls cached store A. ## Affected versions Introduced in commit `0f2876b2c33f` (Jul 2024, "wolfSSL: CA store share fix" for #14278). Present in releases **8.9.1 through 8.21.0**. ## Impact An application that uses `CURLOPT_SSL_CTX_FUNCTION` to restrict trust (e.g. pin to a private CA) has that restriction silently bypassed when CA caching is active. A MITM presenting a certificate valid under the cached store but rejected by the callback's store succeeds. Prerequisites: wolfSSL backend, `CURLOPT_CA_CACHE_TIMEOUT != 0`, a callback that replaces the store, and differing trust between the two stores. ## Reproduction 1. Build an affected curl release (8.9.1 through 8.21.0) against wolfSSL and configure curl without a compiled-in default CA path so that a CA file is eligible for caching. 2. Create two independent certificate authorities, called CA A and CA B. 3. Create a TLS server certificate for the test hostname, including a matching subject alternative name, and sign it with CA A. 4. Start an HTTPS server on the test hostname using that certificate. 5. Write a small libcurl client that uses the same multi handle for two transfers, sets `CURLOPT_CAINFO` to CA A, and sets a nonzero `CURLOPT_CA_CACHE_TIMEOUT`. 6. Make the first transfer without an SSL-context callback. Confirm that it succeeds and thereby populates curl's CA cache with the trust store containing CA A. 7. Fo …

Source code

lib/vtls/wolfssl.clines 790–844 · definition of Curl_wssl_setup_x509_store
790CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
C2: Function definition at line 790 in master; at line 778 in release 8.21.0
791 struct Curl_easy *data,
792 struct wssl_ctx *wssl)
793{
794 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
795 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
796 CURLcode result = CURLE_OK;
797 WOLFSSL_X509_STORE *cached_store;
798 bool cache_criteria_met;
799
800 /* We do not want to do this again, no matter the outcome */
801 wssl->x509_store_setup = TRUE;
C1: In current master (b73a4f00b2a6), the flag is set at line 801: 'wssl->x509_store_setup = TRUE;' — this is the fix from commit ed0338befd
802
803 /* Consider the X509 store cacheable if it comes exclusively from a CAfile,
804 or no source is provided and we are falling back to wolfSSL's built-in
805 default. */
806 cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
C3: Same check at line 806 in master
C5: Same in master
807 conn_config->verifypeer &&
808 !conn_config->CApath &&
809 !conn_config->ca_info_blob &&
810 !ssl_config->primary.CRLfile &&
811 !conn_config->native_ca_store;
812
813 cached_store = cache_criteria_met ? wssl_get_cached_x509_store(cf, data)
814 : NULL;
815 if(cached_store &&
C4: Master fixes this by setting flag at line 801 before cache check
816 wolfSSL_CTX_get_cert_store(wssl->ssl_ctx) == cached_store) {
817 /* The cached store is already in use, do nothing. */
818 }
819 else if(cached_store && wolfSSL_X509_STORE_up_ref(cached_store)) {
820 wolfSSL_CTX_set_cert_store(wssl->ssl_ctx, cached_store);
821 }
822 else if(cache_criteria_met) {
823 /* wolfSSL's initial store in CTX is not shareable by default.
824 * Make a new one, suitable for adding to the cache. See #14278 */
825 WOLFSSL_X509_STORE *store = wolfSSL_X509_STORE_new();
826 if(!store) {
827 failf(data, "SSL: could not create a X509 store");
828 return CURLE_OUT_OF_MEMORY;
829 }
830 wolfSSL_CTX_set_cert_store(wssl->ssl_ctx, store);
831
832 result = wssl_populate_x509_store(cf, data, store, wssl);
833 if(!result) {
834 wssl_set_cached_x509_store(cf, data, store);
835 }
836 }
837 else {
838 /* We never share the CTX's store, use it. */
839 WOLFSSL_X509_STORE *store = wolfSSL_CTX_get_cert_store(wssl->ssl_ctx);
840 result = wssl_populate_x509_store(cf, data, store, wssl);
841 }
842
843 return result;
844}
lib/vtls/wolfssl.c@curl-8_21_0lines 778–829 · definition of Curl_wssl_setup_x509_store as in release curl-8_21_0; differs from master; commits that changed it since: ed0338befd wolfssl: do not run Curl_wssl_setup_x509_store() twice | 7be1e70cb6 vtls: move 'native_ca_store' ssl_config_data => ssl_primary_config
778CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
C1: In release 8.21.0, Curl_wssl_setup_x509_store() lacks the flag set at function entry; wssl->x509_store_setup is only set inside wssl_populate_x509_store() at line 584
779 struct Curl_easy *data,
780 struct wssl_ctx *wssl)
781{
782 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
783 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
784 CURLcode result = CURLE_OK;
785 WOLFSSL_X509_STORE *cached_store;
786 bool cache_criteria_met;
787
788 /* Consider the X509 store cacheable if it comes exclusively from a CAfile,
789 or no source is provided and we are falling back to wolfSSL's built-in
790 default. */
791 cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
C3: cache_criteria_met checks data->set.general_ssl.ca_cache_timeout != 0 at line 791
C5: ca_cache_timeout check enables caching
792 conn_config->verifypeer &&
793 !conn_config->CApath &&
794 !conn_config->ca_info_blob &&
795 !ssl_config->primary.CRLfile &&
796 !ssl_config->native_ca_store;
797
798 cached_store = cache_criteria_met ? wssl_get_cached_x509_store(cf, data)
799 : NULL;
800 if(cached_store &&
C4: On cache hit, cached store is installed (line 805) but flag not set; subsequent call reinstalls it (line 805 again) after callback replaces it
801 wolfSSL_CTX_get_cert_store(wssl->ssl_ctx) == cached_store) {
802 /* The cached store is already in use, do nothing. */
803 }
804 else if(cached_store && wolfSSL_X509_STORE_up_ref(cached_store)) {
805 wolfSSL_CTX_set_cert_store(wssl->ssl_ctx, cached_store);
806 }
807 else if(cache_criteria_met) {
808 /* wolfSSL's initial store in CTX is not shareable by default.
809 * Make a new one, suitable for adding to the cache. See #14278 */
810 WOLFSSL_X509_STORE *store = wolfSSL_X509_STORE_new();
811 if(!store) {
812 failf(data, "SSL: could not create a X509 store");
813 return CURLE_OUT_OF_MEMORY;
814 }
815 wolfSSL_CTX_set_cert_store(wssl->ssl_ctx, store);
816
817 result = wssl_populate_x509_store(cf, data, store, wssl);
818 if(!result) {
819 wssl_set_cached_x509_store(cf, data, store);
820 }
821 }
822 else {
823 /* We never share the CTX's store, use it. */
824 WOLFSSL_X509_STORE *store = wolfSSL_CTX_get_cert_store(wssl->ssl_ctx);
825 result = wssl_populate_x509_store(cf, data, store, wssl);
826 }
827
828 return result;
829}
lib/curl_setup.hlines 1010–1010 · definition of false
Show 1 lines (not cited by the judge)
1010# define false 0
lib/vtls/wolfssl.clines 1492–1557 · definition of wssl_connect_step1
Show 66 lines (not cited by the judge)
1492static CURLcode wssl_connect_step1(struct Curl_cfilter *cf,
1493 struct Curl_easy *data)
1494{
1495 struct ssl_connect_data *connssl = cf->ctx;
1496 struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
1497 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
1498 CURLcode result;
1499
1500 DEBUGASSERT(wssl);
1501
1502 if(connssl->state == ssl_connection_complete)
1503 return CURLE_OK;
1504
1505 result = Curl_wssl_ctx_init(wssl, cf, data, &connssl->peer, connssl->alpn,
1506 NULL, NULL, cf, wssl_on_session_reuse);
1507 if(result)
1508 return result;
1509
1510#ifdef HAVE_ALPN
1511 if(connssl->alpn && (connssl->state != ssl_connection_deferred)) {
1512 struct alpn_proto_buf proto;
1513 memset(&proto, 0, sizeof(proto));
1514 Curl_alpn_to_proto_str(&proto, connssl->alpn);
1515 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
1516 }
1517#endif
1518
1519 /* Enable RFC2818 checks on domain names. This cannot check
1520 * IP addresses which we need to do extra after the handshake. */
1521 if(conn_config->verifyhost && connssl->peer.sni) {
1522 if(wolfSSL_check_domain_name(wssl->ssl, connssl->peer.sni) !=
1523 WOLFSSL_SUCCESS) {
1524 return CURLE_SSL_CONNECT_ERROR;
1525 }
1526 }
1527
1528#ifdef USE_BIO_CHAIN
1529 {
1530 WOLFSSL_BIO *bio;
1531
1532 if(!wssl_bio_cf_method)
1533 return CURLE_FAILED_INIT;
1534 bio = wolfSSL_BIO_new(wssl_bio_cf_method);
1535 if(!bio)
1536 return CURLE_OUT_OF_MEMORY;
1537
1538 wolfSSL_BIO_set_data(bio, cf);
1539 wolfSSL_set_bio(wssl->ssl, bio, bio);
1540 }
1541#else /* !USE_BIO_CHAIN */
1542 {
1543 curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
1544 if(sockfd > INT_MAX) {
1545 failf(data, "SSL: socket value too large");
1546 return CURLE_SSL_CONNECT_ERROR;
1547 }
1548 /* pass the raw socket into the SSL layer */
1549 if(!wolfSSL_set_fd(wssl->ssl, (int)sockfd)) {
1550 failf(data, "SSL: wolfSSL_set_fd failed");
1551 return CURLE_SSL_CONNECT_ERROR;
1552 }
1553 }
1554#endif /* USE_BIO_CHAIN */
1555
1556 return CURLE_OK;
1557}
lib/vtls/wolfssl.c@curl-8_21_0lines 1455–1518 · definition of wssl_connect_step1 as in release curl-8_21_0; differs from master; commits that changed it since: 3dd6a87a7f wolfssl: fix build for wolfssl without bio chain support
Show 64 lines (not cited by the judge)
1455static CURLcode wssl_connect_step1(struct Curl_cfilter *cf,
1456 struct Curl_easy *data)
1457{
1458 struct ssl_connect_data *connssl = cf->ctx;
1459 struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
1460 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
1461 CURLcode result;
1462
1463 DEBUGASSERT(wssl);
1464
1465 if(connssl->state == ssl_connection_complete)
1466 return CURLE_OK;
1467
1468 result = Curl_wssl_ctx_init(wssl, cf, data, &connssl->peer, connssl->alpn,
1469 NULL, NULL, cf, wssl_on_session_reuse);
1470 if(result)
1471 return result;
1472
1473#ifdef HAVE_ALPN
1474 if(connssl->alpn && (connssl->state != ssl_connection_deferred)) {
1475 struct alpn_proto_buf proto;
1476 memset(&proto, 0, sizeof(proto));
1477 Curl_alpn_to_proto_str(&proto, connssl->alpn);
1478 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
1479 }
1480#endif
1481
1482 /* Enable RFC2818 checks on domain names. This cannot check
1483 * IP addresses which we need to do extra after the handshake. */
1484 if(conn_config->verifyhost && connssl->peer.sni) {
1485 if(wolfSSL_check_domain_name(wssl->ssl, connssl->peer.sni) !=
1486 WOLFSSL_SUCCESS) {
1487 return CURLE_SSL_CONNECT_ERROR;
1488 }
1489 }
1490
1491#ifdef USE_BIO_CHAIN
1492 {
1493 WOLFSSL_BIO *bio;
1494
1495 if(!wssl_bio_cf_method)
1496 return CURLE_FAILED_INIT;
1497 bio = wolfSSL_BIO_new(wssl_bio_cf_method);
1498 if(!bio)
1499 return CURLE_OUT_OF_MEMORY;
1500
1501 wolfSSL_BIO_set_data(bio, cf);
1502 wolfSSL_set_bio(wssl->ssl, bio, bio);
1503 }
1504#else /* !USE_BIO_CHAIN */
1505 curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
1506 if(sockfd > INT_MAX) {
1507 failf(data, "SSL: socket value too large");
1508 return CURLE_SSL_CONNECT_ERROR;
1509 }
1510 /* pass the raw socket into the SSL layer */
1511 if(!wolfSSL_set_fd(wssl->ssl, (int)sockfd)) {
1512 failf(data, "SSL: wolfSSL_set_fd failed");
1513 return CURLE_SSL_CONNECT_ERROR;
1514 }
1515#endif /* USE_BIO_CHAIN */
1516
1517 return CURLE_OK;
1518}
lib/vtls/wolfssl.clines 584–672 · definition of wssl_populate_x509_store
Show 89 lines (not cited by the judge)
584static CURLcode wssl_populate_x509_store(struct Curl_cfilter *cf,
585 struct Curl_easy *data,
586 WOLFSSL_X509_STORE *store,
587 struct wssl_ctx *wssl)
588{
589 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
590 const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
591 const char * const ssl_cafile =
592 /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
593 (ca_info_blob ? NULL : conn_config->CAfile);
594 const char * const ssl_capath = conn_config->CApath;
595 bool imported_native_ca = FALSE;
596 bool imported_ca_info_blob = FALSE;
597
598#ifndef NO_FILESYSTEM
599 /* load native CA certificates */
600 if(conn_config->native_ca_store) {
601#ifdef WOLFSSL_SYS_CA_CERTS
602 if(wolfSSL_CTX_load_system_CA_certs(wssl->ssl_ctx) != WOLFSSL_SUCCESS) {
603 infof(data, "error importing native CA store, continuing anyway");
604 }
605 else {
606 imported_native_ca = TRUE;
607 infof(data, "successfully imported native CA store");
608 }
609#else
610 infof(data, "ignoring native CA option because wolfSSL was built without "
611 "native CA support");
612#endif
613 }
614#endif /* !NO_FILESYSTEM */
615
616 /* load certificate blob */
617 if(ca_info_blob) {
618 if(wolfSSL_CTX_load_verify_buffer(wssl->ssl_ctx, ca_info_blob->data,
619 (long)ca_info_blob->len,
620 WOLFSSL_FILETYPE_PEM) !=
621 WOLFSSL_SUCCESS) {
622 failf(data, "error importing CA certificate blob");
623 return CURLE_SSL_CACERT_BADFILE;
624 }
625 else {
626 imported_ca_info_blob = TRUE;
627 infof(data, "successfully imported CA certificate blob");
628 }
629 }
630
631#ifndef NO_FILESYSTEM
632 /* load trusted cacert from file if not blob */
633
634 CURL_TRC_CF(data, cf, "wssl_populate_x509_store, path=%s, blob=%d",
635 ssl_cafile ? ssl_cafile : "none", !!ca_info_blob);
636 if(!store)
637 return CURLE_OUT_OF_MEMORY;
638
639 if(ssl_cafile || ssl_capath) {
640 int rc =
641 wolfSSL_CTX_load_verify_locations_ex(wssl->ssl_ctx,
642 ssl_cafile,
643 ssl_capath,
644 WOLFSSL_LOAD_FLAG_IGNORE_ERR);
645 if(rc != WOLFSSL_SUCCESS) {
646 if(conn_config->verifypeer &&
647 !imported_native_ca && !imported_ca_info_blob) {
648 /* Fail if we insist on successfully verifying the server. */
649 failf(data, "error setting certificate verify locations:"
650 " CAfile: %s CApath: %s",
651 ssl_cafile ? ssl_cafile : "none",
652 ssl_capath ? ssl_capath : "none");
653 return CURLE_SSL_CACERT_BADFILE;
654 }
655 else {
656 /* continue with a warning if no strict certificate
657 verification is required. */
658 infof(data, "error setting certificate verify locations,"
659 " continuing anyway:");
660 }
661 }
662 else {
663 /* Everything is fine. */
664 infof(data, "successfully set certificate verify locations:");
665 }
666 infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
667 infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
668 }
669#endif
670 (void)store;
671 return CURLE_OK;
672}
lib/vtls/wolfssl.c@curl-8_21_0lines 568–660 · definition of wssl_populate_x509_store as in release curl-8_21_0; differs from master; commits that changed it since: ed0338befd wolfssl: do not run Curl_wssl_setup_x509_store() twice | 7be1e70cb6 vtls: move 'native_ca_store' ssl_config_data => ssl_primary_config | 84c5dcdb05 tidy-up: syntax and code nits
Show 93 lines (not cited by the judge)
568static CURLcode wssl_populate_x509_store(struct Curl_cfilter *cf,
569 struct Curl_easy *data,
570 WOLFSSL_X509_STORE *store,
571 struct wssl_ctx *wssl)
572{
573 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
574 const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
575 const char * const ssl_cafile =
576 /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
577 (ca_info_blob ? NULL : conn_config->CAfile);
578 const char * const ssl_capath = conn_config->CApath;
579 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
580 bool imported_native_ca = FALSE;
581 bool imported_ca_info_blob = FALSE;
582
583 /* We do not want to do this again, no matter the outcome */
584 wssl->x509_store_setup = TRUE;
585
586#ifndef NO_FILESYSTEM
587 /* load native CA certificates */
588 if(ssl_config->native_ca_store) {
589#ifdef WOLFSSL_SYS_CA_CERTS
590 if(wolfSSL_CTX_load_system_CA_certs(wssl->ssl_ctx) != WOLFSSL_SUCCESS) {
591 infof(data, "error importing native CA store, continuing anyway");
592 }
593 else {
594 imported_native_ca = TRUE;
595 infof(data, "successfully imported native CA store");
596 }
597#else
598 infof(data, "ignoring native CA option because wolfSSL was built without "
599 "native CA support");
600#endif
601 }
602#endif /* !NO_FILESYSTEM */
603
604 /* load certificate blob */
605 if(ca_info_blob) {
606 if(wolfSSL_CTX_load_verify_buffer(wssl->ssl_ctx, ca_info_blob->data,
607 (long)ca_info_blob->len,
608 WOLFSSL_FILETYPE_PEM) !=
609 WOLFSSL_SUCCESS) {
610 failf(data, "error importing CA certificate blob");
611 return CURLE_SSL_CACERT_BADFILE;
612 }
613 else {
614 imported_ca_info_blob = TRUE;
615 infof(data, "successfully imported CA certificate blob");
616 }
617 }
618
619#ifndef NO_FILESYSTEM
620 /* load trusted cacert from file if not blob */
621
622 CURL_TRC_CF(data, cf, "wssl_populate_x509_store, path=%s, blob=%d",
623 ssl_cafile ? ssl_cafile : "none", !!ca_info_blob);
624 if(!store)
625 return CURLE_OUT_OF_MEMORY;
626
627 if(ssl_cafile || ssl_capath) {
628 int rc =
629 wolfSSL_CTX_load_verify_locations_ex(wssl->ssl_ctx,
630 ssl_cafile,
631 ssl_capath,
632 WOLFSSL_LOAD_FLAG_IGNORE_ERR);
633 if(WOLFSSL_SUCCESS != rc) {
634 if(conn_config->verifypeer &&
635 !imported_native_ca && !imported_ca_info_blob) {
636 /* Fail if we insist on successfully verifying the server. */
637 failf(data, "error setting certificate verify locations:"
638 " CAfile: %s CApath: %s",
639 ssl_cafile ? ssl_cafile : "none",
640 ssl_capath ? ssl_capath : "none");
641 return CURLE_SSL_CACERT_BADFILE;
642 }
643 else {
644 /* continue with a warning if no strict certificate
645 verification is required. */
646 infof(data, "error setting certificate verify locations,"
647 " continuing anyway:");
648 }
649 }
650 else {
651 /* Everything is fine. */
652 infof(data, "successfully set certificate verify locations:");
653 }
654 infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
655 infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
656 }
657#endif
658 (void)store;
659 return CURLE_OK;
660}