✓ProveIt
Examples / Report #3733910 Saved analysis

CVE-2026-8932: incomplete mTLS config matching in conn reuse

curl · 2026-05-1315.6s analysis · $0.040 in model calls

What the report claims

A second curl handle with wrong mTLS credentials silently reuses an existing TLS connection authenticated with a different client identity, allowing impersonation within the same process.

Compare with curl's recorded outcome

Known vulnerability

A real vulnerability: CVE-2026-8932 incomplete mTLS config matching in conn reuse

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 struct split (ssl_primary_config vs ssl_config_data) is real and grounded in lib/urldata.h. Credential fields (key_passwd, key, key_blob, key_type, cert_type) exist only in ssl_config_data and are never compared during connection reuse or session cache lookup.
  • match_ssl_primary_config (lib/vtls/vtls.c:194-225) and cf_ssl_scache_match_auth (lib/vtls/vtls_scache.c:607-627) both omit these fields. connectdata (lib/urldata.h:389) stores only primary config, discarding the credential half when a connection is parked.
  • The PoC demonstrates a concrete attack: two handles sharing a CURLSH pool with CURL_LOCK_DATA_CONNECT + CURL_LOCK_DATA_SSL_SESSION; handle A authenticates with correct KEYPASSWD, handle B (wrong KEYPASSWD) reuses A's connection and inherits A's client identity. Server sees CN=alice for both requests on the same connection ID.
  • This is the same class of flaw as CVE-2022-27782 (incomplete TLS config comparison for connection reuse). It enables silent credential confusion/impersonation in mTLS scenarios where client cert identity maps to authorization — a clear security impact.
  • Master (db4a6f286bbc) still has the gap; the fix proposed by the reporter (promote fields into primary, extend match functions and scache key) is the correct shape.
How this analysis ran 5 claims · 19 citations verified

Checked against curl master on 2026-05-13 (db4a6f286bbc). Test 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 · 50 references checked out, 1 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 6258 tokens · $0.0005
3 · Evidence
13 code snippets
real curl source at db4a6f286bbc · 2 docs via Tavily
4 · Judgment
Nemotron-3-Ultra-550b-a55b
33610 tokens · 10.1s · $0.0400
5 · Receipts
19 of 19 citations verified
every citation must point at code the judge was shown
Review a draft reply to the reporter

Edit and verify before sending.

Thanks for the detailed report and PoC. The claims are grounded: ssl_primary_config omits key_passwd, key, key_blob, key_type, cert_type; match_ssl_primary_config and cf_ssl_scache_match_auth don't compare them; connectdata stores only primary. The PoC shows a real mTLS credential-confusion bug — handle B with a wrong passphrase reuses handle A's authenticated connection. This is a valid security issue (same class as CVE-2022-27782). We'll promote the missing fields into primary and extend the match/scache logic as you outlined.

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

Report claims

C1flaw supported

match_ssl_primary_config only compares struct ssl_primary_config, ignoring fields stored in ssl_config_data such as key_passwd, key, key_type, and cert_type

Read the reasoning

The struct split is real: ssl_primary_config (compared) omits the credential fields that live in ssl_config_data (not compared). The connection-reuse gate literally cannot see them.

C2location supported

match_ssl_primary_config at lib/vtls/vtls.c:194-225

Read the reasoning

The call chain is grounded: url_match_ssl_config → Curl_ssl_conn_config_match → match_ssl_primary_config, all operating on ssl_primary_config only.

C3trigger supported

Two easy handles sharing a CURLSH pool with CURL_LOCK_DATA_CONNECT and CURL_LOCK_DATA_SSL_SESSION reuse a connection when they differ only on SSLKEY, SSLKEY_BLOB, KEYPASSWD, SSLKEYTYPE, or SSLCERTTYPE

Read the reasoning

All five credential fields (SSLKEY, SSLKEY_BLOB, KEYPASSWD, SSLKEYTYPE, SSLCERTTYPE) reside in ssl_config_data and are absent from ssl_primary_config and from the comparison function. When a connection is parked, only primary config survives in connectdata, so the credential differences are lost.

C4impact supported

The second handle silently inherits the first's authenticated TLS identity, causing the server to see the first handle's certificate for all subsequent requests on that connection

Read the reasoning

The session cache key and its auth-match function omit the private-key material. A resumed session can therefore be reused with a different key/passphrase without detection.

C5reproduction supported

F12_poc.c demonstrates that handle B with a wrong KEYPASSWD reuses handle A's connection and succeeds with HTTP 200, while standalone it would fail with CURLE_SSL_CERTPROBLEM

Read the reasoning

The PoC's observed behavior matches the code path: standalone fails at key load; shared pool reuses connection and skips key load entirely.

Deterministic checks that failed

  • line none of curlx_dyn_add, ssl_primary_config, ssl_config_data, CURLSH appear near line 891 at db4a6f286bbc; it reads: '#ifdef MBEDTLS_SSL_RENEGOTIATION'
Read the original report (excerpt)

Full report on HackerOne ↗

Hi all, This report (and my multiple subsequent ones) may come as a surprise, as I was assured that curl now had zero vulnerabilities in it. Nonetheless, I think the CVE-2022-27782 fix ("TLS and SSH connection too eager reuse", commit `f18af4f874` 2022-05-09, "tls: check more TLS details for connection reuse") was incomplete: it moved a batch of SSL knobs into `ssl_primary_config` so conn-reuse would compare them, but left the credential-half of the mTLS pair behind in `ssl_config_data`. Two easy handles sharing a `CURLSH`/`CURLM` pool can reuse each other's authenticated TLS connection whenever they differ only on `SSLKEY`, `SSLKEY_BLOB`, `KEYPASSWD`, `SSLKEYTYPE`, or `SSLCERTTYPE`. The second handle silently inherits the first's authenticated identity to the server. The conn-reuse gate is `match_ssl_primary_config` at `lib/vtls/vtls.c:194-225`, called via `Curl_ssl_conn_config_match` (`lib/vtls/vtls.c:227-240`) from `url_match_ssl_config` in `lib/url.c:991-1003`. Its argument type is `struct ssl_primary_config *` — it literally cannot see anything outside primary. The struct split is in `lib/urldata.h:143-168` (primary, compared) vs `lib/urldata.h:170-193` (`ssl_config_data`, not compared). `connectdata` (`lib/urldata.h:389-392`) only carries the primary copy into the pool, so once a conn is parked the full `ssl_config_data` it was born from is gone. A similar gap exists in the TLS session cache. `Curl_ssl_peer_key_make` (`lib/vtls/vtls_scache.c:137-294`) builds the scache lookup key from primary only, and for the client cert it just adds a literal `:CCERT` marker — same five bytes regardless of which key/cert is set: ```c if(ssl->clientcert && ssl->clientcert[0]) { r = curlx_dyn_add(&buf, ":CCERT"); ``` The secondary auth-match check at `lib/vtls/vtls_scache.c:607-627` (`cf_ssl_scache_match_auth`) compares only `clientcert` and SRP creds — never key, key blob, key passwd, key type, or cert type. (Caveat: in practice the wrong-passwd case eagerly fails inside `client_cert()` before session-resume can hide it, so the scache gap is real-but-narrow for the passphrase variant specifically. The key-blob / key-type variants don't have that eager-fail.) PoC: two easy handles attached to a `CURLSH` with `CURL_LOCK_DATA_CONNECT` + `CURL_LOCK_DATA_SSL_SESSION`. Both target `https://server.test:8443/`, both set the same `SSLCERT=clientA.crt` / `SSLKEY=client …

Source code

lib/vtls/vtls.clines 169–272 · lines 194-225 cited by the report; lines 227-240 cited by the report; definition of clone_ssl_primary_config
169 return &ALPN_SPEC_H2;
170 }
171#else
172 (void)wanted;
173 (void)preferred;
174#endif
175 return &ALPN_SPEC_H11;
176}
177#endif /* !CURL_DISABLE_HTTP || !CURL_DISABLE_PROXY */
178#endif /* USE_SSL */
179
180void Curl_ssl_easy_config_init(struct Curl_easy *data)
181{
182 /*
183 * libcurl 7.10 introduced SSL verification *by default*! This needs to be
184 * switched off unless wanted.
185 */
186 data->set.ssl.primary.verifypeer = TRUE;
187 data->set.ssl.primary.verifyhost = TRUE;
188 data->set.ssl.primary.cache_session = TRUE; /* caching by default */
189#ifndef CURL_DISABLE_PROXY
190 data->set.proxy_ssl = data->set.ssl;
191#endif
192}
193
194static bool match_ssl_primary_config(struct Curl_easy *data,
C1: match_ssl_primary_config (lines 194-225) compares only ssl_primary_config fields; no comparison of key_passwd, key, key_type, cert_type, key_blob
C2: match_ssl_primary_config at lines 194-225 is the conn-reuse gate; its signature takes struct ssl_primary_config *
C3: match_ssl_primary_config does not compare any of these fields
C5: But with connection reuse, match_ssl_primary_config returns true (same primary), so B reuses A's connection and never calls client_cert
195 struct ssl_primary_config *c1,
196 struct ssl_primary_config *c2)
197{
198 (void)data;
199 if((c1->version == c2->version) &&
200 (c1->version_max == c2->version_max) &&
201 (c1->ssl_options == c2->ssl_options) &&
202 (c1->verifypeer == c2->verifypeer) &&
203 (c1->verifyhost == c2->verifyhost) &&
204 (c1->verifystatus == c2->verifystatus) &&
205 blobcmp(c1->cert_blob, c2->cert_blob) &&
206 blobcmp(c1->ca_info_blob, c2->ca_info_blob) &&
207 blobcmp(c1->issuercert_blob, c2->issuercert_blob) &&
208 Curl_safecmp(c1->CApath, c2->CApath) &&
209 Curl_safecmp(c1->CAfile, c2->CAfile) &&
210 Curl_safecmp(c1->issuercert, c2->issuercert) &&
211 Curl_safecmp(c1->clientcert, c2->clientcert) &&
212#ifdef USE_TLS_SRP
213 !Curl_timestrcmp(c1->username, c2->username) &&
214 !Curl_timestrcmp(c1->password, c2->password) &&
215#endif
216 curl_strequal(c1->cipher_list, c2->cipher_list) &&
217 curl_strequal(c1->cipher_list13, c2->cipher_list13) &&
218 curl_strequal(c1->curves, c2->curves) &&
219 curl_strequal(c1->signature_algorithms, c2->signature_algorithms) &&
220 curl_strequal(c1->CRLfile, c2->CRLfile) &&
221 curl_strequal(c1->pinned_key, c2->pinned_key))
222 return TRUE;
223
224 return FALSE;
225}
226
227bool Curl_ssl_conn_config_match(struct Curl_easy *data,
C1: Curl_ssl_conn_config_match (lines 227-240) passes only primary configs to match_ssl_primary_config
C2: Curl_ssl_conn_config_match (lines 227-240) calls it with primary configs only
228 struct connectdata *candidate,
229 bool proxy)
230{
231#ifndef CURL_DISABLE_PROXY
232 if(proxy)
233 return match_ssl_primary_config(data, &data->set.proxy_ssl.primary,
234 &candidate->proxy_ssl_config);
235#else
236 (void)proxy;
237#endif
238 return match_ssl_primary_config(data, &data->set.ssl.primary,
239 &candidate->ssl_config);
240}
241
242static bool clone_ssl_primary_config(struct ssl_primary_config *source,
243 struct ssl_primary_config *dest)
244{
245 dest->version = source->version;
246 dest->version_max = source->version_max;
247 dest->verifypeer = source->verifypeer;
248 dest->verifyhost = source->verifyhost;
249 dest->verifystatus = source->verifystatus;
250 dest->cache_session = source->cache_session;
251 dest->ssl_options = source->ssl_options;
252
253 CLONE_BLOB(cert_blob);
254 CLONE_BLOB(ca_info_blob);
255 CLONE_BLOB(issuercert_blob);
256 CLONE_STRING(CApath);
257 CLONE_STRING(CAfile);
258 CLONE_STRING(issuercert);
259 CLONE_STRING(clientcert);
260 CLONE_STRING(cipher_list);
261 CLONE_STRING(cipher_list13);
262 CLONE_STRING(pinned_key);
263 CLONE_STRING(curves);
264 CLONE_STRING(signature_algorithms);
265 CLONE_STRING(CRLfile);
266#ifdef USE_TLS_SRP
267 CLONE_STRING(username);
268 CLONE_STRING(password);
269#endif
270
271 return TRUE;
272}
lib/url.clines 966–1028 · lines 991-1003 cited by the report
966 if(m->needle->scheme != conn->scheme) {
967 /* `needle` and `conn` do not have the same scheme... */
968 if(get_protocol_family(conn->scheme) != m->needle->scheme->protocol) {
969 /* and `conn`s protocol family is not the protocol `needle` wants.
970 * IMAPS would work for IMAP, but no vice versa. */
971 return FALSE;
972 }
973 /* We are in an IMAPS vs IMAP like case. We expect `conn` to have SSL */
974 if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
975 DEBUGF(infof(m->data, "Connection #%" FMT_OFF_T
976 " has compatible protocol family, but no SSL, no match",
977 conn->connection_id));
978 return FALSE;
979 }
980 }
981
982 /* `needle` must have the same hostname and port in origin and
983 * via_peer (if present, NULL peers are equal) */
984 if(!Curl_peer_same_destination(m->needle->origin, conn->origin) ||
985 !Curl_peer_same_destination(m->needle->via_peer, conn->via_peer))
986 return FALSE;
987 }
988 return TRUE;
989}
990
991static bool url_match_ssl_config(struct connectdata *conn,
C2: url_match_ssl_config (lines 991-1003) calls Curl_ssl_conn_config_match for connection reuse decisions
992 struct url_conn_match *m)
993{
994 /* If talking/upgrading to TLS, conn needs to use the same SSL options. */
995 if(((m->needle->scheme->flags & PROTOPT_SSL) || m->may_tls) &&
996 !Curl_ssl_conn_config_match(m->data, conn, FALSE)) {
997 DEBUGF(infof(m->data, "Connection #%" FMT_OFF_T
998 " has different SSL parameters, cannot reuse",
999 conn->connection_id));
1000 return FALSE;
1001 }
1002 return TRUE;
1003}
1004
1005#ifdef USE_NTLM
1006static bool url_match_auth_ntlm(struct connectdata *conn,
1007 struct url_conn_match *m)
1008{
1009 /* If we are looking for an HTTP+NTLM connection, check if this is
1010 already authenticating with the right credentials. If not, keep
1011 looking so that we can reuse NTLM connections if
1012 possible. (Especially we must not reuse the same connection if
1013 partway through a handshake!) */
1014 if(m->want_ntlm_http) {
1015 if(!Curl_creds_same(m->data->state.creds, conn->creds)) {
1016 /* we prefer a credential match, but this is at least a connection
1017 that can be reused and "upgraded" to NTLM if it does
1018 not have any auth ongoing. */
1019#ifdef USE_SPNEGO
1020 if((conn->http_ntlm_state == NTLMSTATE_NONE)
1021 && (conn->http_negotiate_state == GSS_AUTHNONE)) {
1022#else
1023 if(conn->http_ntlm_state == NTLMSTATE_NONE) {
1024#endif
1025 m->found = conn;
1026 }
1027 return FALSE;
1028 }
lib/urldata.hlines 118–218 · lines 143-168 cited by the report; lines 170-193 cited by the report
118/* The default upload buffer size, should not be smaller than
119 CURL_MAX_WRITE_SIZE, as it needs to hold a full buffer as could be sent in
120 a write callback.
121
122 The size was 16KB for many years but was bumped to 64KB because it makes
123 libcurl able to do significantly faster uploads in some circumstances. Even
124 larger buffers can help further, but this is deemed a fair memory/speed
125 compromise. */
126#define UPLOADBUFFER_DEFAULT 65536
127#define UPLOADBUFFER_MAX (2 * 1024 * 1024)
128#define UPLOADBUFFER_MIN CURL_MAX_WRITE_SIZE
129
130#define CURLEASY_MAGIC_NUMBER 0xc0dedbadU
131#ifdef DEBUGBUILD
132/* On a debug build, we want to fail hard on easy handles that
133 * are not NULL, but no longer have the MAGIC touch. This gives
134 * us early warning on things only discovered by valgrind otherwise. */
135#define GOOD_EASY_HANDLE(x) \
136 (((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER)) ? TRUE : \
137 (DEBUGASSERT(!(x)), FALSE))
138#else
139#define GOOD_EASY_HANDLE(x) \
140 ((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER))
141#endif
142
143struct ssl_primary_config {
C1: ssl_primary_config definition (lines 143-168) lacks key_passwd, key, key_type, cert_type, key_blob
144 char *CApath; /* certificate directory (does not work on Windows) */
145 char *CAfile; /* certificate to verify peer against */
146 char *issuercert; /* optional issuer certificate filename */
147 char *clientcert;
C4: ssl_primary_config.clientcert is the cert path; the key and its passphrase are not in primary
148 char *cipher_list; /* list of ciphers to use */
149 char *cipher_list13; /* list of TLS 1.3 cipher suites to use */
150 char *signature_algorithms; /* list of signature algorithms to use */
151 char *pinned_key;
152 char *CRLfile; /* CRL to check certificate revocation */
153 struct curl_blob *cert_blob;
154 struct curl_blob *ca_info_blob;
155 struct curl_blob *issuercert_blob;
156#ifdef USE_TLS_SRP
157 char *username; /* TLS username (for, e.g., SRP) */
158 char *password; /* TLS password (for, e.g., SRP) */
159#endif
160 char *curves; /* list of curves to use */
161 uint32_t version_max; /* max supported version the client wants to use */
162 uint8_t ssl_options; /* the CURLOPT_SSL_OPTIONS bitmask */
163 uint8_t version; /* what version the client wants to use */
164 BIT(verifypeer); /* set TRUE if this is desired */
165 BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */
166 BIT(verifystatus); /* set TRUE if certificate status must be checked */
167 BIT(cache_session); /* cache session or not */
168};
169
170struct ssl_config_data {
C1: ssl_config_data definition (lines 170-193) contains key_passwd (line 179), key (line 176), key_blob (line 177), key_type (line 178), cert_type (line 175) — not in primary
171 struct ssl_primary_config primary;
172 long certverifyresult; /* result from the certificate verification */
173 curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
174 void *fsslctxp; /* parameter for call back */
175 char *cert_type; /* format for certificate (default: PEM) */
C3: ssl_config_data.cert_type at line 175
176 char *key; /* private key filename */
C3: ssl_config_data.key at line 176
177 struct curl_blob *key_blob;
C3: ssl_config_data.key_blob at line 177
178 char *key_type; /* format for private key (default: PEM) */
C3: ssl_config_data.key_type at line 178
179 char *key_passwd; /* plain text private key password */
C3: ssl_config_data.key_passwd at line 179
180 BIT(certinfo); /* gather lots of certificate info */
181 BIT(earlydata); /* use TLS 1.3 early data */
182 BIT(enable_beast); /* allow this flaw for interoperability's sake */
183 BIT(no_revoke); /* disable SSL certificate revocation checks */
184 BIT(no_partialchain); /* do not accept partial certificate chains */
185 BIT(revoke_best_effort); /* ignore SSL revocation offline/missing revocation
186 list errors */
187 BIT(native_ca_store); /* use the native CA store of operating system */
188 BIT(auto_client_cert); /* automatically locate and use a client
189 certificate for authentication (Schannel) */
190 BIT(custom_cafile); /* application has set custom CA file */
191 BIT(custom_capath); /* application has set custom CA path */
192 BIT(custom_cablob); /* application has set custom CA blob */
193};
194
195struct ssl_general_config {
196 int ca_cache_timeout; /* Certificate store cache timeout (seconds) */
197};
198
199#ifdef USE_WINDOWS_SSPI
200#include "curl_sspi.h"
201#endif
202
203#ifndef CURL_DISABLE_DIGEST_AUTH
204/* Struct used for Digest challenge-response authentication */
205struct digestdata {
206#ifdef USE_WINDOWS_SSPI
207 BYTE *input_token;
208 size_t input_token_len;
209 CtxtHandle *http_context;
210 /* linked credentials used to make the identity for http_context.
211 may be NULL. */
212 struct Curl_creds *creds;
213#else
214 char *nonce;
215 char *cnonce;
216 char *realm;
217 char *opaque;
218 char *qop;
lib/urldata.hlines 364–417 · lines 389-392 cited by the report
364#ifndef CURL_DISABLE_PROXY
365 struct proxy_info socks_proxy;
366 struct proxy_info http_proxy;
367#endif
368 struct Curl_creds *creds; /* When connection itself is tied to credentials */
369 char *options; /* options string, allocated */
370 struct curltime created; /* creation time */
371 struct curltime lastused; /* when returned to the connection pool as idle */
372
373 /* A connection can have one or two sockets and connection filters.
374 * The protocol using the 2nd one is FTP for CONTROL+DATA sockets */
375 curl_socket_t sock[2];
376 struct Curl_cfilter *cfilter[2]; /* connection filters */
377 Curl_recv *recv[2];
378 Curl_send *send[2];
379 int recv_idx; /* on which socket index to receive, default 0 */
380 int send_idx; /* on which socket index to send, default 0 */
381
382#define CONN_SOCK_IDX_VALID(i) (((i) >= 0) && ((i) < 2))
383
384 struct {
385 struct curltime start[2]; /* when filter shutdown started */
386 timediff_t timeout_ms; /* 0 means no timeout */
387 } shutdown;
388
389 struct ssl_primary_config ssl_config;
C3: connectdata carries only ssl_primary_config (line 389) into the pool; the full ssl_config_data is discarded
390#ifndef CURL_DISABLE_PROXY
391 struct ssl_primary_config proxy_ssl_config;
392#endif
393 struct ConnectBits bits; /* various state-flags for this connection */
394
395 const struct Curl_scheme *scheme; /* Connection's protocol handler */
396 const struct Curl_scheme *given; /* The protocol first given */
397
398 /* Protocols can use a custom keepalive mechanism to keep connections alive.
399 This allows those protocols to track the last time the keepalive mechanism
400 was used on this connection. */
401 struct curltime keepalive;
402
403 /* A connection cache from a SHARE might be used in several multi handles.
404 * We MUST not reuse connections that are running in another multi,
405 * for concurrency reasons. That multi might run in another thread.
406 * `attached_multi` is set by the first transfer attached and cleared
407 * when the last one is detached.
408 * NEVER call anything on this multi, check for equality. */
409 struct Curl_multi *attached_multi;
410
411 /*************** Request - specific items ************/
412#if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS)
413 CtxtHandle *sslContext; /* mingw-w64 v9+. MS SDK 7.0A+. */
414#endif
415
416#ifdef USE_NTLM
417 curlntlm http_ntlm_state;
lib/vtls/vtls_scache.clines 112–319 · lines 137-294 cited by the report
112 goto out;
113 r = Curl_sha256it(hash, blob->data, blob->len);
114 if(r)
115 goto out;
116 for(i = 0; i < CURL_SHA256_DIGEST_LENGTH; ++i) {
117 r = curlx_dyn_addf(buf, "%02x", hash[i]);
118 if(r)
119 goto out;
120 }
121 }
122out:
123 return r;
124}
125
126#define CURL_SSLS_LOCAL_SUFFIX ":L"
127#define CURL_SSLS_GLOBAL_SUFFIX ":G"
128
129static bool cf_ssl_peer_key_is_global(const char *peer_key)
130{
131 size_t len = peer_key ? strlen(peer_key) : 0;
132 return (len > 2) &&
133 (peer_key[len - 1] == 'G') &&
134 (peer_key[len - 2] == ':');
135}
136
137CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf,
138 const struct ssl_peer *peer,
139 const char *tls_id,
140 char **ppeer_key)
141{
142 struct ssl_primary_config *ssl = Curl_ssl_cf_get_primary_config(cf);
143 struct dynbuf buf;
144 size_t key_len;
145 bool is_local = FALSE;
146 CURLcode r;
147
148 *ppeer_key = NULL;
149 curlx_dyn_init(&buf, 10 * 1024);
150
151 r = curlx_dyn_addf(&buf, "%s:%d",
152 peer->dest->hostname, peer->dest->port);
153 if(r)
154 goto out;
155
156 switch(peer->transport) {
157 case TRNSPRT_TCP:
158 break;
159 case TRNSPRT_UDP:
160 r = curlx_dyn_add(&buf, ":UDP");
161 break;
162 case TRNSPRT_QUIC:
163 r = curlx_dyn_add(&buf, ":QUIC");
164 break;
165 case TRNSPRT_UNIX:
166 r = curlx_dyn_add(&buf, ":UNIX");
167 break;
168 default:
169 r = curlx_dyn_addf(&buf, ":TRNSPRT-%d", peer->transport);
170 break;
171 }
172 if(r)
173 goto out;
174
175 if(!ssl->verifypeer) {
176 r = curlx_dyn_add(&buf, ":NO-VRFY-PEER");
177 if(r)
178 goto out;
179 }
180 if(!ssl->verifyhost) {
181 r = curlx_dyn_add(&buf, ":NO-VRFY-HOST");
182 if(r)
183 goto out;
184 }
185 if(ssl->verifystatus) {
186 r = curlx_dyn_add(&buf, ":VRFY-STATUS");
187 if(r)
188 goto out;
189 }
190 if(!ssl->verifypeer || !ssl->verifyhost) {
191 if(cf->conn->via_peer) {
192 r = curlx_dyn_addf(&buf, ":CHOST-%s:CPORT-%u",
193 cf->conn->via_peer->hostname,
194 cf->conn->via_peer->port);
195 if(r)
196 goto out;
197 }
198 }
199
200 if(ssl->version || ssl->version_max) {
201 r = curlx_dyn_addf(&buf, ":TLSVER-%d-%u", ssl->version,
202 (ssl->version_max >> 16));
203 if(r)
204 goto out;
205 }
206 if(ssl->ssl_options) {
207 r = curlx_dyn_addf(&buf, ":TLSOPT-%x", ssl->ssl_options);
208 if(r)
209 goto out;
210 }
211 if(ssl->cipher_list) {
212 r = curlx_dyn_addf(&buf, ":CIPHER-%s", ssl->cipher_list);
213 if(r)
214 goto out;
215 }
216 if(ssl->cipher_list13) {
217 r = curlx_dyn_addf(&buf, ":CIPHER13-%s", ssl->cipher_list13);
218 if(r)
219 goto out;
220 }
221 if(ssl->curves) {
222 r = curlx_dyn_addf(&buf, ":CURVES-%s", ssl->curves);
223 if(r)
224 goto out;
225 }
226 if(ssl->verifypeer) {
227 r = cf_ssl_peer_key_add_path(&buf, "CA", ssl->CAfile, &is_local);
228 if(r)
229 goto out;
230 r = cf_ssl_peer_key_add_path(&buf, "CApath", ssl->CApath, &is_local);
231 if(r)
232 goto out;
233 r = cf_ssl_peer_key_add_path(&buf, "CRL", ssl->CRLfile, &is_local);
234 if(r)
235 goto out;
236 r = cf_ssl_peer_key_add_path(&buf, "Issuer", ssl->issuercert, &is_local);
237 if(r)
238 goto out;
239 if(ssl->ca_info_blob) {
240 r = cf_ssl_peer_key_add_hash(&buf, "CAInfoBlob", ssl->ca_info_blob);
241 if(r)
242 goto out;
243 }
244 if(ssl->issuercert_blob) {
245 r = cf_ssl_peer_key_add_hash(&buf, "IssuerBlob", ssl->issuercert_blob);
246 if(r)
247 goto out;
248 }
249 }
250 if(ssl->cert_blob) {
251 r = cf_ssl_peer_key_add_hash(&buf, "CertBlob", ssl->cert_blob);
252 if(r)
253 goto out;
254 }
255 if(ssl->pinned_key && ssl->pinned_key[0]) {
256 r = curlx_dyn_addf(&buf, ":Pinned-%s", ssl->pinned_key);
257 if(r)
258 goto out;
259 }
260
261 if(ssl->clientcert && ssl->clientcert[0]) {
262 r = curlx_dyn_add(&buf, ":CCERT");
263 if(r)
C4: Curl_ssl_peer_key_make (lines 137-294) adds only ':CCERT' literal for clientcert (line 263-266), not the cert path or key material
264 goto out;
265 }
266#ifdef USE_TLS_SRP
267 if(ssl->username || ssl->password) {
268 r = curlx_dyn_add(&buf, ":SRP-AUTH");
269 if(r)
270 goto out;
271 }
272#endif
273
274 if(!tls_id || !tls_id[0]) {
275 r = CURLE_FAILED_INIT;
276 goto out;
277 }
278 r = curlx_dyn_addf(&buf, ":IMPL-%s", tls_id);
279 if(r)
280 goto out;
281
282 r = curlx_dyn_addf(&buf, is_local ?
283 CURL_SSLS_LOCAL_SUFFIX : CURL_SSLS_GLOBAL_SUFFIX);
284 if(r)
285 goto out;
286
287 *ppeer_key = curlx_dyn_take(&buf, &key_len);
288 /* we added printable char, and dynbuf always null-terminates, no need
289 * to track length */
290
291out:
292 curlx_dyn_free(&buf);
293 return r;
294}
295
296struct Curl_ssl_scache {
297 unsigned int magic;
298 struct Curl_ssl_scache_peer *peers;
299 size_t peer_count;
300 int default_lifetime_secs;
301 long age;
302 BIT(is_locked);
303};
304
305static struct Curl_ssl_scache *cf_ssl_scache_get(struct Curl_easy *data)
306{
307 struct Curl_ssl_scache *scache = NULL;
308 /* If a share is present, its ssl_scache has preference over the multi */
309 if(data->share && data->share->ssl_scache)
310 scache = data->share->ssl_scache;
311 else if(data->multi && data->multi->ssl_scache)
312 scache = data->multi->ssl_scache;
313 if(scache && !GOOD_SCACHE(scache)) {
314 failf(data, "transfer would use an invalid scache at %p, denied",
315 (void *)scache);
316 DEBUGASSERT(0);
317 return NULL;
318 }
319 return scache;
lib/vtls/vtls_scache.clines 582–652 · lines 607-627 cited by the report
582/* Lock shared SSL session data */
583void Curl_ssl_scache_lock(struct Curl_easy *data)
584{
585 struct Curl_ssl_scache *scache = cf_ssl_scache_get(data);
586 if(scache) {
587 if(CURL_SHARE_ssl_scache(data))
588 Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION,
589 CURL_LOCK_ACCESS_SINGLE);
590 DEBUGASSERT(!scache->is_locked);
591 scache->is_locked = TRUE;
592 }
593}
594
595/* Unlock shared SSL session data */
596void Curl_ssl_scache_unlock(struct Curl_easy *data)
597{
598 struct Curl_ssl_scache *scache = cf_ssl_scache_get(data);
599 if(scache) {
600 DEBUGASSERT(scache->is_locked);
601 scache->is_locked = FALSE;
602 if(CURL_SHARE_ssl_scache(data))
603 Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
604 }
605}
606
607static bool cf_ssl_scache_match_auth(struct Curl_ssl_scache_peer *peer,
C4: cf_ssl_scache_match_auth (lines 607-627) compares only clientcert and SRP creds; never key, key_blob, key_passwd, key_type, cert_type
608 struct ssl_primary_config *conn_config)
609{
610 if(!conn_config) {
611 if(peer->clientcert)
612 return FALSE;
613#ifdef USE_TLS_SRP
614 if(peer->srp_username || peer->srp_password)
615 return FALSE;
616#endif
617 return TRUE;
618 }
619 else if(!Curl_safecmp(peer->clientcert, conn_config->clientcert))
620 return FALSE;
621#ifdef USE_TLS_SRP
622 if(Curl_timestrcmp(peer->srp_username, conn_config->username) ||
623 Curl_timestrcmp(peer->srp_password, conn_config->password))
624 return FALSE;
625#endif
626 return TRUE;
627}
628
629static CURLcode cf_ssl_find_peer_by_key(struct Curl_easy *data,
630 struct Curl_ssl_scache *scache,
631 const char *ssl_peer_key,
632 struct ssl_primary_config *conn_config,
633 struct Curl_ssl_scache_peer **ppeer)
634{
635 size_t i, peer_key_len = 0;
636 CURLcode result = CURLE_OK;
637
638 *ppeer = NULL;
639 if(!GOOD_SCACHE(scache)) {
640 return CURLE_BAD_FUNCTION_ARGUMENT;
641 }
642
643 CURL_TRC_SSLS(data, "find peer slot for %s among %zu slots",
644 ssl_peer_key, scache->peer_count);
645
646 /* check for entries with known peer_key */
647 for(i = 0; scache && i < scache->peer_count; i++) {
648 if(scache->peers[i].ssl_peer_key &&
649 curl_strequal(ssl_peer_key, scache->peers[i].ssl_peer_key) &&
650 cf_ssl_scache_match_auth(&scache->peers[i], conn_config)) {
651 /* yes, we have a cached session for this! */
652 *ppeer = &scache->peers[i];
lib/vtls/openssl.clines 1422–1582 · definition of client_cert (truncated)
1422static CURLcode client_cert(struct Curl_easy *data,
C5: client_cert (lines 1422-1582) eagerly fails with CURLE_SSL_CERTPROBLEM when key_passwd is wrong (lines 1443-1448, 1522-1527) — confirming standalone B would fail
1423 SSL_CTX* ctx,
1424 char *cert_file,
1425 const struct curl_blob *cert_blob,
1426 const char *cert_type,
1427 char *key_file,
1428 const struct curl_blob *key_blob,
1429 const char *key_type,
1430 char *key_passwd)
1431{
1432 char error_buffer[256];
1433 bool check_privkey = TRUE;
1434 int file_type = ossl_do_file_type(cert_type);
1435
1436 if(cert_file || cert_blob || (file_type == SSL_FILETYPE_ENGINE) ||
1437 (file_type == SSL_FILETYPE_PROVIDER)) {
1438 SSL *ssl;
1439 X509 *x509;
1440 bool pcks12_done = FALSE;
1441 int cert_use_result;
1442
1443 if(key_passwd) {
1444 /* set the password in the callback userdata */
1445 SSL_CTX_set_default_passwd_cb_userdata(ctx, key_passwd);
1446 /* Set passwd callback: */
1447 SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
1448 }
1449
1450 switch(file_type) {
1451 case SSL_FILETYPE_PEM:
1452 /* SSL_CTX_use_certificate_chain_file() only works on PEM files */
1453 cert_use_result = cert_blob ?
1454 use_certificate_chain_blob(ctx, cert_blob, key_passwd) :
1455 SSL_CTX_use_certificate_chain_file(ctx, cert_file);
1456 if(cert_use_result != 1) {
1457 failf(data,
1458 "could not load PEM client certificate from %s, " OSSL_PACKAGE
1459 " error %s, "
1460 "(no key found, wrong passphrase, or wrong file format?)",
1461 (cert_blob ? "CURLOPT_SSLCERT_BLOB" : cert_file),
1462 ossl_strerror(ERR_get_error(), error_buffer,
1463 sizeof(error_buffer)));
1464 return CURLE_SSL_CERTPROBLEM;
1465 }
1466 break;
1467
1468 case SSL_FILETYPE_ASN1:
1469 /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but
1470 we use the case above for PEM so this can only be performed with
1471 ASN1 files. */
1472
1473 cert_use_result = cert_blob ?
1474 use_certificate_blob(ctx, cert_blob, file_type, key_passwd) :
1475 SSL_CTX_use_certificate_file(ctx, cert_file, file_type);
1476 if(cert_use_result != 1) {
1477 failf(data,
1478 "could not load ASN1 client certificate from %s, " OSSL_PACKAGE
1479 " error %s, "
1480 "(no key found, wrong passphrase, or wrong file format?)",
1481 (cert_blob ? "CURLOPT_SSLCERT_BLOB" : cert_file),
1482 ossl_strerror(ERR_get_error(), error_buffer,
1483 sizeof(error_buffer)));
1484 return CURLE_SSL_CERTPROBLEM;
1485 }
1486 break;
1487
1488 case SSL_FILETYPE_ENGINE:
1489 if(!cert_file || !engineload(data, ctx, cert_file))
1490 return CURLE_SSL_CERTPROBLEM;
1491 break;
1492
1493 case SSL_FILETYPE_PROVIDER:
1494 if(!cert_file || !providerload(data, ctx, cert_file))
1495 return CURLE_SSL_CERTPROBLEM;
1496 break;
1497
1498 case SSL_FILETYPE_PKCS12:
1499 if(!pkcs12load(data, ctx, cert_blob, cert_file, key_passwd))
1500 return CURLE_SSL_CERTPROBLEM;
1501 pcks12_done = TRUE;
1502 break;
1503
1504 default:
1505 failf(data, "not supported file type '%s' for certificate", cert_type);
1506 return CURLE_BAD_FUNCTION_ARGUMENT;
1507 }
1508
1509 if(!key_file && !key_blob) {
1510 key_file = cert_file;
1511 key_blob = cert_blob;
1512 }
1513 else
1514 file_type = ossl_do_file_type(key_type);
1515
1516 switch(file_type) {
1517 case SSL_FILETYPE_PEM:
1518 case SSL_FILETYPE_ASN1:
1519 cert_use_result = key_blob ?
1520 use_privatekey_blob(ctx, key_blob, file_type, key_passwd) :
1521 SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type);
1522 if(cert_use_result != 1) {
1523 failf(data, "unable to set private key file: '%s' type %s",
1524 key_file ? key_file : "(memory blob)",
1525 key_type ? key_type : "PEM");
1526 return CURLE_BAD_FUNCTION_ARGUMENT;
1527 }
1528 break;
1529 case SSL_FILETYPE_ENGINE:
1530 if(!enginecheck(data, ctx, key_file, key_passwd))
1531 return CURLE_SSL_CERTPROBLEM;
1532 break;
1533
1534 case SSL_FILETYPE_PROVIDER:
1535 if(!providercheck(data, ctx, key_file))
1536 return CURLE_SSL_CERTPROBLEM;
1537 break;
1538
1539 case SSL_FILETYPE_PKCS12:
1540 if(!pcks12_done) {
1541 failf(data, "file type P12 for private key not supported");
1542 return CURLE_SSL_CERTPROBLEM;
1543 }
1544 break;
1545 default:
1546 failf(data, "not supported file type for private key");
1547 return CURLE_BAD_FUNCTION_ARGUMENT;
1548 }
1549
1550 ssl = SSL_new(ctx);
1551 if(!ssl) {
1552 failf(data, "unable to create an SSL structure");
1553 return CURLE_OUT_OF_MEMORY;
1554 }
1555
1556 x509 = SSL_get_certificate(ssl);
1557
1558 if(x509) {
1559 EVP_PKEY *pktmp = X509_get_pubkey(x509);
1560 EVP_PKEY_copy_parameters(pktmp, SSL_get_privatekey(ssl));
1561 EVP_PKEY_free(pktmp);
1562 }
1563
1564#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DEPRECATED_3_0)
1565 {
1566 /* If RSA is used, do not check the private key if its flags indicate
1567 * it does not support it. */
1568 EVP_PKEY *priv_key = SSL_get_privatekey(ssl);
1569 if(EVP_PKEY_id(priv_key) == EVP_PKEY_RSA) {
1570 RSA *rsa = EVP_PKEY_get1_RSA(priv_key);
1571 if(RSA_flags(rsa) & RSA_METHOD_FLAG_NO_CHECK)
1572 check_privkey = FALSE;
1573 RSA_free(rsa); /* Decrement reference count */
1574 }
1575 }
1576#endif
1577
1578 SSL_free(ssl);
1579
1580 /* If we are using DSA, we can copy the parameters from
1581 * the private key */
1582
lib/vtls/mbedtls.clines 1046–1151 · lines 1071-1126 cited by the report
Show 106 lines (not cited by the judge)
1046 }
1047 else if(ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
1048 failf(data, "peer certificate could not be verified");
1049 return CURLE_PEER_FAILED_VERIFICATION;
1050 }
1051 else if(ret) {
1052 char errorbuf[128];
1053 CURL_TRC_CF(data, cf, "TLS version %04X",
1054 mbedtls_ssl_get_version_number(&backend->ssl));
1055 mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
1056 failf(data, "ssl_handshake returned: (-0x%04X) %s",
1057 -ret, errorbuf);
1058 return CURLE_SSL_CONNECT_ERROR;
1059 }
1060
1061 {
1062 char cipher_str[64];
1063 uint16_t cipher_id;
1064 cipher_id =
1065 (uint16_t)mbedtls_ssl_get_ciphersuite_id_from_ssl(&backend->ssl);
1066 mbed_cipher_suite_get_str(cipher_id, cipher_str, sizeof(cipher_str), TRUE);
1067 infof(data, "mbedTLS: %s Handshake complete, cipher is %s",
1068 mbedtls_ssl_get_version(&backend->ssl), cipher_str);
1069 }
1070
1071#ifdef HAVE_PINNED_PUBKEY
1072 if(pinnedpubkey) {
1073 int size;
1074 const mbedtls_x509_crt *peercert;
1075 mbedtls_x509_crt *p = NULL;
1076 unsigned char *pubkey = NULL;
1077
1078 peercert = mbedtls_ssl_get_peer_cert(&backend->ssl);
1079 if(!peercert || !peercert->raw.p || !peercert->raw.len) {
1080 failf(data, "Failed due to missing peer certificate");
1081 return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1082 }
1083
1084 p = curlx_calloc(1, sizeof(*p));
1085
1086 if(!p)
1087 return CURLE_OUT_OF_MEMORY;
1088
1089 pubkey = curlx_malloc(PUB_DER_MAX_BYTES);
1090
1091 if(!pubkey) {
1092 result = CURLE_OUT_OF_MEMORY;
1093 goto pinnedpubkey_error;
1094 }
1095
1096 mbedtls_x509_crt_init(p);
1097
1098 /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der
1099 needs a non-const key, for now.
1100 https://github.com/Mbed-TLS/mbedtls/issues/396 */
1101 if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
1102 failf(data, "Failed copying peer certificate");
1103 result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1104 goto pinnedpubkey_error;
1105 }
1106
1107 size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);
1108
1109 if(size <= 0) {
1110 failf(data, "Failed copying public key from peer certificate");
1111 result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1112 goto pinnedpubkey_error;
1113 }
1114
1115 /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */
1116 result = Curl_pin_peer_pubkey(data,
1117 pinnedpubkey,
1118 &pubkey[PUB_DER_MAX_BYTES - size], size);
1119pinnedpubkey_error:
1120 mbedtls_x509_crt_free(p);
1121 curlx_free(p);
1122 curlx_free(pubkey);
1123 if(result)
1124 return result;
1125 }
1126#endif
1127
1128#ifdef HAS_ALPN_MBEDTLS
1129 if(connssl->alpn) {
1130 const char *proto = mbedtls_ssl_get_alpn_protocol(&backend->ssl);
1131
1132 result = Curl_alpn_set_negotiated(cf, data, connssl,
1133 (const unsigned char *)proto,
1134 proto ? strlen(proto) : 0);
1135 if(result)
1136 return result;
1137 }
1138#endif
1139
1140 connssl->connecting_state = ssl_connect_3;
1141 infof(data, "SSL connected");
1142
1143 return CURLE_OK;
1144}
1145
1146static CURLcode mbed_new_session(struct Curl_cfilter *cf,
1147 struct Curl_easy *data)
1148{
1149 struct ssl_connect_data *connssl = cf->ctx;
1150 struct mbed_ssl_backend_data *backend =
1151 (struct mbed_ssl_backend_data *)connssl->backend;
lib/vtls/vtls.clines 755–894 · definition of Curl_pin_peer_pubkey
Show 140 lines (not cited by the judge)
755CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
756 const char *pinnedpubkey,
757 const unsigned char *pubkey, size_t pubkeylen)
758{
759 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
760
761 /* if a path was not specified, do not pin */
762 if(!pinnedpubkey)
763 return CURLE_OK;
764 if(!pubkey || !pubkeylen)
765 return result;
766
767 /* only do this if pinnedpubkey starts with "sha256//", length 8 */
768 if(!strncmp(pinnedpubkey, "sha256//", 8)) {
769 CURLcode encode;
770 char *cert_hash = NULL;
771 const char *pinned_hash, *end_pos;
772 size_t cert_hash_len = 0, pinned_hash_len;
773 unsigned char *sha256sumdigest;
774
775 if(!Curl_ssl->sha256sum) {
776 /* without sha256 support, this cannot match */
777 return result;
778 }
779
780 /* compute sha256sum of public key */
781 sha256sumdigest = curlx_malloc(CURL_SHA256_DIGEST_LENGTH);
782 if(!sha256sumdigest)
783 return CURLE_OUT_OF_MEMORY;
784 encode = Curl_ssl->sha256sum(pubkey, pubkeylen,
785 sha256sumdigest, CURL_SHA256_DIGEST_LENGTH);
786
787 if(!encode)
788 encode = curlx_base64_encode(sha256sumdigest,
789 CURL_SHA256_DIGEST_LENGTH,
790 &cert_hash, &cert_hash_len);
791 curlx_safefree(sha256sumdigest);
792
793 if(encode)
794 return encode;
795
796 infof(data, " public key hash: sha256//%s", cert_hash);
797
798 pinned_hash = pinnedpubkey;
799 while(pinned_hash &&
800 !strncmp(pinned_hash, "sha256//", (sizeof("sha256//") - 1))) {
801 pinned_hash = pinned_hash + (sizeof("sha256//") - 1);
802 end_pos = strchr(pinned_hash, ';');
803 pinned_hash_len = end_pos ?
804 (size_t)(end_pos - pinned_hash) : strlen(pinned_hash);
805
806 /* compare base64 sha256 digests */
807 if(cert_hash_len == pinned_hash_len &&
808 !memcmp(cert_hash, pinned_hash, cert_hash_len)) {
809 DEBUGF(infof(data, "public key hash matches pinned value"));
810 result = CURLE_OK;
811 break;
812 }
813
814 DEBUGF(infof(data, "public key hash does not match 'sha256//%.*s'",
815 (int)pinned_hash_len, pinned_hash));
816 /* next one or we are at the end */
817 pinned_hash = end_pos ? (end_pos + 1) : NULL;
818 }
819 curlx_safefree(cert_hash);
820 }
821 else {
822 long filesize;
823 size_t size, pem_len;
824 CURLcode pem_read;
825 struct dynbuf buf;
826 unsigned char *pem_ptr = NULL;
827 size_t left;
828 FILE *fp = curlx_fopen(pinnedpubkey, "rb");
829 if(!fp)
830 return result;
831
832 curlx_dyn_init(&buf, MAX_PINNED_PUBKEY_SIZE);
833
834 /* Determine the file's size */
835 if(fseek(fp, 0, SEEK_END))
836 goto end;
837 filesize = ftell(fp);
838 if(fseek(fp, 0, SEEK_SET))
839 goto end;
840 if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE)
841 goto end;
842
843 /*
844 * if the size of our certificate is bigger than the file
845 * size then it cannot match
846 */
847 size = curlx_sotouz((curl_off_t)filesize);
848 if(pubkeylen > size)
849 goto end;
850
851 /*
852 * Read the file into the dynbuf
853 */
854 left = size;
855 do {
856 char buffer[1024];
857 size_t want = left > sizeof(buffer) ? sizeof(buffer) : left;
858 if(want != fread(buffer, 1, want, fp))
859 goto end;
860 if(curlx_dyn_addn(&buf, buffer, want))
861 goto end;
862 left -= want;
863 } while(left);
864
865 /* If the sizes are the same, it cannot be base64 encoded, must be der */
866 if(pubkeylen == size) {
867 if(!memcmp(pubkey, curlx_dyn_ptr(&buf), pubkeylen))
868 result = CURLE_OK;
869 goto end;
870 }
871
872 /*
873 * Otherwise we assume it is PEM and try to decode it after placing
874 * null-terminator
875 */
876 pem_read = pubkey_pem_to_der(curlx_dyn_ptr(&buf), &pem_ptr, &pem_len);
877 /* if it was not read successfully, exit */
878 if(pem_read)
879 goto end;
880
881 /*
882 * if the size of our certificate does not match the size of
883 * the decoded file, they cannot be the same, otherwise compare
884 */
885 if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
886 result = CURLE_OK;
887end:
888 curlx_dyn_free(&buf);
889 curlx_safefree(pem_ptr);
890 curlx_fclose(fp);
891 }
892
893 return result;
894}
lib/vtls/vtls_scache.c@curl-8_20_0lines 137–296 · definition of Curl_ssl_peer_key_make as in release curl-8_20_0; differs from master; commits that changed it since: bc40e09f63 lib: introduce Curl_peer
Show 160 lines (not cited by the judge)
137CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf,
138 const struct ssl_peer *peer,
139 const char *tls_id,
140 char **ppeer_key)
141{
142 struct ssl_primary_config *ssl = Curl_ssl_cf_get_primary_config(cf);
143 struct dynbuf buf;
144 size_t key_len;
145 bool is_local = FALSE;
146 CURLcode r;
147
148 *ppeer_key = NULL;
149 curlx_dyn_init(&buf, 10 * 1024);
150
151 r = curlx_dyn_addf(&buf, "%s:%d", peer->hostname, peer->port);
152 if(r)
153 goto out;
154
155 switch(peer->transport) {
156 case TRNSPRT_TCP:
157 break;
158 case TRNSPRT_UDP:
159 r = curlx_dyn_add(&buf, ":UDP");
160 break;
161 case TRNSPRT_QUIC:
162 r = curlx_dyn_add(&buf, ":QUIC");
163 break;
164 case TRNSPRT_UNIX:
165 r = curlx_dyn_add(&buf, ":UNIX");
166 break;
167 default:
168 r = curlx_dyn_addf(&buf, ":TRNSPRT-%d", peer->transport);
169 break;
170 }
171 if(r)
172 goto out;
173
174 if(!ssl->verifypeer) {
175 r = curlx_dyn_add(&buf, ":NO-VRFY-PEER");
176 if(r)
177 goto out;
178 }
179 if(!ssl->verifyhost) {
180 r = curlx_dyn_add(&buf, ":NO-VRFY-HOST");
181 if(r)
182 goto out;
183 }
184 if(ssl->verifystatus) {
185 r = curlx_dyn_add(&buf, ":VRFY-STATUS");
186 if(r)
187 goto out;
188 }
189 if(!ssl->verifypeer || !ssl->verifyhost) {
190 if(cf->conn->bits.conn_to_host) {
191 r = curlx_dyn_addf(&buf, ":CHOST-%s", cf->conn->conn_to_host.name);
192 if(r)
193 goto out;
194 }
195 if(cf->conn->bits.conn_to_port) {
196 r = curlx_dyn_addf(&buf, ":CPORT-%d", cf->conn->conn_to_port);
197 if(r)
198 goto out;
199 }
200 }
201
202 if(ssl->version || ssl->version_max) {
203 r = curlx_dyn_addf(&buf, ":TLSVER-%d-%u", ssl->version,
204 (ssl->version_max >> 16));
205 if(r)
206 goto out;
207 }
208 if(ssl->ssl_options) {
209 r = curlx_dyn_addf(&buf, ":TLSOPT-%x", ssl->ssl_options);
210 if(r)
211 goto out;
212 }
213 if(ssl->cipher_list) {
214 r = curlx_dyn_addf(&buf, ":CIPHER-%s", ssl->cipher_list);
215 if(r)
216 goto out;
217 }
218 if(ssl->cipher_list13) {
219 r = curlx_dyn_addf(&buf, ":CIPHER13-%s", ssl->cipher_list13);
220 if(r)
221 goto out;
222 }
223 if(ssl->curves) {
224 r = curlx_dyn_addf(&buf, ":CURVES-%s", ssl->curves);
225 if(r)
226 goto out;
227 }
228 if(ssl->verifypeer) {
229 r = cf_ssl_peer_key_add_path(&buf, "CA", ssl->CAfile, &is_local);
230 if(r)
231 goto out;
232 r = cf_ssl_peer_key_add_path(&buf, "CApath", ssl->CApath, &is_local);
233 if(r)
234 goto out;
235 r = cf_ssl_peer_key_add_path(&buf, "CRL", ssl->CRLfile, &is_local);
236 if(r)
237 goto out;
238 r = cf_ssl_peer_key_add_path(&buf, "Issuer", ssl->issuercert, &is_local);
239 if(r)
240 goto out;
241 if(ssl->ca_info_blob) {
242 r = cf_ssl_peer_key_add_hash(&buf, "CAInfoBlob", ssl->ca_info_blob);
243 if(r)
244 goto out;
245 }
246 if(ssl->issuercert_blob) {
247 r = cf_ssl_peer_key_add_hash(&buf, "IssuerBlob", ssl->issuercert_blob);
248 if(r)
249 goto out;
250 }
251 }
252 if(ssl->cert_blob) {
253 r = cf_ssl_peer_key_add_hash(&buf, "CertBlob", ssl->cert_blob);
254 if(r)
255 goto out;
256 }
257 if(ssl->pinned_key && ssl->pinned_key[0]) {
258 r = curlx_dyn_addf(&buf, ":Pinned-%s", ssl->pinned_key);
259 if(r)
260 goto out;
261 }
262
263 if(ssl->clientcert && ssl->clientcert[0]) {
264 r = curlx_dyn_add(&buf, ":CCERT");
265 if(r)
266 goto out;
267 }
268#ifdef USE_TLS_SRP
269 if(ssl->username || ssl->password) {
270 r = curlx_dyn_add(&buf, ":SRP-AUTH");
271 if(r)
272 goto out;
273 }
274#endif
275
276 if(!tls_id || !tls_id[0]) {
277 r = CURLE_FAILED_INIT;
278 goto out;
279 }
280 r = curlx_dyn_addf(&buf, ":IMPL-%s", tls_id);
281 if(r)
282 goto out;
283
284 r = curlx_dyn_addf(&buf, is_local ?
285 CURL_SSLS_LOCAL_SUFFIX : CURL_SSLS_GLOBAL_SUFFIX);
286 if(r)
287 goto out;
288
289 *ppeer_key = curlx_dyn_take(&buf, &key_len);
290 /* we added printable char, and dynbuf always null-terminates, no need
291 * to track length */
292
293out:
294 curlx_dyn_free(&buf);
295 return r;
296}
lib/curlx/dynbuf.clines 173–182 · definition of curlx_dyn_add
Show 10 lines (not cited by the judge)
173CURLcode curlx_dyn_add(struct dynbuf *s, const char *str)
174{
175 size_t n;
176 DEBUGASSERT(str);
177 DEBUGASSERT(s);
178 DEBUGASSERT(s->init == DYNINIT);
179 DEBUGASSERT(!s->leng || s->bufr);
180 n = strlen(str);
181 return dyn_nappend(s, (const unsigned char *)str, n);
182}
lib/vtls/vtls.clines 274–293 · definition of free_primary_ssl_config
Show 20 lines (not cited by the judge)
274static void free_primary_ssl_config(struct ssl_primary_config *sslc)
275{
276 curlx_safefree(sslc->CApath);
277 curlx_safefree(sslc->CAfile);
278 curlx_safefree(sslc->issuercert);
279 curlx_safefree(sslc->clientcert);
280 curlx_safefree(sslc->cipher_list);
281 curlx_safefree(sslc->cipher_list13);
282 curlx_safefree(sslc->pinned_key);
283 curlx_safefree(sslc->cert_blob);
284 curlx_safefree(sslc->ca_info_blob);
285 curlx_safefree(sslc->issuercert_blob);
286 curlx_safefree(sslc->curves);
287 curlx_safefree(sslc->signature_algorithms);
288 curlx_safefree(sslc->CRLfile);
289#ifdef USE_TLS_SRP
290 curlx_safefree(sslc->username);
291 curlx_safefree(sslc->password);
292#endif
293}
lib/url.c@curl-8_20_0lines 1059–1071 · definition of url_match_ssl_config as in release curl-8_20_0; differs from master; commits that changed it since: a86efdd7ca url: fix connection reuse for starttls protocols
Show 13 lines (not cited by the judge)
1059static bool url_match_ssl_config(struct connectdata *conn,
1060 struct url_conn_match *m)
1061{
1062 /* If talking TLS, conn needs to use the same SSL options. */
1063 if((m->needle->scheme->flags & PROTOPT_SSL) &&
1064 !Curl_ssl_conn_config_match(m->data, conn, FALSE)) {
1065 DEBUGF(infof(m->data, "Connection #%" FMT_OFF_T
1066 " has different SSL parameters, cannot reuse",
1067 conn->connection_id));
1068 return FALSE;
1069 }
1070 return TRUE;
1071}