✓ProveIt
Examples / Report #3993870 Saved analysis

CVE-2026-86415: auto client cert connection reuse mixup

curl · 2026-09-0317.8s analysis · $0.026 in model calls

What the report claims

libcurl's connection cache reuses a Schannel connection authenticated with a client certificate to a different origin after a redirect, bypassing the per-request auto_client_cert=FALSE check.

Compare with curl's recorded outcome

Known vulnerability

A real vulnerability: CVE-2026-86415 auto client cert connection reuse mixup

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?
  • auto_client_cert is computed per-request based on origin vs initial_origin (vtls_config.c:236-238) to prevent presenting client certs to redirected hosts
  • Connection cache matcher (match_ssl_primary_config) only compares ssl_primary_config fields, which excludes auto_client_cert (vtls_config.c:136-169, vtls_config.h:62-79, urldata.h:322)
  • A redirect from attacker-controlled host A to host B causes reuse of B's cached authenticated connection because the matcher doesn't see that auto_client_cert should be FALSE for the redirected request
  • Schannel uses auto_client_cert at handshake time (schannel.c:783-786, 981) but connection reuse bypasses handshake entirely
  • The flaw was introduced by commit d69bfad3fa3daf5e72331f6870667607828d5891 which added the per-origin check but didn't update the matcher, and persists at master (e26f6e408a80)
How this analysis ran 5 claims · 17 citations verified

Checked against curl master on 2026-09-03 (e26f6e408a80). 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
grounded
no model · 43 references checked out, 0 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 2934 tokens · $0.0003
3 · Evidence
17 code snippets
real curl source at e26f6e408a80 · 1 docs via Tavily
4 · Judgment
Nemotron-3-Ultra-550b-a55b
19606 tokens · 13.9s · $0.0255
5 · Receipts
17 of 17 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 code confirms the flaw: `auto_client_cert` is correctly derived per-request to block client certs on redirects (vtls_config.c:236-238), but `match_ssl_primary_config()` only compares `ssl_primary_config` fields (vtls_config.c:136-169), which lacks this flag. A cached Schannel connection established with `auto_client_cert=TRUE` can be reused for a redirected request where it should be `FALSE`, bypassing the handshake where Schannel would suppress the cert (schannel.c:783-786, 981). This is a valid security issue on Windows/Schannel with `CURLSSLOPT_AUTO_CLIENT_CERT`.

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

Report claims

C1flaw supported

The connection cache matcher never checks the per-request auto_client_cert flag, allowing reuse of a cached connection that was established with auto_client_cert=TRUE for a request that should have auto_client_cert=FALSE.

Read the reasoning

The code confirms auto_client_cert is derived per-request (line 236-238) but connection matching only uses ssl_primary_config which lacks this field. The raw ssl_options bitmask is compared but it doesn't capture the per-origin derivation.

C2location supported

The flag auto_client_cert is stored in struct ssl_config_data but connections are matched using only struct ssl_primary_config, so match_ssl_primary_config() cannot distinguish differing auto_client_cert values.

Read the reasoning

The struct layout shows auto_client_cert is in ssl_config_data but not in ssl_primary_config, and connections only retain the primary struct. The matcher therefore cannot see auto_client_cert.

C3trigger supported

A redirect from an attacker-controlled host causes a request to reuse an existing cached connection to a different host that was established with client certificate authentication.

Read the reasoning

A redirect changes origin but not initial_origin, so auto_client_cert becomes FALSE for the redirected request. However, the connection matcher doesn't check this flag, so a cached connection established with auto_client_cert=TRUE (for initial_origin) can be reused.

C4impact supported

The client certificate is sent to the original host (B) instead of the redirect target (A), allowing the attacker to obtain resources or actions intended for the authenticated host.

Read the reasoning

When a cached connection is reused, no new handshake occurs, so the schannel flags that would suppress client cert presentation are never evaluated. The attacker-controlled redirect target (A) causes reuse of B's authenticated session, letting A steer authenticated requests to B.

C5reproduction supported

Create a redirect chain that leads to a host B for which a cached Schannel connection with auto_client_cert=TRUE exists, then follow the redirect with a client that has CURLSSLOPT_AUTO_CLIENT_CERT set; the cached connection is reused without a new handshake.

Read the reasoning

The reproduction steps follow directly from the code: establish a connection to B with auto_client_cert=TRUE (B == initial_origin), then have A redirect to B. The redirected request computes auto_client_cert=FALSE but the matcher ignores it, reusing B's authenticated connection.

Read the original report (excerpt)

Full report on HackerOne ↗

Howdy, libcurl's connection-cache matcher never checks `auto_client_cert`, so a cached, already-authenticated Schannel connection can be handed to a transfer that just got redirected to a different origin, even though the code explicitly computed `auto_client_cert = FALSE` for that transfer to prevent exactly this. ## The bug `Curl_ssl_easy_config_complete()` recomputes the effective SSL config for every request, including a request that is the result of following a `Location:` redirect. Part of that is deciding whether the automatically-selected client certificate applies: ```c // lib/vtls/vtls_config.c:236-238 sslc->auto_client_cert = Curl_peer_equal(origin, initial_origin) && !!(options & CURLSSLOPT_AUTO_CLIENT_CERT); ``` `initial_origin` is the origin of the very first URL of the `curl_easy_perform()`, set once and kept for the whole redirect chain. So the moment a redirect takes the transfer to a different host, `auto_client_cert` is correctly forced to `FALSE` — the client shouldn't auto-present a certificate to a host it wasn't explicitly pointed at. The problem is that this flag lives in `struct ssl_config_data`, not in `struct ssl_primary_config`: ```c // lib/vtls/vtls_config.h:74-75 BIT(auto_client_cert); /* automatically locate and use a client certificate for authentication (Schannel) */ ``` and connections in the pool only ever retain the primary struct: ```c // lib/urldata.h:322 struct ssl_primary_config ssl_config; ``` Connection reuse is decided by `match_ssl_primary_config()`, which takes two `ssl_primary_config *` and therefore has no way to see `auto_client_cert` even in principle: ```c // lib/vtls/vtls_config.c:136-146 static bool match_ssl_primary_config(struct Curl_easy *data, struct ssl_primary_config *c1, struct ssl_primary_config *c2) { (void)data; if((c1->version == c2->version) && (c1->version_max == c2->version_max) && (c1->ssl_options == c2->ssl_options) && (c1->native_ca_store == c2->native_ca_store) && (c1->verifypeer == c2->verifypeer) && (c1->verifyhost == c2->verifyhost) && ``` `ssl_options` (the raw `CURLOPT_SSL_OPTIONS` bitmask, including the `CURLSSLOPT_AUTO_CLIENT_CERT` bit) is identical on every request from the same easy handle, so it always matches. T …

Source code

lib/vtls/vtls_config.clines 211–363 · lines 236-238 cited by the report; definition of Curl_ssl_easy_config_complete
211 CLONE_STRING(CRLfile);
212 /* SSL credentials: client certificate */
213 CLONE_STRING(clientcert);
214 CLONE_STRING(cert_type);
215 CLONE_STRING(key);
216 CLONE_STRING(key_type);
217 CLONE_STRING(key_passwd);
218 CLONE_BLOB(key_blob);
219 return TRUE;
220}
221
222static void ssl_easy_config_compl_options(struct Curl_peer *origin,
223 struct Curl_peer *initial_origin,
224 struct ssl_config_data *sslc)
225{
226 uint8_t options = sslc->primary.ssl_options;
227 /* If set via CURLOPT_(PROXY_)SSL_OPTIONS, we definitely use it.
228 * If not, we switch it on for supported backends if no custom
229 * CA settings exist. */
230 sslc->primary.native_ca_store = !!(options & CURLSSLOPT_NATIVE_CA);
231 sslc->enable_beast = !!(options & CURLSSLOPT_ALLOW_BEAST);
232 sslc->no_partialchain = !!(options & CURLSSLOPT_NO_PARTIALCHAIN);
233 sslc->no_revoke = !!(options & CURLSSLOPT_NO_REVOKE);
234 sslc->revoke_best_effort = !!(options & CURLSSLOPT_REVOKE_BEST_EFFORT);
235 sslc->earlydata = !!(options & CURLSSLOPT_EARLYDATA);
236
C1: auto_client_cert computed per-request based on origin vs initial_origin
C3: auto_client_cert becomes FALSE when origin != initial_origin
C5: auto_client_cert derivation
237 sslc->auto_client_cert = Curl_peer_equal(origin, initial_origin) &&
238 !!(options & CURLSSLOPT_AUTO_CLIENT_CERT);
239}
240
241static char *ssl_easy_steal(struct Curl_easy *data, enum dupstring id)
242{
243 /* For connection matching, we borrow string references from data
244 * THIS IS NOT REALLY NICE. */
245 return CURL_UNCONST(CURL_EASY_STR(data, id));
246}
247
248CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data,
249 struct Curl_peer *origin)
250{
251 struct ssl_config_data *sslc = &data->set.ssl;
252#if defined(CURL_CA_PATH) || defined(CURL_CA_BUNDLE)
253 CURLcode result;
254#endif
255
256 ssl_easy_config_compl_options(origin, data->state.initial_origin, sslc);
257
258 if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
259#if defined(USE_APPLE_SECTRUST) || defined(CURL_CA_NATIVE)
260 if(!sslc->custom_capath && !sslc->custom_cafile && !sslc->custom_cablob)
261 sslc->primary.native_ca_store = TRUE;
262#endif
263#ifdef CURL_CA_PATH
264 if(!sslc->custom_capath && !CURL_EASY_STR(data, STRING_SSL_CAPATH)) {
265 result = Curl_setstropt(data, STRING_SSL_CAPATH, CURL_CA_PATH);
266 if(result)
267 return result;
268 }
269#endif
270#ifdef CURL_CA_BUNDLE
271 if(!sslc->custom_cafile && !CURL_EASY_STR(data, STRING_SSL_CAFILE)) {
272 result = Curl_setstropt(data, STRING_SSL_CAFILE, CURL_CA_BUNDLE);
273 if(result)
274 return result;
275 }
276#endif
277 }
278 sslc->primary.CAfile = ssl_easy_steal(data, STRING_SSL_CAFILE);
279 sslc->primary.CRLfile = ssl_easy_steal(data, STRING_SSL_CRLFILE);
280 sslc->primary.CApath = ssl_easy_steal(data, STRING_SSL_CAPATH);
281 sslc->primary.cipher_list = ssl_easy_steal(data, STRING_SSL_CIPHER_LIST);
282 sslc->primary.cipher_list13 = ssl_easy_steal(data, STRING_SSL_CIPHER13_LIST);
283 sslc->primary.signature_algorithms =
284 ssl_easy_steal(data, STRING_SSL_SIGNATURE_ALGORITHMS);
285 sslc->primary.ca_info_blob = data->set.blobs[BLOB_CAINFO];
286 sslc->primary.curves = ssl_easy_steal(data, STRING_SSL_EC_CURVES);
287 /* Maybe these should not be used for another origin. But for
288 * backwards compatibility, keep them in. */
289 sslc->primary.issuercert = ssl_easy_steal(data, STRING_SSL_ISSUERCERT);
290 sslc->primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
291
292 if(Curl_peer_equal(data->state.initial_origin, origin)) {
293 sslc->primary.pinned_key =
294 ssl_easy_steal(data, STRING_SSL_PINNEDPUBLICKEY);
295 sslc->primary.cert_blob = data->set.blobs[BLOB_CERT];
296 sslc->primary.cert_type = ssl_easy_steal(data, STRING_CERT_TYPE);
297 sslc->primary.key = ssl_easy_steal(data, STRING_KEY);
298 sslc->primary.key_type = ssl_easy_steal(data, STRING_KEY_TYPE);
299 sslc->primary.key_passwd = ssl_easy_steal(data, STRING_KEY_PASSWD);
300 sslc->primary.clientcert = ssl_easy_steal(data, STRING_CERT);
301 sslc->primary.key_blob = data->set.blobs[BLOB_KEY];
302 }
303 else {
304 sslc->primary.pinned_key = NULL;
305 sslc->primary.cert_blob = NULL;
306 sslc->primary.cert_type = NULL;
307 sslc->primary.key = NULL;
308 sslc->primary.key_type = NULL;
309 sslc->primary.key_passwd = NULL;
310 sslc->primary.clientcert = NULL;
311 sslc->primary.key_blob = NULL;
312 }
313
314#ifndef CURL_DISABLE_PROXY
315 sslc = &data->set.proxy_ssl;
316 /* no initial origin for proxy, it is not changed for redirects */
317 ssl_easy_config_compl_options(NULL, NULL, sslc);
318
319 if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
320#if defined(USE_APPLE_SECTRUST) || defined(CURL_CA_NATIVE)
321 if(!sslc->custom_capath && !sslc->custom_cafile && !sslc->custom_cablob)
322 sslc->primary.native_ca_store = TRUE;
323#endif
324#ifdef CURL_CA_PATH
325 if(!sslc->custom_capath &&
326 !CURL_EASY_STR(data, STRING_SSL_CAPATH_PROXY)) {
327 result = Curl_setstropt(data, STRING_SSL_CAPATH_PROXY, CURL_CA_PATH);
328 if(result)
329 return result;
330 }
331#endif
332#ifdef CURL_CA_BUNDLE
333 if(!sslc->custom_cafile &&
334 !CURL_EASY_STR(data, STRING_SSL_CAFILE_PROXY)) {
335 result = Curl_setstropt(data, STRING_SSL_CAFILE_PROXY, CURL_CA_BUNDLE);
336 if(result)
337 return result;
338 }
339#endif
340 }
341 sslc->primary.CAfile = ssl_easy_steal(data, STRING_SSL_CAFILE_PROXY);
342 sslc->primary.CApath = ssl_easy_steal(data, STRING_SSL_CAPATH_PROXY);
343 sslc->primary.cipher_list =
344 ssl_easy_steal(data, STRING_SSL_CIPHER_LIST_PROXY);
345 sslc->primary.cipher_list13 =
346 ssl_easy_steal(data, STRING_SSL_CIPHER13_LIST_PROXY);
347 sslc->primary.pinned_key =
348 ssl_easy_steal(data, STRING_SSL_PINNEDPUBLICKEY_PROXY);
349 sslc->primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
350 sslc->primary.ca_info_blob = data->set.blobs[BLOB_CAINFO_PROXY];
351 sslc->primary.issuercert = ssl_easy_steal(data, STRING_SSL_ISSUERCERT_PROXY);
352 sslc->primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY];
353 sslc->primary.CRLfile = ssl_easy_steal(data, STRING_SSL_CRLFILE_PROXY);
354 sslc->primary.cert_type = ssl_easy_steal(data, STRING_CERT_TYPE_PROXY);
355 sslc->primary.key = ssl_easy_steal(data, STRING_KEY_PROXY);
356 sslc->primary.key_type = ssl_easy_steal(data, STRING_KEY_TYPE_PROXY);
357 sslc->primary.key_passwd = ssl_easy_steal(data, STRING_KEY_PASSWD_PROXY);
358 sslc->primary.clientcert = ssl_easy_steal(data, STRING_CERT_PROXY);
359 sslc->primary.key_blob = data->set.blobs[BLOB_KEY_PROXY];
360#endif /* CURL_DISABLE_PROXY */
361
362 return CURLE_OK;
363}
lib/vtls/vtls_config.hlines 49–100 · lines 74-75 cited by the report
49 struct curl_blob *key_blob;
50 char *curves; /* list of curves to use */
51 uint32_t version_max; /* max supported version the client wants to use */
52 uint8_t ssl_options; /* the CURLOPT_SSL_OPTIONS bitmask */
53 uint8_t version; /* what version the client wants to use */
54 BIT(verifypeer); /* set TRUE if this is desired */
55 BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */
56 BIT(verifystatus); /* set TRUE if certificate status must be checked */
57 BIT(native_ca_store); /* use the native CA store of operating system */
58 BIT(cache_session); /* cache session or not */
59 BIT(deep_copy); /* members are deep copies, eg. owned here */
60};
61
62struct ssl_config_data {
C2: ssl_config_data contains primary (ssl_primary_config) and auto_client_cert as separate fields
63 struct ssl_primary_config primary;
64 long certverifyresult; /* result from the certificate verification */
65 curl_ssl_ctx_callback fsslctx; /* function to initialize SSL ctx */
66 void *fsslctxp; /* parameter for call back */
67 BIT(certinfo); /* gather lots of certificate info */
68 BIT(earlydata); /* use TLS 1.3 early data */
69 BIT(enable_beast); /* allow this flaw for interoperability's sake */
70 BIT(no_revoke); /* disable SSL certificate revocation checks */
71 BIT(no_partialchain); /* do not accept partial certificate chains */
72 BIT(revoke_best_effort); /* ignore SSL revocation offline/missing revocation
73 list errors */
74 BIT(auto_client_cert); /* automatically locate and use a client
C1: auto_client_cert defined in ssl_config_data, not ssl_primary_config
75 certificate for authentication (Schannel) */
76 BIT(custom_cafile); /* application has set custom CA file */
77 BIT(custom_capath); /* application has set custom CA path */
78 BIT(custom_cablob); /* application has set custom CA blob */
79};
80
81struct ssl_general_config {
82 int ca_cache_timeout; /* Certificate store cache timeout (seconds) */
83};
84
85void Curl_ssl_config_init(struct ssl_primary_config *sslc);
86void Curl_ssl_config_cleanup(struct ssl_primary_config *sslc);
87
88/**
89 * Init the `data->set.ssl` and `data->set.proxy_ssl` for
90 * connection matching use.
91 */
92CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data,
93 struct Curl_peer *origin);
94
95/**
96 * Init SSL configs (main + proxy) for a new connection from the easy handle.
97 */
98CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data,
99 struct connectdata *conn);
100
lib/urldata.hlines 297–347 · lines 322-322 cited by the report
297 timediff_t lastchecked_ms; /* when last checked alive status */
298 timediff_t lastupkeep_ms; /* when last done conn_upkeep */
299
300#ifndef CURL_DISABLE_PROXY
301 struct proxy_info socks_proxy;
302 struct proxy_info http_proxy;
303#endif
304
305 struct Curl_cfilter *cfilter[2]; /* connection filters */
306 Curl_recv *recv[2];
307 Curl_send *send[2];
308 /* A connection can have one or two sockets and connection filters.
309 * The protocol using the 2nd one is FTP for CONTROL+DATA sockets */
310 curl_socket_t sock[2];
311
312#define CONN_SOCK_IDX_VALID(i) (((i) >= 0) && ((i) < 2))
313
314 struct {
315 timediff_t start_ms[2]; /* when filter shutdown started */
316 timediff_t timeout_ms; /* 0 means no timeout */
317 } shutdown;
318
319 curl_closesocket_callback fclosesocket; /* function closing the socket(s) */
320 void *closesocket_client;
321
322 struct ssl_primary_config ssl_config;
C1: connection stores only ssl_primary_config
C2: connectdata has only ssl_primary_config ssl_config
323#ifndef CURL_DISABLE_PROXY
324 struct ssl_primary_config proxy_ssl_config;
325#endif
326 char *options; /* options string, allocated */
327
328 /*************** Request - specific items ************/
329#ifdef USE_WINDOWS_SSPI
330 CtxtHandle *sslContext;
331#endif
332
333#ifdef USE_NTLM
334 curlntlm http_ntlm_state;
335 curlntlm proxy_ntlm_state;
336#endif
337
338#ifdef USE_SPNEGO
339 curlnegotiate http_negotiate_state;
340 curlnegotiate proxy_negotiate_state;
341#endif
342
343 /* When this connection is created, store the conditions for the local end
344 bind. This is stored before the actual bind and before any connection is
345 made and will serve the purpose of being used for comparison reasons so
346 that subsequent bound-requested connections are not accidentally reusing
347 wrong connections. */
lib/vtls/vtls_config.clines 111–184 · lines 136-146 cited by the report; definition of Curl_ssl_conn_config_match
111void Curl_ssl_config_cleanup(struct ssl_primary_config *sslc)
112{
113 if(sslc->deep_copy) {
114 curlx_safefree(sslc->CApath);
115 curlx_safefree(sslc->CAfile);
116 curlx_safefree(sslc->issuercert);
117 curlx_safefree(sslc->clientcert);
118 curlx_safefree(sslc->cipher_list);
119 curlx_safefree(sslc->cipher_list13);
120 curlx_safefree(sslc->pinned_key);
121 curlx_safefree(sslc->cert_blob);
122 curlx_safefree(sslc->ca_info_blob);
123 curlx_safefree(sslc->issuercert_blob);
124 curlx_safefree(sslc->key_blob);
125 curlx_safefree(sslc->curves);
126 curlx_safefree(sslc->signature_algorithms);
127 curlx_safefree(sslc->CRLfile);
128 curlx_safefree(sslc->cert_type);
129 curlx_safefree(sslc->key);
130 curlx_safefree(sslc->key_type);
131 curlx_safefree(sslc->key_passwd);
132 sslc->deep_copy = FALSE;
133 }
134}
135
136static bool match_ssl_primary_config(struct Curl_easy *data,
C1: match_ssl_primary_config only compares ssl_primary_config fields, not auto_client_cert
C2: match_ssl_primary_config signature takes ssl_primary_config*
C3: matcher doesn't check auto_client_cert
C4: cached connection reuse bypasses handshake where these flags would apply
C5: matcher omission
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}
170
171bool Curl_ssl_conn_config_match(struct Curl_easy *data,
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}
lib/http.clines 3389–3464 · lines 3414-3439 cited by the report
3389 }
3390 else if(k->httpcode < 300)
3391 data->state.resume_from = 0; /* get everything */
3392 }
3393 return CURLE_OK;
3394}
3395
3396/*
3397 * http_header_l() parses a single response header starting with L.
3398 */
3399static CURLcode http_header_l(struct Curl_easy *data,
3400 const char *hd, size_t hdlen)
3401{
3402 struct connectdata *conn = data->conn;
3403 struct SingleRequest *k = &data->req;
3404 const char *v = (!k->http_bodyless &&
3405 (data->set.timecondition || data->set.get_filetime)) ?
3406 HD_VAL(hd, hdlen, "Last-Modified:") : NULL;
3407 if(v) {
3408 if(Curl_getdate_capped(v, &k->timeofdoc))
3409 k->timeofdoc = 0;
3410 if(data->set.get_filetime)
3411 data->info.filetime = k->timeofdoc;
3412 return CURLE_OK;
3413 }
3414 if(HD_IS(hd, hdlen, "Location:")) {
C3: http_header_l handles Location: header for redirects
C5: redirect handling in http_header_l
3415 /* this is the URL that the server advises us to use instead */
3416 char *location = Curl_copy_header_value(hd);
3417 if(!location)
3418 return CURLE_OUT_OF_MEMORY;
3419 if(!*location ||
3420 (data->req.location && !strcmp(data->req.location, location))) {
3421 /* ignore empty header, or exact repeat of a previous one */
3422 curlx_free(location);
3423 return CURLE_OK;
3424 }
3425 else {
3426 /* has value and is not an exact repeat */
3427 if(data->req.location) {
3428 failf(data, "Multiple Location headers");
3429 curlx_free(location);
3430 return CURLE_WEIRD_SERVER_REPLY;
3431 }
3432 data->req.location = location;
3433
3434 if((k->httpcode >= 300 && k->httpcode < 400) &&
C3: on 3xx with follow_mode, sets newurl and this_is_a_follow
3435 data->set.http_follow_mode) {
3436 CURLcode result;
3437 DEBUGASSERT(!data->req.newurl);
3438 data->req.newurl = curlx_strdup(data->req.location); /* clone */
3439 if(!data->req.newurl)
3440 return CURLE_OUT_OF_MEMORY;
3441
3442 /* some cases of POST and PUT etc needs to rewind the data
3443 stream at this point */
3444 result = http_perhapsrewind(data, conn);
3445 if(result)
3446 return result;
3447
3448 /* mark the next request as a followed location: */
3449 data->state.this_is_a_follow = TRUE;
3450 }
3451 }
3452 }
3453 return CURLE_OK;
3454}
3455
3456/*
3457 * http_header_p() parses a single response header starting with P.
3458 */
3459static CURLcode http_header_p(struct Curl_easy *data,
3460 const char *hd, size_t hdlen)
3461{
3462 struct SingleRequest *k = &data->req;
3463
3464#ifndef CURL_DISABLE_PROXY
lib/vtls/schannel.clines 758–811 · lines 783-786 cited by the report
758 SCH_CRED_IGNORE_REVOCATION_OFFLINE |
759 SCH_CRED_REVOCATION_CHECK_CHAIN;
760
761 DEBUGF(infof(data, "schannel: ignore revocation offline errors"));
762 }
763 else {
764 flags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
765
766 DEBUGF(infof(data, "schannel: checking server certificate revocation"));
767 }
768 }
769 else {
770 flags = SCH_CRED_MANUAL_CRED_VALIDATION |
771 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
772 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
773 DEBUGF(infof(data, "schannel: disabled server cert revocation checks"));
774 }
775
776 if(!conn_config->verifyhost) {
777 flags |= SCH_CRED_NO_SERVERNAME_CHECK;
778 DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
779 "comparing the supplied target name with the subject "
780 "names in server certificates."));
781 }
782
783 if(!ssl_config->auto_client_cert) {
C4: auto_client_cert=FALSE disables automatic client cert via SCH_CRED_NO_DEFAULT_CREDS
784 flags &= ~(DWORD)SCH_CRED_USE_DEFAULT_CREDS;
785 flags |= SCH_CRED_NO_DEFAULT_CREDS;
786 infof(data, "schannel: disabled automatic use of client certificate");
787 }
788 else
789 infof(data, "schannel: enabled automatic use of client certificate");
790
791 DEBUGASSERT(conn_config->version != CURL_SSLVERSION_DEFAULT);
792 switch(conn_config->version) {
793 case CURL_SSLVERSION_TLSv1:
794 case CURL_SSLVERSION_TLSv1_0:
795 case CURL_SSLVERSION_TLSv1_1:
796 case CURL_SSLVERSION_TLSv1_2:
797 case CURL_SSLVERSION_TLSv1_3: {
798 result = schannel_set_ssl_version_min_max(&enabled_protocols, cf, data);
799 if(result)
800 return result;
801 break;
802 }
803 case CURL_SSLVERSION_SSLv3:
804 case CURL_SSLVERSION_SSLv2:
805 failf(data, "SSL versions not supported");
806 return CURLE_NOT_BUILT_IN;
807 default:
808 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
809 return CURLE_SSL_CONNECT_ERROR;
810 }
811
lib/vtls/schannel.clines 956–1006 · lines 981-981 cited by the report
956
957 *list_len = curlx_uitous(cur - list_start_index);
958 *extension_len = (unsigned int)(*list_len +
959 sizeof(unsigned int) + sizeof(unsigned short));
960
961 InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
962 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
963
964 Curl_alpn_to_proto_str(&proto, connssl->alpn);
965 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
966 }
967 else {
968 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
969 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
970 }
971
972 /* setup output buffer */
973 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
974 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
975
976 /* security request flags */
977 backend->req_flags =
978 ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
979 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
980 ISC_REQ_STREAM |
981 (!ssl_config->auto_client_cert ? ISC_REQ_USE_SUPPLIED_CREDS : 0);
C4: auto_client_cert=FALSE sets ISC_REQ_USE_SUPPLIED_CREDS
982
983 /* allocate memory for the security context handle */
984 backend->ctxt = (struct Curl_schannel_ctxt *)
985 curlx_calloc(1, sizeof(struct Curl_schannel_ctxt));
986 if(!backend->ctxt) {
987 failf(data, "schannel: unable to allocate memory");
988 return CURLE_OUT_OF_MEMORY;
989 }
990
991 /* Schannel InitializeSecurityContext:
992 https://learn.microsoft.com/windows/win32/api/sspi/nf-sspi-initializesecuritycontextw
993
994 At the moment we do not pass inbuf unless we are using ALPN since we only
995 use it for that, and WINE (for which we currently disable ALPN) is giving
996 us problems with inbuf regardless. https://github.com/curl/curl/issues/983
997 */
998 sspi_status = Curl_pSecFn->InitializeSecurityContext(
999 &backend->cred->cred_handle, NULL, backend->cred->sni_hostname,
1000 backend->req_flags, 0, 0,
1001 (backend->use_alpn ? &inbuf_desc : NULL),
1002 0, &backend->ctxt->ctxt_handle,
1003 &outbuf_desc, &backend->ret_flags, NULL);
1004
1005 if(sspi_status != SEC_I_CONTINUE_NEEDED) {
1006 char buffer[STRERROR_LEN];
lib/peer.clines 321–327 · definition of Curl_peer_equal
Show 7 lines (not cited by the judge)
321bool Curl_peer_equal(struct Curl_peer *p1, struct Curl_peer *p2)
322{
323 return (p1 == p2) ||
324 (p1 && p2 &&
325 (p1->scheme == p2->scheme) &&
326 Curl_peer_same_destination(p1, p2));
327}
lib/curl_setup.hlines 1036–1036 · definition of BIT
Show 1 lines (not cited by the judge)
1036#define BIT(x) curl_bit x:1
include/curl/curl.hlines 971–971 · definition of CURLSSLOPT_AUTO_CLIENT_CERT
Show 1 lines (not cited by the judge)
971#define CURLSSLOPT_AUTO_CLIENT_CERT (1L << 5)
lib/curl_setup.hlines 1048–1048 · definition of FALSE
Show 1 lines (not cited by the judge)
1048#define FALSE false
lib/http.clines 3214–3215 · definition of HD_IS
Show 2 lines (not cited by the judge)
3214#define HD_IS(hd, hdlen, n) \
3215 (((hdlen) >= (sizeof(n) - 1)) && curl_strnequal(n, hd, sizeof(n) - 1))
lib/curl_setup.hlines 1045–1045 · definition of TRUE
Show 1 lines (not cited by the judge)
1045#define TRUE true
lib/easy.clines 851–861 · definition of curl_easy_perform
Show 11 lines (not cited by the judge)
851CURLcode curl_easy_perform(CURL *curl)
852{
853 struct Curl_eapi_guard guard = { 0 };
854 CURLcode result;
855
856 if(CURL_EAPI_ENTER(&guard, curl, easy_perform, &result)) {
857 result = easy_perform(curl, FALSE);
858 }
859 CURL_EAPI_LEAVE(&guard);
860 return result;
861}
lib/curl_setup.hlines 1470–1470 · definition of curlx_strdup
Show 1 lines (not cited by the judge)
1470#define curlx_strdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__)
lib/curl_trc.hlines 142–146 · definition of infof
Show 5 lines (not cited by the judge)
142#define infof(data, ...) \
143 do { \
144 if(Curl_trc_is_verbose(data)) \
145 Curl_infof(data, __VA_ARGS__); \
146 } while(0)
src/curlinfo.clines 273–281 · definition of main
Show 9 lines (not cited by the judge)
273int main(void)
274{
275 size_t i;
276
277 for(i = 0; i < CURL_ARRAYSIZE(disabled); i++)
278 puts(disabled[i]);
279
280 return 0;
281}