CVE-2026-82208: wolfSSL CA-cache hit overrides callback
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
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.
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
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.
in lib/vtls/wolfssl.c
Read the reasoning
File location confirmed in both master and release versions.
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.
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.
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)
Source code
| 790 | CURLcode 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 | } |
| 778 | CURLcode 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 | } |
Show 1 lines (not cited by the judge)
| 1010 | # define false 0 |
Show 66 lines (not cited by the judge)
| 1492 | static 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 | } |
Show 64 lines (not cited by the judge)
| 1455 | static 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 | } |
Show 89 lines (not cited by the judge)
| 584 | static 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 | } |
Show 93 lines (not cited by the judge)
| 568 | static 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 | } |