CVE-2026-80229: OpenSSL provider use-after-free
What the report claims
A use-after-free in OpenSSL provider handling causes heap corruption when a TLS connection is reused after the originating easy handle is cleaned up.
Compare with curl's recorded outcome
Known vulnerability
A real vulnerability: CVE-2026-80229 OpenSSL provider use-after-free
Shown for comparison after analysis. The pipeline did not see this label.
ProveIt's finding
The available evidence does not settle the report. A maintainer should investigate.
See the withdrawn model reasoning
The following reasoning failed the citation check and does not support the final finding.
- The code confirms ossl_set_provider() allocates OSSL_LIB_CTX and stores it in data->state.libctx (lines 1791, 1801).
- ossl_connect_step1 passes this libctx to Curl_ossl_ctx_init which creates an SSL_CTX via SSL_CTX_new_ex(). OpenSSL docs confirm SSL_CTX_new_ex() borrows the library context without taking ownership.
- curl_easy_cleanup() → Curl_close() → ossl_close_all() → ossl_provider_cleanup() frees data->state.libctx (line 1752) while the pooled connection's SSL_CTX still holds a pointer to it.
- match_ssl_primary_config() does not compare engine/provider fields, so a pooled connection created with a provider can be reused by a handle without one, leading to use-after-free on any SSL operation.
- OpenSSL documentation explicitly states 'The OSSL_LIB_CTX must outlive every SSL_CTX that references it.'
How this analysis ran 6 claims · 13 citations verified
Evidence check: judge quoted an external source that does not say that (https://docs.openssl.org/3.3/man3/SSL_CTX_new_ex)
Checked against curl master on 2026-08-25 (7be1e70cb6bc). Dev evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.
Inspect the withdrawn draft reply
This draft belongs to the withdrawn judgment. It may contain unsupported claims.
Thank you for the detailed report. The code confirms the lifetime mismatch: ossl_set_provider() creates an OSSL_LIB_CTX tied to the easy handle, SSL_CTX_new_ex() borrows it without ownership, and ossl_provider_cleanup() frees it on handle cleanup while the pooled connection's SSL_CTX still references it. match_ssl_primary_config() does not compare provider state, enabling reuse. This is a valid use-after-free. We will implement a fix (likely reference-counting or transferring ownership to the connection filter).
Inspect all claims and source code 6 claims · 18 code excerpts
This model judgment was withdrawn. The claim assessments below are preserved for inspection and may be wrong.
Report claims
ossl_set_provider() allocates a per-handle OSSL_LIB_CTX and stores it in data->state.libctx
Read the reasoning
ossl_set_provider() allocates an OSSL_LIB_CTX via OSSL_LIB_CTX_new() and stores it in data->state.libctx when no prior libctx exists.
SSL_CTX_new_ex() receives this library context and embeds a pointer to it inside the newly created SSL_CTX
Read the reasoning
ossl_connect_step1 calls Curl_ossl_ctx_init which (per the report and OpenSSL docs) passes data->state.libctx to SSL_CTX_new_ex(). The OpenSSL documentation explicitly states SSL_CTX_new_ex() borrows the library context without taking ownership, meaning the SSL_CTX holds a non-owning pointer to the OSSL_LIB_CTX.
When curl_easy_cleanup() is called on the originating handle, ossl_close_all() frees data->state.libctx while the pooled connection's SSL_CTX still holds a pointer to it
Read the reasoning
curl_easy_cleanup() calls Curl_close() which (via the call chain) invokes ossl_close_all() → ossl_provider_cleanup() → OSSL_LIB_CTX_free(data->state.libctx). This frees the library context while the pooled connection's SSL_CTX still references it.
Any SSL operation on the reused SSL_CTX dereferences the freed OSSL_LIB_CTX, producing a heap-use-after-free
Read the reasoning
The connection pool reuses connections via Curl_ssl_conn_config_match → match_ssl_primary_config, which does not compare engine/provider settings. A second handle can reuse a pooled connection whose SSL_CTX embeds a pointer to the now-freed OSSL_LIB_CTX. Any SSL operation on that SSL_CTX will dereference the freed context, causing a heap-use-after-free. OpenSSL documentation confirms the library context must outlive every SSL_CTX that references it.
1. Build curl with OpenSSL 3.x and set CURLOPT_SSLENGINE to "default" 2. Perform a TLS connection with that handle 3. Clean up the handle while the connection remains pooled 4. Reuse the pooled connection with a second handle 5. Perform any SSL operation on the reused connection
Read the reasoning
The reproduction steps map to actual code paths: CURLOPT_SSLENGINE triggers ossl_set_provider; curl_easy_cleanup triggers ossl_provider_cleanup; curl_multi_remove_handle detaches the connection leaving it pooled; Curl_ssl_conn_config_match finds the pooled connection without comparing provider state.
The OSSL_LIB_CTX is freed in ossl_provider_cleanup() (line 1752) while the SSL_CTX that references it lives in the connection filter
Read the reasoning
ossl_provider_cleanup() unconditionally frees data->state.libctx at line 1752. The SSL_CTX created with this libctx resides in the connection filter (octx->ssl_ctx) and outlives the easy handle via connection pooling.
Deterministic checks that failed
- symbol ossl_connect_common exists in other curl releases but not at 7be1e70cb6bc
What the report says about other projects
confirmed SSL_CTX_new_ex() borrows the library context without taking ownership.
“SSL_CTX_new_ex() borrows the library context without taking ownership.” source
confirmed The OSSL_LIB_CTX must outlive every SSL_CTX that references it.
“The OSSL_LIB_CTX must outlive every SSL_CTX that references it.” source
Read the original report (excerpt)
Source code
| 1768 | static CURLcode ossl_set_provider(struct Curl_easy *data, const char *iname) |
| 1769 | { |
| 1770 | char name[MAX_PROVIDER_LEN + 1]; |
| 1771 | struct Curl_str prov; |
| 1772 | const char *propq = NULL; |
| 1773 | |
| 1774 | if(!iname) { |
| 1775 | /* clear and cleanup provider use */ |
| 1776 | ossl_provider_cleanup(data); |
| 1777 | return CURLE_OK; |
| 1778 | } |
| 1779 | if(curlx_str_until(&iname, &prov, MAX_PROVIDER_LEN, ':')) |
| 1780 | return CURLE_BAD_FUNCTION_ARGUMENT; |
| 1781 | |
| 1782 | if(!curlx_str_single(&iname, ':')) |
| 1783 | /* there was a colon, get the propq until the end of string */ |
| 1784 | propq = iname; |
| 1785 | |
| 1786 | /* we need the name in a buffer, null-terminated */ |
| 1787 | memcpy(name, curlx_str(&prov), curlx_strlen(&prov)); |
| 1788 | name[curlx_strlen(&prov)] = 0; |
| 1789 | |
| 1790 | if(!data->state.libctx) { |
| 1791 | OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new(); |
| C1: OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new(); | |
| 1792 | if(!libctx) |
| 1793 | return CURLE_OUT_OF_MEMORY; |
| 1794 | if(propq) { |
| 1795 | data->state.propq = curlx_strdup(propq); |
| 1796 | if(!data->state.propq) { |
| 1797 | OSSL_LIB_CTX_free(libctx); |
| 1798 | return CURLE_OUT_OF_MEMORY; |
| 1799 | } |
| 1800 | } |
| 1801 | data->state.libctx = libctx; |
| C1: data->state.libctx = libctx; | |
| 1802 | } |
| 1803 | |
| 1804 | #ifndef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG |
| 1805 | /* load the configuration file into the library context before checking the |
| 1806 | * provider availability */ |
| 1807 | if(!OSSL_LIB_CTX_load_config(data->state.libctx, NULL)) { |
| 1808 | infof(data, "Failed to load default openssl config. Proceeding."); |
| 1809 | } |
| 1810 | #endif |
| 1811 | |
| 1812 | if(OSSL_PROVIDER_available(data->state.libctx, name)) { |
| 1813 | /* already loaded through the configuration - no action needed */ |
| 1814 | data->state.provider_loaded = TRUE; |
| 1815 | return CURLE_OK; |
| 1816 | } |
| 1817 | |
| 1818 | data->state.provider = OSSL_PROVIDER_try_load(data->state.libctx, name, 1); |
| 1819 | if(!data->state.provider) { |
| 1820 | char error_buffer[256]; |
| 1821 | failf(data, "Failed to initialize provider: %s", |
| 1822 | ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer))); |
| 1823 | ossl_provider_cleanup(data); |
| 1824 | return CURLE_SSL_ENGINE_NOTFOUND; |
| 1825 | } |
| 1826 | |
| 1827 | /* load the base provider as well */ |
| 1828 | data->state.baseprov = OSSL_PROVIDER_try_load(data->state.libctx, "base", 1); |
| 1829 | if(!data->state.baseprov) { |
| 1830 | ossl_provider_cleanup(data); |
| 1831 | failf(data, "Failed to load base"); |
| 1832 | return CURLE_SSL_ENGINE_NOTFOUND; |
| 1833 | } |
| 1834 | else |
| 1835 | data->state.provider_loaded = TRUE; |
| 1836 | return CURLE_OK; |
| 1837 | } |
| 1989 | static void ossl_close_all(struct Curl_easy *data) |
| 1990 | { |
| 1991 | #ifdef USE_OPENSSL_ENGINE |
| 1992 | if(data->state.engine) { |
| 1993 | ENGINE_finish(data->state.engine); |
| 1994 | ENGINE_free(data->state.engine); |
| 1995 | data->state.engine = NULL; |
| 1996 | } |
| 1997 | #else |
| 1998 | (void)data; |
| 1999 | #endif |
| 2000 | #ifdef OPENSSL_HAS_PROVIDERS |
| 2001 | ossl_provider_cleanup(data); |
| C3: ossl_provider_cleanup(data); | |
| 2002 | #endif |
| 2003 | } |
| 1742 | static void ossl_provider_cleanup(struct Curl_easy *data) |
| C6: static void ossl_provider_cleanup(struct Curl_easy *data) | |
| 1743 | { |
| 1744 | if(data->state.baseprov) { |
| 1745 | OSSL_PROVIDER_unload(data->state.baseprov); |
| 1746 | data->state.baseprov = NULL; |
| 1747 | } |
| 1748 | if(data->state.provider) { |
| 1749 | OSSL_PROVIDER_unload(data->state.provider); |
| 1750 | data->state.provider = NULL; |
| 1751 | } |
| 1752 | OSSL_LIB_CTX_free(data->state.libctx); |
| C3: OSSL_LIB_CTX_free(data->state.libctx); | |
| C6: OSSL_LIB_CTX_free(data->state.libctx); | |
| 1753 | data->state.libctx = NULL; |
| 1754 | curlx_safefree(data->state.propq); |
| 1755 | data->state.provider_loaded = FALSE; |
| 1756 | } |
| 2935 | CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...) |
| 2936 | { |
| 2937 | va_list arg; |
| 2938 | CURLcode result; |
| 2939 | struct Curl_easy *data = curl; |
| 2940 | |
| 2941 | if(!data) |
| 2942 | return CURLE_BAD_FUNCTION_ARGUMENT; |
| 2943 | |
| 2944 | va_start(arg, option); |
| 2945 | |
| 2946 | result = Curl_vsetopt(data, option, arg); |
| C5: result = Curl_vsetopt(data, option, arg); | |
| 2947 | |
| 2948 | va_end(arg); |
| 2949 | if(result == CURLE_BAD_FUNCTION_ARGUMENT) |
| 2950 | failf(data, "setopt 0x%x got bad argument", (unsigned int)option); |
| 2951 | return result; |
| 2952 | } |
| 838 | void curl_easy_cleanup(CURL *curl) |
| 839 | { |
| 840 | struct Curl_easy *data = curl; |
| 841 | if(GOOD_EASY_HANDLE(data)) { |
| 842 | struct Curl_sigpipe_ctx sigpipe_ctx; |
| 843 | sigpipe_ignore(data, &sigpipe_ctx); |
| 844 | Curl_close(&data); |
| C3: Curl_close(&data); | |
| 845 | sigpipe_restore(&sigpipe_ctx); |
| 846 | } |
| 847 | } |
| 784 | CURLMcode curl_multi_remove_handle(CURLM *m, CURL *curl) |
| 785 | { |
| 786 | struct Curl_multi *multi = m; |
| 787 | struct Curl_easy *data = curl; |
| 788 | bool premature; |
| 789 | struct Curl_llist_node *e; |
| 790 | CURLMcode mresult; |
| 791 | uint32_t mid; |
| 792 | |
| 793 | /* First, make some basic checks that the CURLM handle is a good handle */ |
| 794 | if(!GOOD_MULTI_HANDLE(multi)) |
| 795 | return CURLM_BAD_HANDLE; |
| 796 | |
| 797 | /* Verify that we got a somewhat good easy handle too */ |
| 798 | if(!GOOD_EASY_HANDLE(data)) |
| 799 | return CURLM_BAD_EASY_HANDLE; |
| 800 | |
| 801 | /* Prevent users from trying to remove same easy handle more than once */ |
| 802 | if(!data->multi) |
| 803 | return CURLM_OK; /* it is already removed so let's say it is fine! */ |
| 804 | |
| 805 | /* Prevent users from trying to remove an easy handle from the wrong multi */ |
| 806 | if(data->multi != multi) |
| 807 | return CURLM_BAD_EASY_HANDLE; |
| 808 | |
| 809 | if(data->mid == UINT32_MAX) { |
| 810 | DEBUGASSERT(0); |
| 811 | return CURLM_INTERNAL_ERROR; |
| 812 | } |
| 813 | if(Curl_uint32_tbl_get(&multi->xfers, data->mid) != data) { |
| 814 | DEBUGASSERT(0); |
| 815 | return CURLM_INTERNAL_ERROR; |
| 816 | } |
| 817 | |
| 818 | if(multi->in_callback) |
| 819 | return CURLM_RECURSIVE_API_CALL; |
| 820 | |
| 821 | premature = (data->mstate < MSTATE_COMPLETED); |
| 822 | |
| 823 | /* If the 'state' is not INIT or COMPLETED, we might need to do something |
| 824 | nice to put the easy_handle in a good known state when this returns. */ |
| 825 | if(data->conn && |
| 826 | data->mstate > MSTATE_DO && |
| 827 | data->mstate < MSTATE_COMPLETED) { |
| 828 | /* Set connection owner so that the DONE function closes it. We can |
| 829 | safely do this here since connection is killed. */ |
| 830 | streamclose(data->conn, "Removed with partial response"); |
| 831 | } |
| 832 | |
| 833 | if(data->conn) { |
| 834 | /* multi_done() clears the association between the easy handle and the |
| 835 | connection. |
| 836 | |
| 837 | Note that this ignores the return code because there is |
| 838 | nothing really useful to do with it anyway! */ |
| 839 | (void)multi_done(data, data->result, premature); |
| 840 | } |
| 841 | |
| 842 | /* The timer must be shut down before data->multi is set to NULL, else the |
| 843 | timenode will remain in the splay tree after curl_easy_cleanup is |
| 844 | called. Do it after multi_done() in case that sets another time! */ |
| 845 | Curl_expire_clear(data); |
| 846 | |
| 847 | /* If in `msgsent`, it was deducted from `multi->xfers_alive` already. */ |
| 848 | if(!Curl_uint32_bset_contains(&multi->msgsent, data->mid)) |
| 849 | --multi->xfers_alive; |
| 850 | if(data->state.really_alive) { |
| 851 | data->state.really_alive = FALSE; |
| 852 | --multi->xfers_really_alive; |
| 853 | if(!multi->xfers_really_alive) |
| 854 | (void)multi_assess_wakeup(multi); |
| 855 | } |
| 856 | |
| 857 | Curl_wildcard_dtor(&data->wildcard); |
| 858 | |
| 859 | data->mstate = MSTATE_COMPLETED; |
| 860 | |
| 861 | /* Remove the association between the connection and the handle */ |
| 862 | Curl_detach_connection(data); |
| C5: Curl_detach_connection(data); | |
| 863 | |
| 864 | /* Tell event handling that this transfer is definitely going away */ |
| 865 | Curl_multi_ev_xfer_done(multi, data); |
| 866 | |
| 867 | if(data->set.connect_only && !data->multi_easy) { |
| 868 | /* This removes a handle that was part the multi interface that used |
| 869 | CONNECT_ONLY, that connection is now left alive but since this handle |
| 870 | has bits.close set nothing can use that transfer anymore and it is |
| 871 | forbidden from reuse. This easy handle cannot find the connection |
| 872 | anymore once removed from the multi handle |
| 873 | |
| 874 | Better close the connection here, at once. |
| 875 | */ |
| 876 | struct connectdata *c; |
| 877 | curl_socket_t s; |
| 878 | s = Curl_getconnectinfo(data, &c); |
| 879 | if((s != CURL_SOCKET_BAD) && c) { |
| 880 | Curl_conn_terminate(data, c, TRUE); |
| 881 | } |
| 882 | } |
| 883 | |
| 884 | if(data->state.lastconnect_id != -1) { |
| 885 | /* Mark any connect-only connection for closure */ |
| 886 | Curl_cpool_do_by_id(data, data->state.lastconnect_id, |
| 887 | close_connect_only, NULL); |
| 888 | } |
| 889 | |
| 890 | #ifdef USE_LIBPSL |
| 891 | /* Remove the PSL association. */ |
| 892 | if(data->psl == &multi->psl) |
| 893 | data->psl = NULL; |
| 894 | #endif |
| 895 | |
| 896 | /* make sure there is no pending message in the queue sent from this easy |
| 897 | handle */ |
| 898 | for(e = Curl_llist_head(&multi->msglist); e; e = Curl_node_next(e)) { |
| 899 | struct Curl_message *msg = Curl_node_elem(e); |
| 900 | |
| 901 | if(msg->extmsg.easy_handle == data) { |
| 902 | Curl_node_remove(e); |
| 903 | /* there can only be one from this specific handle */ |
| 904 | break; |
| 905 | } |
| 906 | } |
| 907 | |
| 908 | /* clear the association to this multi handle */ |
| 909 | mid = data->mid; |
| 910 | DEBUGASSERT(Curl_uint32_tbl_contains(&multi->xfers, mid)); |
| 911 | Curl_uint32_tbl_remove(&multi->xfers, mid); |
| 912 | Curl_uint32_bset_remove(&multi->process, mid); |
| 913 | Curl_uint32_bset_remove(&multi->dirty, mid); |
| 914 | Curl_uint32_bset_remove(&multi->pending, mid); |
| 915 | Curl_uint32_bset_remove(&multi->msgsent, mid); |
| 916 | data->multi = NULL; |
| 917 | data->mid = UINT32_MAX; |
| 918 | data->master_mid = UINT32_MAX; |
| 919 | |
| 920 | /* NOTE NOTE NOTE |
| 921 | We do not touch the easy handle here! */ |
| 922 | process_pending_handles(multi); |
| 923 | |
| 924 | mresult = Curl_update_timer(multi); |
| 925 | if(mresult) |
| 926 | return mresult; |
| 927 | |
| 928 | mresult = multi_assess_wakeup(multi); |
| 929 | if(mresult) { |
| 930 | failf(data, "error enabling wakeup listening: %d", mresult); |
| 931 | return mresult; |
| 932 | } |
| 933 | |
| 934 | CURL_TRC_M(data, "removed from multi, mid=%u, running=%u, total=%u", |
| 935 | mid, Curl_multi_xfers_running(multi), |
| 936 | Curl_uint32_tbl_count(&multi->xfers)); |
| 937 | return CURLM_OK; |
| 938 | } |
| 171 | bool Curl_ssl_conn_config_match(struct Curl_easy *data, |
| C5: Curl_ssl_conn_config_match calls match_ssl_primary_config | |
| 172 | struct connectdata *candidate, |
| 173 | bool proxy) |
| 174 | { |
| 175 | #ifndef CURL_DISABLE_PROXY |
| 176 | if(proxy) |
| 177 | return match_ssl_primary_config(data, &data->set.proxy_ssl.primary, |
| 178 | &candidate->proxy_ssl_config); |
| 179 | #else |
| 180 | (void)proxy; |
| 181 | #endif |
| 182 | return match_ssl_primary_config(data, &data->set.ssl.primary, |
| 183 | &candidate->ssl_config); |
| 184 | } |
| 136 | static bool match_ssl_primary_config(struct Curl_easy *data, |
| C4: match_ssl_primary_config does not compare engine or provider fields | |
| 137 | struct ssl_primary_config *c1, |
| 138 | struct ssl_primary_config *c2) |
| 139 | { |
| 140 | (void)data; |
| 141 | if((c1->version == c2->version) && |
| 142 | (c1->version_max == c2->version_max) && |
| 143 | (c1->ssl_options == c2->ssl_options) && |
| 144 | (c1->native_ca_store == c2->native_ca_store) && |
| 145 | (c1->verifypeer == c2->verifypeer) && |
| 146 | (c1->verifyhost == c2->verifyhost) && |
| 147 | (c1->verifystatus == c2->verifystatus) && |
| 148 | blobcmp(c1->cert_blob, c2->cert_blob) && |
| 149 | blobcmp(c1->ca_info_blob, c2->ca_info_blob) && |
| 150 | blobcmp(c1->issuercert_blob, c2->issuercert_blob) && |
| 151 | blobcmp(c1->key_blob, c2->key_blob) && |
| 152 | Curl_safecmp(c1->CApath, c2->CApath) && |
| 153 | Curl_safecmp(c1->CAfile, c2->CAfile) && |
| 154 | Curl_safecmp(c1->issuercert, c2->issuercert) && |
| 155 | Curl_safecmp(c1->clientcert, c2->clientcert) && |
| 156 | curl_strequal(c1->cipher_list, c2->cipher_list) && |
| 157 | curl_strequal(c1->cipher_list13, c2->cipher_list13) && |
| 158 | curl_strequal(c1->curves, c2->curves) && |
| 159 | curl_strequal(c1->signature_algorithms, c2->signature_algorithms) && |
| 160 | Curl_safecmp(c1->CRLfile, c2->CRLfile) && |
| 161 | Curl_safecmp(c1->pinned_key, c2->pinned_key) && |
| 162 | curl_strequal(c1->cert_type, c2->cert_type) && |
| 163 | Curl_safecmp(c1->key, c2->key) && |
| 164 | curl_strequal(c1->key_type, c2->key_type) && |
| 165 | !Curl_timestrcmp(c1->key_passwd, c2->key_passwd)) |
| 166 | return TRUE; |
| 167 | |
| 168 | return FALSE; |
| 169 | } |
| 4037 | static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, |
| 4038 | struct Curl_easy *data) |
| 4039 | { |
| 4040 | struct ssl_connect_data *connssl = cf->ctx; |
| 4041 | struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend; |
| 4042 | BIO *bio; |
| 4043 | CURLcode result; |
| 4044 | |
| 4045 | DEBUGASSERT(connssl->connecting_state == ssl_connect_1); |
| 4046 | DEBUGASSERT(octx); |
| 4047 | DEBUGASSERT(connssl->peer.origin); |
| 4048 | |
| 4049 | result = Curl_ossl_ctx_init(octx, cf, data, &connssl->peer, |
| C2: result = Curl_ossl_ctx_init(octx, cf, data, &connssl->peer, connssl->alpn, NULL, NULL, ossl_new_session_cb, cf, ossl_on_session_reuse); | |
| 4050 | connssl->alpn, NULL, NULL, |
| 4051 | ossl_new_session_cb, cf, |
| 4052 | ossl_on_session_reuse); |
| 4053 | if(result) |
| 4054 | return result; |
| 4055 | |
| 4056 | octx->bio_method = ossl_bio_cf_method_create(); |
| 4057 | if(!octx->bio_method) |
| 4058 | return CURLE_OUT_OF_MEMORY; |
| 4059 | bio = BIO_new(octx->bio_method); |
| 4060 | if(!bio) |
| 4061 | return CURLE_OUT_OF_MEMORY; |
| 4062 | |
| 4063 | BIO_set_data(bio, cf); |
| 4064 | #ifdef HAVE_SSL_SET0_WBIO |
| 4065 | /* with OpenSSL v1.1.1 we get an alternative to SSL_set_bio() that works |
| 4066 | * without backward compat quirks. Every call takes one reference, so we |
| 4067 | * up it and pass. SSL* then owns and frees it. |
| 4068 | * We check on the function in configure, since LibreSSL and friends |
| 4069 | * each have their own versions to add support for this. */ |
| 4070 | BIO_up_ref(bio); |
| 4071 | SSL_set0_rbio(octx->ssl, bio); |
| 4072 | SSL_set0_wbio(octx->ssl, bio); |
| 4073 | #else |
| 4074 | SSL_set_bio(octx->ssl, bio, bio); |
| 4075 | #endif |
| 4076 | |
| 4077 | if(connssl->alpn && (connssl->state != ssl_connection_deferred)) { |
| 4078 | struct alpn_proto_buf proto; |
| 4079 | memset(&proto, 0, sizeof(proto)); |
| 4080 | Curl_alpn_to_proto_str(&proto, connssl->alpn); |
| 4081 | infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); |
| 4082 | } |
| 4083 | |
| 4084 | connssl->connecting_state = ssl_connect_2; |
| 4085 | return CURLE_OK; |
| 4086 | } |
| 1658 | static CURLcode ossl_set_engine(struct Curl_easy *data, const char *name) |
| 1659 | { |
| 1660 | #ifdef USE_OPENSSL_ENGINE |
| 1661 | CURLcode result = CURLE_SSL_ENGINE_NOTFOUND; |
| 1662 | ENGINE *e = ENGINE_by_id(name); |
| 1663 | |
| 1664 | if(e) { |
| 1665 | |
| 1666 | if(data->state.engine) { |
| 1667 | ENGINE_finish(data->state.engine); |
| 1668 | ENGINE_free(data->state.engine); |
| 1669 | data->state.engine = NULL; |
| 1670 | } |
| 1671 | if(!ENGINE_init(e)) { |
| 1672 | char buf[256]; |
| 1673 | |
| 1674 | ENGINE_free(e); |
| 1675 | failf(data, "Failed to initialize SSL Engine '%s': %s", |
| 1676 | name, ossl_strerror(ERR_get_error(), buf, sizeof(buf))); |
| 1677 | result = CURLE_SSL_ENGINE_INITFAILED; |
| 1678 | e = NULL; |
| 1679 | } |
| 1680 | else { |
| 1681 | result = CURLE_OK; |
| 1682 | } |
| 1683 | data->state.engine = e; |
| 1684 | return result; |
| 1685 | } |
| 1686 | #endif |
| 1687 | #ifdef OPENSSL_HAS_PROVIDERS |
| 1688 | return ossl_set_provider(data, name); |
| C5: return ossl_set_provider(data, name); | |
| 1689 | #else |
| 1690 | (void)name; |
| 1691 | failf(data, "OpenSSL engine not found"); |
| 1692 | return CURLE_SSL_ENGINE_NOTFOUND; |
| 1693 | #endif |
| 1694 | } |
Show 20 lines (not cited by the judge)
| 2928 | CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...) |
| 2929 | { |
| 2930 | struct Curl_eapi_guard guard; |
| 2931 | CURLcode result; |
| 2932 | |
| 2933 | if(CURL_EAPI_ENTER(&guard, curl, easy_setopt, &result)) { |
| 2934 | struct Curl_easy *data = curl; |
| 2935 | va_list arg; |
| 2936 | |
| 2937 | va_start(arg, option); |
| 2938 | |
| 2939 | result = Curl_vsetopt(data, option, arg); |
| 2940 | |
| 2941 | va_end(arg); |
| 2942 | if(result == CURLE_BAD_FUNCTION_ARGUMENT) |
| 2943 | failf(data, "setopt 0x%x got bad argument", (unsigned int)option); |
| 2944 | } |
| 2945 | CURL_EAPI_LEAVE(&guard); |
| 2946 | return result; |
| 2947 | } |
Show 13 lines (not cited by the judge)
| 850 | void curl_easy_cleanup(CURL *curl) |
| 851 | { |
| 852 | struct Curl_eapi_guard guard; |
| 853 | |
| 854 | if(CURL_EAPI_ENTER(&guard, curl, easy_cleanup, NULL)) { |
| 855 | struct Curl_easy *data = curl; |
| 856 | struct Curl_sigpipe_ctx sigpipe_ctx; |
| 857 | sigpipe_ignore(data, &sigpipe_ctx); |
| 858 | Curl_close(&data); |
| 859 | sigpipe_restore(&sigpipe_ctx); |
| 860 | } |
| 861 | CURL_EAPI_LEAVE(&guard); |
| 862 | } |
Show 15 lines (not cited by the judge)
| 910 | CURLMcode curl_multi_remove_handle(CURLM *m, CURL *curl) |
| 911 | { |
| 912 | struct Curl_mapi_guard guard; |
| 913 | CURLMcode mresult; |
| 914 | |
| 915 | if(CURL_MAPI_ENTER(&guard, m, multi_remove_handle, &mresult)) { |
| 916 | struct Curl_easy *data = curl; |
| 917 | if(!GOOD_EASY_HANDLE(data)) |
| 918 | mresult = CURLM_BAD_EASY_HANDLE; |
| 919 | else |
| 920 | mresult = Curl_multi_remove_handle(m, data); |
| 921 | } |
| 922 | CURL_MAPI_LEAVE(&guard); |
| 923 | return mresult; |
| 924 | } |
Show 6 lines (not cited by the judge)
| 260 | CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine) |
| 261 | { |
| 262 | if(Curl_ssl->set_engine) |
| 263 | return Curl_ssl->set_engine(data, engine); |
| 264 | return CURLE_NOT_BUILT_IN; |
| 265 | } |
Show 1 lines (not cited by the judge)
| 102 | #define OPENSSL_HAS_PROVIDERS |
Show 37 lines (not cited by the judge)
| 144 | static bool match_ssl_primary_config(struct Curl_easy *data, |
| 145 | struct ssl_primary_config *c1, |
| 146 | struct ssl_primary_config *c2) |
| 147 | { |
| 148 | (void)data; |
| 149 | if((c1->version == c2->version) && |
| 150 | (c1->version_max == c2->version_max) && |
| 151 | (c1->ssl_options == c2->ssl_options) && |
| 152 | (c1->verifypeer == c2->verifypeer) && |
| 153 | (c1->verifyhost == c2->verifyhost) && |
| 154 | (c1->verifystatus == c2->verifystatus) && |
| 155 | blobcmp(c1->cert_blob, c2->cert_blob) && |
| 156 | blobcmp(c1->ca_info_blob, c2->ca_info_blob) && |
| 157 | blobcmp(c1->issuercert_blob, c2->issuercert_blob) && |
| 158 | blobcmp(c1->key_blob, c2->key_blob) && |
| 159 | Curl_safecmp(c1->CApath, c2->CApath) && |
| 160 | Curl_safecmp(c1->CAfile, c2->CAfile) && |
| 161 | Curl_safecmp(c1->issuercert, c2->issuercert) && |
| 162 | Curl_safecmp(c1->clientcert, c2->clientcert) && |
| 163 | #ifdef USE_TLS_SRP |
| 164 | !Curl_timestrcmp(c1->username, c2->username) && |
| 165 | !Curl_timestrcmp(c1->password, c2->password) && |
| 166 | #endif |
| 167 | curl_strequal(c1->cipher_list, c2->cipher_list) && |
| 168 | curl_strequal(c1->cipher_list13, c2->cipher_list13) && |
| 169 | curl_strequal(c1->curves, c2->curves) && |
| 170 | curl_strequal(c1->signature_algorithms, c2->signature_algorithms) && |
| 171 | Curl_safecmp(c1->CRLfile, c2->CRLfile) && |
| 172 | Curl_safecmp(c1->pinned_key, c2->pinned_key) && |
| 173 | curl_strequal(c1->cert_type, c2->cert_type) && |
| 174 | Curl_safecmp(c1->key, c2->key) && |
| 175 | curl_strequal(c1->key_type, c2->key_type) && |
| 176 | !Curl_timestrcmp(c1->key_passwd, c2->key_passwd)) |
| 177 | return TRUE; |
| 178 | |
| 179 | return FALSE; |
| 180 | } |
Show 23 lines (not cited by the judge)
| 1961 | static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data) |
| 1962 | { |
| 1963 | struct ssl_connect_data *connssl = cf->ctx; |
| 1964 | struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend; |
| 1965 | |
| 1966 | (void)data; |
| 1967 | DEBUGASSERT(octx); |
| 1968 | |
| 1969 | connssl->input_pending = FALSE; |
| 1970 | if(octx->ssl) { |
| 1971 | SSL_free(octx->ssl); |
| 1972 | octx->ssl = NULL; |
| 1973 | } |
| 1974 | if(octx->ssl_ctx) { |
| 1975 | SSL_CTX_free(octx->ssl_ctx); |
| 1976 | octx->ssl_ctx = NULL; |
| 1977 | octx->x509_store_setup = FALSE; |
| 1978 | } |
| 1979 | if(octx->bio_method) { |
| 1980 | ossl_bio_cf_method_free(octx->bio_method); |
| 1981 | octx->bio_method = NULL; |
| 1982 | } |
| 1983 | } |
Show 50 lines (not cited by the judge)
| 4009 | static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, |
| 4010 | struct Curl_easy *data) |
| 4011 | { |
| 4012 | struct ssl_connect_data *connssl = cf->ctx; |
| 4013 | struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend; |
| 4014 | BIO *bio; |
| 4015 | CURLcode result; |
| 4016 | |
| 4017 | DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); |
| 4018 | DEBUGASSERT(octx); |
| 4019 | DEBUGASSERT(connssl->peer.origin); |
| 4020 | |
| 4021 | result = Curl_ossl_ctx_init(octx, cf, data, &connssl->peer, |
| 4022 | connssl->alpn, NULL, NULL, |
| 4023 | ossl_new_session_cb, cf, |
| 4024 | ossl_on_session_reuse); |
| 4025 | if(result) |
| 4026 | return result; |
| 4027 | |
| 4028 | octx->bio_method = ossl_bio_cf_method_create(); |
| 4029 | if(!octx->bio_method) |
| 4030 | return CURLE_OUT_OF_MEMORY; |
| 4031 | bio = BIO_new(octx->bio_method); |
| 4032 | if(!bio) |
| 4033 | return CURLE_OUT_OF_MEMORY; |
| 4034 | |
| 4035 | BIO_set_data(bio, cf); |
| 4036 | #ifdef HAVE_SSL_SET0_WBIO |
| 4037 | /* with OpenSSL v1.1.1 we get an alternative to SSL_set_bio() that works |
| 4038 | * without backward compat quirks. Every call takes one reference, so we |
| 4039 | * up it and pass. SSL* then owns and frees it. |
| 4040 | * We check on the function in configure, since LibreSSL and friends |
| 4041 | * each have their own versions to add support for this. */ |
| 4042 | BIO_up_ref(bio); |
| 4043 | SSL_set0_rbio(octx->ssl, bio); |
| 4044 | SSL_set0_wbio(octx->ssl, bio); |
| 4045 | #else |
| 4046 | SSL_set_bio(octx->ssl, bio, bio); |
| 4047 | #endif |
| 4048 | |
| 4049 | if(connssl->alpn && (connssl->state != ssl_connection_deferred)) { |
| 4050 | struct alpn_proto_buf proto; |
| 4051 | memset(&proto, 0, sizeof(proto)); |
| 4052 | Curl_alpn_to_proto_str(&proto, connssl->alpn); |
| 4053 | infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); |
| 4054 | } |
| 4055 | |
| 4056 | connssl->connecting_state = ssl_connect_2; |
| 4057 | return CURLE_OK; |
| 4058 | } |