VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/vtls/vtls.c@ 104083

Last change on this file since 104083 was 104083, checked in by vboxsync, 12 months ago

curl-8.7.1: Applied and adjusted our curl changes to 8.4.0. bugref:10639

  • Property svn:eol-style set to native
File size: 58.2 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25/* This file is for implementing all "generic" SSL functions that all libcurl
26 internals should use. It is then responsible for calling the proper
27 "backend" function.
28
29 SSL-functions in libcurl should call functions in this source file, and not
30 to any specific SSL-layer.
31
32 Curl_ssl_ - prefix for generic ones
33
34 Note that this source code uses the functions of the configured SSL
35 backend via the global Curl_ssl instance.
36
37 "SSL/TLS Strong Encryption: An Introduction"
38 https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html
39*/
40
41#include "curl_setup.h"
42
43#ifdef HAVE_SYS_TYPES_H
44#include <sys/types.h>
45#endif
46#ifdef HAVE_SYS_STAT_H
47#include <sys/stat.h>
48#endif
49#ifdef HAVE_FCNTL_H
50#include <fcntl.h>
51#endif
52
53#include "urldata.h"
54#include "cfilters.h"
55
56#include "vtls.h" /* generic SSL protos etc */
57#include "vtls_int.h"
58#include "slist.h"
59#include "sendf.h"
60#include "strcase.h"
61#include "url.h"
62#include "progress.h"
63#include "share.h"
64#include "multiif.h"
65#include "timeval.h"
66#include "curl_md5.h"
67#include "warnless.h"
68#include "curl_base64.h"
69#include "curl_printf.h"
70#include "inet_pton.h"
71#include "strdup.h"
72
73/* The last #include files should be: */
74#include "curl_memory.h"
75#include "memdebug.h"
76
77
78/* convenience macro to check if this handle is using a shared SSL session */
79#define SSLSESSION_SHARED(data) (data->share && \
80 (data->share->specifier & \
81 (1<<CURL_LOCK_DATA_SSL_SESSION)))
82
83#define CLONE_STRING(var) \
84 do { \
85 if(source->var) { \
86 dest->var = strdup(source->var); \
87 if(!dest->var) \
88 return FALSE; \
89 } \
90 else \
91 dest->var = NULL; \
92 } while(0)
93
94#define CLONE_BLOB(var) \
95 do { \
96 if(blobdup(&dest->var, source->var)) \
97 return FALSE; \
98 } while(0)
99
100static CURLcode blobdup(struct curl_blob **dest,
101 struct curl_blob *src)
102{
103 DEBUGASSERT(dest);
104 DEBUGASSERT(!*dest);
105 if(src) {
106 /* only if there's data to dupe! */
107 struct curl_blob *d;
108 d = malloc(sizeof(struct curl_blob) + src->len);
109 if(!d)
110 return CURLE_OUT_OF_MEMORY;
111 d->len = src->len;
112 /* Always duplicate because the connection may survive longer than the
113 handle that passed in the blob. */
114 d->flags = CURL_BLOB_COPY;
115 d->data = (void *)((char *)d + sizeof(struct curl_blob));
116 memcpy(d->data, src->data, src->len);
117 *dest = d;
118 }
119 return CURLE_OK;
120}
121
122/* returns TRUE if the blobs are identical */
123static bool blobcmp(struct curl_blob *first, struct curl_blob *second)
124{
125 if(!first && !second) /* both are NULL */
126 return TRUE;
127 if(!first || !second) /* one is NULL */
128 return FALSE;
129 if(first->len != second->len) /* different sizes */
130 return FALSE;
131 return !memcmp(first->data, second->data, first->len); /* same data */
132}
133
134#ifdef USE_SSL
135static const struct alpn_spec ALPN_SPEC_H11 = {
136 { ALPN_HTTP_1_1 }, 1
137};
138#ifdef USE_HTTP2
139static const struct alpn_spec ALPN_SPEC_H2_H11 = {
140 { ALPN_H2, ALPN_HTTP_1_1 }, 2
141};
142#endif
143
144static const struct alpn_spec *alpn_get_spec(int httpwant, bool use_alpn)
145{
146 if(!use_alpn)
147 return NULL;
148#ifdef USE_HTTP2
149 if(httpwant >= CURL_HTTP_VERSION_2)
150 return &ALPN_SPEC_H2_H11;
151#else
152 (void)httpwant;
153#endif
154 /* Use the ALPN protocol "http/1.1" for HTTP/1.x.
155 Avoid "http/1.0" because some servers don't support it. */
156 return &ALPN_SPEC_H11;
157}
158#endif /* USE_SSL */
159
160
161void Curl_ssl_easy_config_init(struct Curl_easy *data)
162{
163 /*
164 * libcurl 7.10 introduced SSL verification *by default*! This needs to be
165 * switched off unless wanted.
166 */
167 data->set.ssl.primary.verifypeer = TRUE;
168 data->set.ssl.primary.verifyhost = TRUE;
169 data->set.ssl.primary.sessionid = TRUE; /* session ID caching by default */
170#ifndef CURL_DISABLE_PROXY
171 data->set.proxy_ssl = data->set.ssl;
172#endif
173}
174
175static bool
176match_ssl_primary_config(struct Curl_easy *data,
177 struct ssl_primary_config *c1,
178 struct ssl_primary_config *c2)
179{
180 (void)data;
181 if((c1->version == c2->version) &&
182 (c1->version_max == c2->version_max) &&
183 (c1->ssl_options == c2->ssl_options) &&
184 (c1->verifypeer == c2->verifypeer) &&
185 (c1->verifyhost == c2->verifyhost) &&
186 (c1->verifystatus == c2->verifystatus) &&
187 blobcmp(c1->cert_blob, c2->cert_blob) &&
188 blobcmp(c1->ca_info_blob, c2->ca_info_blob) &&
189 blobcmp(c1->issuercert_blob, c2->issuercert_blob) &&
190 Curl_safecmp(c1->CApath, c2->CApath) &&
191 Curl_safecmp(c1->CAfile, c2->CAfile) &&
192 Curl_safecmp(c1->issuercert, c2->issuercert) &&
193 Curl_safecmp(c1->clientcert, c2->clientcert) &&
194#ifdef USE_TLS_SRP
195 !Curl_timestrcmp(c1->username, c2->username) &&
196 !Curl_timestrcmp(c1->password, c2->password) &&
197#endif
198 strcasecompare(c1->cipher_list, c2->cipher_list) &&
199 strcasecompare(c1->cipher_list13, c2->cipher_list13) &&
200 strcasecompare(c1->curves, c2->curves) &&
201 strcasecompare(c1->CRLfile, c2->CRLfile) &&
202 strcasecompare(c1->pinned_key, c2->pinned_key))
203 return TRUE;
204
205 return FALSE;
206}
207
208bool Curl_ssl_conn_config_match(struct Curl_easy *data,
209 struct connectdata *candidate,
210 bool proxy)
211{
212#ifndef CURL_DISABLE_PROXY
213 if(proxy)
214 return match_ssl_primary_config(data, &data->set.proxy_ssl.primary,
215 &candidate->proxy_ssl_config);
216#else
217 (void)proxy;
218#endif
219 return match_ssl_primary_config(data, &data->set.ssl.primary,
220 &candidate->ssl_config);
221}
222
223static bool clone_ssl_primary_config(struct ssl_primary_config *source,
224 struct ssl_primary_config *dest)
225{
226 dest->version = source->version;
227 dest->version_max = source->version_max;
228 dest->verifypeer = source->verifypeer;
229 dest->verifyhost = source->verifyhost;
230 dest->verifystatus = source->verifystatus;
231 dest->sessionid = source->sessionid;
232 dest->ssl_options = source->ssl_options;
233
234 CLONE_BLOB(cert_blob);
235 CLONE_BLOB(ca_info_blob);
236 CLONE_BLOB(issuercert_blob);
237 CLONE_STRING(CApath);
238 CLONE_STRING(CAfile);
239 CLONE_STRING(issuercert);
240 CLONE_STRING(clientcert);
241 CLONE_STRING(cipher_list);
242 CLONE_STRING(cipher_list13);
243 CLONE_STRING(pinned_key);
244 CLONE_STRING(curves);
245 CLONE_STRING(CRLfile);
246#ifdef USE_TLS_SRP
247 CLONE_STRING(username);
248 CLONE_STRING(password);
249#endif
250
251 return TRUE;
252}
253
254static void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
255{
256 Curl_safefree(sslc->CApath);
257 Curl_safefree(sslc->CAfile);
258 Curl_safefree(sslc->issuercert);
259 Curl_safefree(sslc->clientcert);
260 Curl_safefree(sslc->cipher_list);
261 Curl_safefree(sslc->cipher_list13);
262 Curl_safefree(sslc->pinned_key);
263 Curl_safefree(sslc->cert_blob);
264 Curl_safefree(sslc->ca_info_blob);
265 Curl_safefree(sslc->issuercert_blob);
266 Curl_safefree(sslc->curves);
267 Curl_safefree(sslc->CRLfile);
268#ifdef USE_TLS_SRP
269 Curl_safefree(sslc->username);
270 Curl_safefree(sslc->password);
271#endif
272}
273
274CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data)
275{
276 data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH];
277 data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE];
278 data->set.ssl.primary.CRLfile = data->set.str[STRING_SSL_CRLFILE];
279 data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
280 data->set.ssl.primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
281 data->set.ssl.primary.cipher_list =
282 data->set.str[STRING_SSL_CIPHER_LIST];
283 data->set.ssl.primary.cipher_list13 =
284 data->set.str[STRING_SSL_CIPHER13_LIST];
285 data->set.ssl.primary.pinned_key =
286 data->set.str[STRING_SSL_PINNEDPUBLICKEY];
287 data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT];
288 data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO];
289 data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES];
290#ifdef USE_TLS_SRP
291 data->set.ssl.primary.username = data->set.str[STRING_TLSAUTH_USERNAME];
292 data->set.ssl.primary.password = data->set.str[STRING_TLSAUTH_PASSWORD];
293#endif
294 data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE];
295 data->set.ssl.key = data->set.str[STRING_KEY];
296 data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE];
297 data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD];
298 data->set.ssl.primary.clientcert = data->set.str[STRING_CERT];
299 data->set.ssl.key_blob = data->set.blobs[BLOB_KEY];
300
301#ifndef CURL_DISABLE_PROXY
302 data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
303 data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
304 data->set.proxy_ssl.primary.cipher_list =
305 data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
306 data->set.proxy_ssl.primary.cipher_list13 =
307 data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
308 data->set.proxy_ssl.primary.pinned_key =
309 data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
310 data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
311 data->set.proxy_ssl.primary.ca_info_blob =
312 data->set.blobs[BLOB_CAINFO_PROXY];
313 data->set.proxy_ssl.primary.issuercert =
314 data->set.str[STRING_SSL_ISSUERCERT_PROXY];
315 data->set.proxy_ssl.primary.issuercert_blob =
316 data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY];
317 data->set.proxy_ssl.primary.CRLfile =
318 data->set.str[STRING_SSL_CRLFILE_PROXY];
319 data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
320 data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY];
321 data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
322 data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
323 data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY];
324 data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
325#ifdef USE_TLS_SRP
326 data->set.proxy_ssl.primary.username =
327 data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
328 data->set.proxy_ssl.primary.password =
329 data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
330#endif
331#endif /* CURL_DISABLE_PROXY */
332
333 return CURLE_OK;
334}
335
336CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data,
337 struct connectdata *conn)
338{
339 /* Clone "primary" SSL configurations from the esay handle to
340 * the connection. They are used for connection cache matching and
341 * probably outlive the easy handle */
342 if(!clone_ssl_primary_config(&data->set.ssl.primary, &conn->ssl_config))
343 return CURLE_OUT_OF_MEMORY;
344#ifndef CURL_DISABLE_PROXY
345 if(!clone_ssl_primary_config(&data->set.proxy_ssl.primary,
346 &conn->proxy_ssl_config))
347 return CURLE_OUT_OF_MEMORY;
348#endif
349 return CURLE_OK;
350}
351
352void Curl_ssl_conn_config_cleanup(struct connectdata *conn)
353{
354 Curl_free_primary_ssl_config(&conn->ssl_config);
355#ifndef CURL_DISABLE_PROXY
356 Curl_free_primary_ssl_config(&conn->proxy_ssl_config);
357#endif
358}
359
360void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy)
361{
362 /* May be called on an easy that has no connection yet */
363 if(data->conn) {
364 struct ssl_primary_config *src, *dest;
365#ifndef CURL_DISABLE_PROXY
366 src = for_proxy? &data->set.proxy_ssl.primary : &data->set.ssl.primary;
367 dest = for_proxy? &data->conn->proxy_ssl_config : &data->conn->ssl_config;
368#else
369 (void)for_proxy;
370 src = &data->set.ssl.primary;
371 dest = &data->conn->ssl_config;
372#endif
373 dest->verifyhost = src->verifyhost;
374 dest->verifypeer = src->verifypeer;
375 dest->verifystatus = src->verifystatus;
376 }
377}
378
379#ifdef USE_SSL
380static int multissl_setup(const struct Curl_ssl *backend);
381#endif
382
383curl_sslbackend Curl_ssl_backend(void)
384{
385#ifdef USE_SSL
386 multissl_setup(NULL);
387 return Curl_ssl->info.id;
388#else
389 return CURLSSLBACKEND_NONE;
390#endif
391}
392
393#ifdef USE_SSL
394
395/* "global" init done? */
396static bool init_ssl = FALSE;
397
398/**
399 * Global SSL init
400 *
401 * @retval 0 error initializing SSL
402 * @retval 1 SSL initialized successfully
403 */
404int Curl_ssl_init(void)
405{
406 /* make sure this is only done once */
407 if(init_ssl)
408 return 1;
409 init_ssl = TRUE; /* never again */
410
411 return Curl_ssl->init();
412}
413
414#if defined(CURL_WITH_MULTI_SSL)
415static const struct Curl_ssl Curl_ssl_multi;
416#endif
417
418/* Global cleanup */
419void Curl_ssl_cleanup(void)
420{
421 if(init_ssl) {
422 /* only cleanup if we did a previous init */
423 Curl_ssl->cleanup();
424#if defined(CURL_WITH_MULTI_SSL)
425 Curl_ssl = &Curl_ssl_multi;
426#endif
427 init_ssl = FALSE;
428 }
429}
430
431static bool ssl_prefs_check(struct Curl_easy *data)
432{
433 /* check for CURLOPT_SSLVERSION invalid parameter value */
434 const unsigned char sslver = data->set.ssl.primary.version;
435 if(sslver >= CURL_SSLVERSION_LAST) {
436 failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION");
437 return FALSE;
438 }
439
440 switch(data->set.ssl.primary.version_max) {
441 case CURL_SSLVERSION_MAX_NONE:
442 case CURL_SSLVERSION_MAX_DEFAULT:
443 break;
444
445 default:
446 if((data->set.ssl.primary.version_max >> 16) < sslver) {
447 failf(data, "CURL_SSLVERSION_MAX incompatible with CURL_SSLVERSION");
448 return FALSE;
449 }
450 }
451
452 return TRUE;
453}
454
455static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data,
456 const struct alpn_spec *alpn)
457{
458 struct ssl_connect_data *ctx;
459
460 (void)data;
461 ctx = calloc(1, sizeof(*ctx));
462 if(!ctx)
463 return NULL;
464
465 ctx->alpn = alpn;
466 ctx->backend = calloc(1, Curl_ssl->sizeof_ssl_backend_data);
467 if(!ctx->backend) {
468 free(ctx);
469 return NULL;
470 }
471 return ctx;
472}
473
474static void cf_ctx_free(struct ssl_connect_data *ctx)
475{
476 if(ctx) {
477 free(ctx->backend);
478 free(ctx);
479 }
480}
481
482static CURLcode ssl_connect(struct Curl_cfilter *cf, struct Curl_easy *data)
483{
484 struct ssl_connect_data *connssl = cf->ctx;
485 CURLcode result;
486
487 if(!ssl_prefs_check(data))
488 return CURLE_SSL_CONNECT_ERROR;
489
490 /* mark this is being ssl-enabled from here on. */
491 connssl->state = ssl_connection_negotiating;
492
493 result = Curl_ssl->connect_blocking(cf, data);
494
495 if(!result) {
496 DEBUGASSERT(connssl->state == ssl_connection_complete);
497 }
498
499 return result;
500}
501
502static CURLcode
503ssl_connect_nonblocking(struct Curl_cfilter *cf, struct Curl_easy *data,
504 bool *done)
505{
506 if(!ssl_prefs_check(data))
507 return CURLE_SSL_CONNECT_ERROR;
508
509 /* mark this is being ssl requested from here on. */
510 return Curl_ssl->connect_nonblocking(cf, data, done);
511}
512
513/*
514 * Lock shared SSL session data
515 */
516void Curl_ssl_sessionid_lock(struct Curl_easy *data)
517{
518 if(SSLSESSION_SHARED(data))
519 Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
520}
521
522/*
523 * Unlock shared SSL session data
524 */
525void Curl_ssl_sessionid_unlock(struct Curl_easy *data)
526{
527 if(SSLSESSION_SHARED(data))
528 Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
529}
530
531/*
532 * Check if there's a session ID for the given connection in the cache, and if
533 * there's one suitable, it is provided. Returns TRUE when no entry matched.
534 */
535bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
536 struct Curl_easy *data,
537 void **ssl_sessionid,
538 size_t *idsize) /* set 0 if unknown */
539{
540 struct ssl_connect_data *connssl = cf->ctx;
541 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
542 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
543 struct Curl_ssl_session *check;
544 size_t i;
545 long *general_age;
546 bool no_match = TRUE;
547
548 *ssl_sessionid = NULL;
549 if(!ssl_config)
550 return TRUE;
551
552 DEBUGASSERT(ssl_config->primary.sessionid);
553
554 if(!ssl_config->primary.sessionid || !data->state.session)
555 /* session ID reuse is disabled or the session cache has not been
556 setup */
557 return TRUE;
558
559 /* Lock if shared */
560 if(SSLSESSION_SHARED(data))
561 general_age = &data->share->sessionage;
562 else
563 general_age = &data->state.sessionage;
564
565 for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
566 check = &data->state.session[i];
567 if(!check->sessionid)
568 /* not session ID means blank entry */
569 continue;
570 if(strcasecompare(connssl->peer.hostname, check->name) &&
571 ((!cf->conn->bits.conn_to_host && !check->conn_to_host) ||
572 (cf->conn->bits.conn_to_host && check->conn_to_host &&
573 strcasecompare(cf->conn->conn_to_host.name, check->conn_to_host))) &&
574 ((!cf->conn->bits.conn_to_port && check->conn_to_port == -1) ||
575 (cf->conn->bits.conn_to_port && check->conn_to_port != -1 &&
576 cf->conn->conn_to_port == check->conn_to_port)) &&
577 (connssl->port == check->remote_port) &&
578 strcasecompare(cf->conn->handler->scheme, check->scheme) &&
579 match_ssl_primary_config(data, conn_config, &check->ssl_config)) {
580 /* yes, we have a session ID! */
581 (*general_age)++; /* increase general age */
582 check->age = *general_age; /* set this as used in this age */
583 *ssl_sessionid = check->sessionid;
584 if(idsize)
585 *idsize = check->idsize;
586 no_match = FALSE;
587 break;
588 }
589 }
590
591 DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d",
592 no_match? "Didn't find": "Found",
593 Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host",
594 cf->conn->handler->scheme, connssl->peer.hostname,
595 connssl->port));
596 return no_match;
597}
598
599/*
600 * Kill a single session ID entry in the cache.
601 */
602void Curl_ssl_kill_session(struct Curl_ssl_session *session)
603{
604 if(session->sessionid) {
605 /* defensive check */
606
607 /* free the ID the SSL-layer specific way */
608 Curl_ssl->session_free(session->sessionid);
609
610 session->sessionid = NULL;
611 session->age = 0; /* fresh */
612
613 Curl_free_primary_ssl_config(&session->ssl_config);
614
615 Curl_safefree(session->name);
616 Curl_safefree(session->conn_to_host);
617 }
618}
619
620/*
621 * Delete the given session ID from the cache.
622 */
623void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid)
624{
625 size_t i;
626
627 for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
628 struct Curl_ssl_session *check = &data->state.session[i];
629
630 if(check->sessionid == ssl_sessionid) {
631 Curl_ssl_kill_session(check);
632 break;
633 }
634 }
635}
636
637/*
638 * Store session id in the session cache. The ID passed on to this function
639 * must already have been extracted and allocated the proper way for the SSL
640 * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
641 * later on.
642 */
643CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
644 struct Curl_easy *data,
645 void *ssl_sessionid,
646 size_t idsize,
647 bool *added)
648{
649 struct ssl_connect_data *connssl = cf->ctx;
650 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
651 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
652 size_t i;
653 struct Curl_ssl_session *store;
654 long oldest_age;
655 char *clone_host;
656 char *clone_conn_to_host;
657 int conn_to_port;
658 long *general_age;
659
660 if(added)
661 *added = FALSE;
662
663 if(!data->state.session)
664 return CURLE_OK;
665
666 store = &data->state.session[0];
667 oldest_age = data->state.session[0].age; /* zero if unused */
668 (void)ssl_config;
669 DEBUGASSERT(ssl_config->primary.sessionid);
670
671 clone_host = strdup(connssl->peer.hostname);
672 if(!clone_host)
673 return CURLE_OUT_OF_MEMORY; /* bail out */
674
675 if(cf->conn->bits.conn_to_host) {
676 clone_conn_to_host = strdup(cf->conn->conn_to_host.name);
677 if(!clone_conn_to_host) {
678 free(clone_host);
679 return CURLE_OUT_OF_MEMORY; /* bail out */
680 }
681 }
682 else
683 clone_conn_to_host = NULL;
684
685 if(cf->conn->bits.conn_to_port)
686 conn_to_port = cf->conn->conn_to_port;
687 else
688 conn_to_port = -1;
689
690 /* Now we should add the session ID and the host name to the cache, (remove
691 the oldest if necessary) */
692
693 /* If using shared SSL session, lock! */
694 if(SSLSESSION_SHARED(data)) {
695 general_age = &data->share->sessionage;
696 }
697 else {
698 general_age = &data->state.sessionage;
699 }
700
701 /* find an empty slot for us, or find the oldest */
702 for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) &&
703 data->state.session[i].sessionid; i++) {
704 if(data->state.session[i].age < oldest_age) {
705 oldest_age = data->state.session[i].age;
706 store = &data->state.session[i];
707 }
708 }
709 if(i == data->set.general_ssl.max_ssl_sessions)
710 /* cache is full, we must "kill" the oldest entry! */
711 Curl_ssl_kill_session(store);
712 else
713 store = &data->state.session[i]; /* use this slot */
714
715 /* now init the session struct wisely */
716 store->sessionid = ssl_sessionid;
717 store->idsize = idsize;
718 store->age = *general_age; /* set current age */
719 /* free it if there's one already present */
720 free(store->name);
721 free(store->conn_to_host);
722 store->name = clone_host; /* clone host name */
723 store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
724 store->conn_to_port = conn_to_port; /* connect to port number */
725 /* port number */
726 store->remote_port = connssl->port;
727 store->scheme = cf->conn->handler->scheme;
728
729 if(!clone_ssl_primary_config(conn_config, &store->ssl_config)) {
730 Curl_free_primary_ssl_config(&store->ssl_config);
731 store->sessionid = NULL; /* let caller free sessionid */
732 free(clone_host);
733 free(clone_conn_to_host);
734 return CURLE_OUT_OF_MEMORY;
735 }
736
737 if(added)
738 *added = TRUE;
739
740 DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]",
741 store->scheme, store->name, store->remote_port,
742 Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server"));
743 return CURLE_OK;
744}
745
746void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend)
747{
748 if(Curl_ssl->free_multi_ssl_backend_data && mbackend)
749 Curl_ssl->free_multi_ssl_backend_data(mbackend);
750}
751
752void Curl_ssl_close_all(struct Curl_easy *data)
753{
754 /* kill the session ID cache if not shared */
755 if(data->state.session && !SSLSESSION_SHARED(data)) {
756 size_t i;
757 for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++)
758 /* the single-killer function handles empty table slots */
759 Curl_ssl_kill_session(&data->state.session[i]);
760
761 /* free the cache data */
762 Curl_safefree(data->state.session);
763 }
764
765 Curl_ssl->close_all(data);
766}
767
768void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data,
769 struct easy_pollset *ps)
770{
771 if(!cf->connected) {
772 struct ssl_connect_data *connssl = cf->ctx;
773 curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
774 if(sock != CURL_SOCKET_BAD) {
775 if(connssl->connecting_state == ssl_connect_2_writing) {
776 Curl_pollset_set_out_only(data, ps, sock);
777 CURL_TRC_CF(data, cf, "adjust_pollset, POLLOUT fd=%"
778 CURL_FORMAT_SOCKET_T, sock);
779 }
780 else {
781 Curl_pollset_set_in_only(data, ps, sock);
782 CURL_TRC_CF(data, cf, "adjust_pollset, POLLIN fd=%"
783 CURL_FORMAT_SOCKET_T, sock);
784 }
785 }
786 }
787}
788
789/* Selects an SSL crypto engine
790 */
791CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine)
792{
793 return Curl_ssl->set_engine(data, engine);
794}
795
796/* Selects the default SSL crypto engine
797 */
798CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data)
799{
800 return Curl_ssl->set_engine_default(data);
801}
802
803/* Return list of OpenSSL crypto engine names. */
804struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data)
805{
806 return Curl_ssl->engines_list(data);
807}
808
809/*
810 * This sets up a session ID cache to the specified size. Make sure this code
811 * is agnostic to what underlying SSL technology we use.
812 */
813CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount)
814{
815 struct Curl_ssl_session *session;
816
817 if(data->state.session)
818 /* this is just a precaution to prevent multiple inits */
819 return CURLE_OK;
820
821 session = calloc(amount, sizeof(struct Curl_ssl_session));
822 if(!session)
823 return CURLE_OUT_OF_MEMORY;
824
825 /* store the info in the SSL section */
826 data->set.general_ssl.max_ssl_sessions = amount;
827 data->state.session = session;
828 data->state.sessionage = 1; /* this is brand new */
829 return CURLE_OK;
830}
831
832static size_t multissl_version(char *buffer, size_t size);
833
834void Curl_ssl_version(char *buffer, size_t size)
835{
836#ifdef CURL_WITH_MULTI_SSL
837 (void)multissl_version(buffer, size);
838#else
839 (void)Curl_ssl->version(buffer, size);
840#endif
841}
842
843void Curl_ssl_free_certinfo(struct Curl_easy *data)
844{
845 struct curl_certinfo *ci = &data->info.certs;
846
847 if(ci->num_of_certs) {
848 /* free all individual lists used */
849 int i;
850 for(i = 0; i<ci->num_of_certs; i++) {
851 curl_slist_free_all(ci->certinfo[i]);
852 ci->certinfo[i] = NULL;
853 }
854
855 free(ci->certinfo); /* free the actual array too */
856 ci->certinfo = NULL;
857 ci->num_of_certs = 0;
858 }
859}
860
861CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num)
862{
863 struct curl_certinfo *ci = &data->info.certs;
864 struct curl_slist **table;
865
866 /* Free any previous certificate information structures */
867 Curl_ssl_free_certinfo(data);
868
869 /* Allocate the required certificate information structures */
870 table = calloc((size_t) num, sizeof(struct curl_slist *));
871 if(!table)
872 return CURLE_OUT_OF_MEMORY;
873
874 ci->num_of_certs = num;
875 ci->certinfo = table;
876
877 return CURLE_OK;
878}
879
880/*
881 * 'value' is NOT a null-terminated string
882 */
883CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
884 int certnum,
885 const char *label,
886 const char *value,
887 size_t valuelen)
888{
889 struct curl_certinfo *ci = &data->info.certs;
890 struct curl_slist *nl;
891 CURLcode result = CURLE_OK;
892 struct dynbuf build;
893
894 Curl_dyn_init(&build, 10000);
895
896 if(Curl_dyn_add(&build, label) ||
897 Curl_dyn_addn(&build, ":", 1) ||
898 Curl_dyn_addn(&build, value, valuelen))
899 return CURLE_OUT_OF_MEMORY;
900
901 nl = Curl_slist_append_nodup(ci->certinfo[certnum],
902 Curl_dyn_ptr(&build));
903 if(!nl) {
904 Curl_dyn_free(&build);
905 curl_slist_free_all(ci->certinfo[certnum]);
906 result = CURLE_OUT_OF_MEMORY;
907 }
908
909 ci->certinfo[certnum] = nl;
910 return result;
911}
912
913CURLcode Curl_ssl_random(struct Curl_easy *data,
914 unsigned char *entropy,
915 size_t length)
916{
917 return Curl_ssl->random(data, entropy, length);
918}
919
920/*
921 * Public key pem to der conversion
922 */
923
924static CURLcode pubkey_pem_to_der(const char *pem,
925 unsigned char **der, size_t *der_len)
926{
927 char *stripped_pem, *begin_pos, *end_pos;
928 size_t pem_count, stripped_pem_count = 0, pem_len;
929 CURLcode result;
930
931 /* if no pem, exit. */
932 if(!pem)
933 return CURLE_BAD_CONTENT_ENCODING;
934
935 begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----");
936 if(!begin_pos)
937 return CURLE_BAD_CONTENT_ENCODING;
938
939 pem_count = begin_pos - pem;
940 /* Invalid if not at beginning AND not directly following \n */
941 if(0 != pem_count && '\n' != pem[pem_count - 1])
942 return CURLE_BAD_CONTENT_ENCODING;
943
944 /* 26 is length of "-----BEGIN PUBLIC KEY-----" */
945 pem_count += 26;
946
947 /* Invalid if not directly following \n */
948 end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----");
949 if(!end_pos)
950 return CURLE_BAD_CONTENT_ENCODING;
951
952 pem_len = end_pos - pem;
953
954 stripped_pem = malloc(pem_len - pem_count + 1);
955 if(!stripped_pem)
956 return CURLE_OUT_OF_MEMORY;
957
958 /*
959 * Here we loop through the pem array one character at a time between the
960 * correct indices, and place each character that is not '\n' or '\r'
961 * into the stripped_pem array, which should represent the raw base64 string
962 */
963 while(pem_count < pem_len) {
964 if('\n' != pem[pem_count] && '\r' != pem[pem_count])
965 stripped_pem[stripped_pem_count++] = pem[pem_count];
966 ++pem_count;
967 }
968 /* Place the null terminator in the correct place */
969 stripped_pem[stripped_pem_count] = '\0';
970
971 result = Curl_base64_decode(stripped_pem, der, der_len);
972
973 Curl_safefree(stripped_pem);
974
975 return result;
976}
977
978/*
979 * Generic pinned public key check.
980 */
981
982CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
983 const char *pinnedpubkey,
984 const unsigned char *pubkey, size_t pubkeylen)
985{
986 FILE *fp;
987 unsigned char *buf = NULL, *pem_ptr = NULL;
988 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
989#ifdef CURL_DISABLE_VERBOSE_STRINGS
990 (void)data;
991#endif
992
993 /* if a path wasn't specified, don't pin */
994 if(!pinnedpubkey)
995 return CURLE_OK;
996 if(!pubkey || !pubkeylen)
997 return result;
998
999 /* only do this if pinnedpubkey starts with "sha256//", length 8 */
1000 if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
1001 CURLcode encode;
1002 size_t encodedlen = 0;
1003 char *encoded = NULL, *pinkeycopy, *begin_pos, *end_pos;
1004 unsigned char *sha256sumdigest;
1005
1006 if(!Curl_ssl->sha256sum) {
1007 /* without sha256 support, this cannot match */
1008 return result;
1009 }
1010
1011 /* compute sha256sum of public key */
1012 sha256sumdigest = malloc(CURL_SHA256_DIGEST_LENGTH);
1013 if(!sha256sumdigest)
1014 return CURLE_OUT_OF_MEMORY;
1015 encode = Curl_ssl->sha256sum(pubkey, pubkeylen,
1016 sha256sumdigest, CURL_SHA256_DIGEST_LENGTH);
1017
1018 if(!encode)
1019 encode = Curl_base64_encode((char *)sha256sumdigest,
1020 CURL_SHA256_DIGEST_LENGTH, &encoded,
1021 &encodedlen);
1022 Curl_safefree(sha256sumdigest);
1023
1024 if(encode)
1025 return encode;
1026
1027 infof(data, " public key hash: sha256//%s", encoded);
1028
1029 /* it starts with sha256//, copy so we can modify it */
1030 pinkeycopy = strdup(pinnedpubkey);
1031 if(!pinkeycopy) {
1032 Curl_safefree(encoded);
1033 return CURLE_OUT_OF_MEMORY;
1034 }
1035 /* point begin_pos to the copy, and start extracting keys */
1036 begin_pos = pinkeycopy;
1037 do {
1038 end_pos = strstr(begin_pos, ";sha256//");
1039 /*
1040 * if there is an end_pos, null terminate,
1041 * otherwise it'll go to the end of the original string
1042 */
1043 if(end_pos)
1044 end_pos[0] = '\0';
1045
1046 /* compare base64 sha256 digests, 8 is the length of "sha256//" */
1047 if(encodedlen == strlen(begin_pos + 8) &&
1048 !memcmp(encoded, begin_pos + 8, encodedlen)) {
1049 result = CURLE_OK;
1050 break;
1051 }
1052
1053 /*
1054 * change back the null-terminator we changed earlier,
1055 * and look for next begin
1056 */
1057 if(end_pos) {
1058 end_pos[0] = ';';
1059 begin_pos = strstr(end_pos, "sha256//");
1060 }
1061 } while(end_pos && begin_pos);
1062 Curl_safefree(encoded);
1063 Curl_safefree(pinkeycopy);
1064 return result;
1065 }
1066
1067 fp = fopen(pinnedpubkey, "rb");
1068 if(!fp)
1069 return result;
1070
1071 do {
1072 long filesize;
1073 size_t size, pem_len;
1074 CURLcode pem_read;
1075
1076 /* Determine the file's size */
1077 if(fseek(fp, 0, SEEK_END))
1078 break;
1079 filesize = ftell(fp);
1080 if(fseek(fp, 0, SEEK_SET))
1081 break;
1082 if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE)
1083 break;
1084
1085 /*
1086 * if the size of our certificate is bigger than the file
1087 * size then it can't match
1088 */
1089 size = curlx_sotouz((curl_off_t) filesize);
1090 if(pubkeylen > size)
1091 break;
1092
1093 /*
1094 * Allocate buffer for the pinned key
1095 * With 1 additional byte for null terminator in case of PEM key
1096 */
1097 buf = malloc(size + 1);
1098 if(!buf)
1099 break;
1100
1101 /* Returns number of elements read, which should be 1 */
1102 if((int) fread(buf, size, 1, fp) != 1)
1103 break;
1104
1105 /* If the sizes are the same, it can't be base64 encoded, must be der */
1106 if(pubkeylen == size) {
1107 if(!memcmp(pubkey, buf, pubkeylen))
1108 result = CURLE_OK;
1109 break;
1110 }
1111
1112 /*
1113 * Otherwise we will assume it's PEM and try to decode it
1114 * after placing null terminator
1115 */
1116 buf[size] = '\0';
1117 pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
1118 /* if it wasn't read successfully, exit */
1119 if(pem_read)
1120 break;
1121
1122 /*
1123 * if the size of our certificate doesn't match the size of
1124 * the decoded file, they can't be the same, otherwise compare
1125 */
1126 if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
1127 result = CURLE_OK;
1128 } while(0);
1129
1130 Curl_safefree(buf);
1131 Curl_safefree(pem_ptr);
1132 fclose(fp);
1133
1134 return result;
1135}
1136
1137/*
1138 * Check whether the SSL backend supports the status_request extension.
1139 */
1140bool Curl_ssl_cert_status_request(void)
1141{
1142 return Curl_ssl->cert_status_request();
1143}
1144
1145/*
1146 * Check whether the SSL backend supports false start.
1147 */
1148bool Curl_ssl_false_start(struct Curl_easy *data)
1149{
1150 (void)data;
1151 return Curl_ssl->false_start();
1152}
1153
1154/*
1155 * Default implementations for unsupported functions.
1156 */
1157
1158int Curl_none_init(void)
1159{
1160 return 1;
1161}
1162
1163void Curl_none_cleanup(void)
1164{ }
1165
1166int Curl_none_shutdown(struct Curl_cfilter *cf UNUSED_PARAM,
1167 struct Curl_easy *data UNUSED_PARAM)
1168{
1169 (void)data;
1170 (void)cf;
1171 return 0;
1172}
1173
1174int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
1175{
1176 (void)cf;
1177 (void)data;
1178 return -1;
1179}
1180
1181CURLcode Curl_none_random(struct Curl_easy *data UNUSED_PARAM,
1182 unsigned char *entropy UNUSED_PARAM,
1183 size_t length UNUSED_PARAM)
1184{
1185 (void)data;
1186 (void)entropy;
1187 (void)length;
1188 return CURLE_NOT_BUILT_IN;
1189}
1190
1191void Curl_none_close_all(struct Curl_easy *data UNUSED_PARAM)
1192{
1193 (void)data;
1194}
1195
1196void Curl_none_session_free(void *ptr UNUSED_PARAM)
1197{
1198 (void)ptr;
1199}
1200
1201bool Curl_none_data_pending(struct Curl_cfilter *cf UNUSED_PARAM,
1202 const struct Curl_easy *data UNUSED_PARAM)
1203{
1204 (void)cf;
1205 (void)data;
1206 return 0;
1207}
1208
1209bool Curl_none_cert_status_request(void)
1210{
1211 return FALSE;
1212}
1213
1214CURLcode Curl_none_set_engine(struct Curl_easy *data UNUSED_PARAM,
1215 const char *engine UNUSED_PARAM)
1216{
1217 (void)data;
1218 (void)engine;
1219 return CURLE_NOT_BUILT_IN;
1220}
1221
1222CURLcode Curl_none_set_engine_default(struct Curl_easy *data UNUSED_PARAM)
1223{
1224 (void)data;
1225 return CURLE_NOT_BUILT_IN;
1226}
1227
1228struct curl_slist *Curl_none_engines_list(struct Curl_easy *data UNUSED_PARAM)
1229{
1230 (void)data;
1231 return (struct curl_slist *)NULL;
1232}
1233
1234bool Curl_none_false_start(void)
1235{
1236 return FALSE;
1237}
1238
1239static int multissl_init(void)
1240{
1241 if(multissl_setup(NULL))
1242 return 1;
1243 return Curl_ssl->init();
1244}
1245
1246static CURLcode multissl_connect(struct Curl_cfilter *cf,
1247 struct Curl_easy *data)
1248{
1249 if(multissl_setup(NULL))
1250 return CURLE_FAILED_INIT;
1251 return Curl_ssl->connect_blocking(cf, data);
1252}
1253
1254static CURLcode multissl_connect_nonblocking(struct Curl_cfilter *cf,
1255 struct Curl_easy *data,
1256 bool *done)
1257{
1258 if(multissl_setup(NULL))
1259 return CURLE_FAILED_INIT;
1260 return Curl_ssl->connect_nonblocking(cf, data, done);
1261}
1262
1263static void multissl_adjust_pollset(struct Curl_cfilter *cf,
1264 struct Curl_easy *data,
1265 struct easy_pollset *ps)
1266{
1267 if(multissl_setup(NULL))
1268 return;
1269 Curl_ssl->adjust_pollset(cf, data, ps);
1270}
1271
1272static void *multissl_get_internals(struct ssl_connect_data *connssl,
1273 CURLINFO info)
1274{
1275 if(multissl_setup(NULL))
1276 return NULL;
1277 return Curl_ssl->get_internals(connssl, info);
1278}
1279
1280static void multissl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
1281{
1282 if(multissl_setup(NULL))
1283 return;
1284 Curl_ssl->close(cf, data);
1285}
1286
1287static ssize_t multissl_recv_plain(struct Curl_cfilter *cf,
1288 struct Curl_easy *data,
1289 char *buf, size_t len, CURLcode *code)
1290{
1291 if(multissl_setup(NULL))
1292 return CURLE_FAILED_INIT;
1293 return Curl_ssl->recv_plain(cf, data, buf, len, code);
1294}
1295
1296static ssize_t multissl_send_plain(struct Curl_cfilter *cf,
1297 struct Curl_easy *data,
1298 const void *mem, size_t len,
1299 CURLcode *code)
1300{
1301 if(multissl_setup(NULL))
1302 return CURLE_FAILED_INIT;
1303 return Curl_ssl->send_plain(cf, data, mem, len, code);
1304}
1305
1306static const struct Curl_ssl Curl_ssl_multi = {
1307 { CURLSSLBACKEND_NONE, "multi" }, /* info */
1308 0, /* supports nothing */
1309 (size_t)-1, /* something insanely large to be on the safe side */
1310
1311 multissl_init, /* init */
1312 Curl_none_cleanup, /* cleanup */
1313 multissl_version, /* version */
1314 Curl_none_check_cxn, /* check_cxn */
1315 Curl_none_shutdown, /* shutdown */
1316 Curl_none_data_pending, /* data_pending */
1317 Curl_none_random, /* random */
1318 Curl_none_cert_status_request, /* cert_status_request */
1319 multissl_connect, /* connect */
1320 multissl_connect_nonblocking, /* connect_nonblocking */
1321 multissl_adjust_pollset, /* adjust_pollset */
1322 multissl_get_internals, /* get_internals */
1323 multissl_close, /* close_one */
1324 Curl_none_close_all, /* close_all */
1325 Curl_none_session_free, /* session_free */
1326 Curl_none_set_engine, /* set_engine */
1327 Curl_none_set_engine_default, /* set_engine_default */
1328 Curl_none_engines_list, /* engines_list */
1329 Curl_none_false_start, /* false_start */
1330 NULL, /* sha256sum */
1331 NULL, /* associate_connection */
1332 NULL, /* disassociate_connection */
1333 NULL, /* free_multi_ssl_backend_data */
1334 multissl_recv_plain, /* recv decrypted data */
1335 multissl_send_plain, /* send data to encrypt */
1336};
1337
1338const struct Curl_ssl *Curl_ssl =
1339#if defined(CURL_WITH_MULTI_SSL)
1340 &Curl_ssl_multi;
1341#elif defined(USE_WOLFSSL)
1342 &Curl_ssl_wolfssl;
1343#elif defined(USE_SECTRANSP)
1344 &Curl_ssl_sectransp;
1345#elif defined(USE_GNUTLS)
1346 &Curl_ssl_gnutls;
1347#elif defined(USE_MBEDTLS)
1348 &Curl_ssl_mbedtls;
1349#elif defined(USE_RUSTLS)
1350 &Curl_ssl_rustls;
1351#elif defined(USE_OPENSSL)
1352 &Curl_ssl_openssl;
1353#elif defined(USE_SCHANNEL)
1354 &Curl_ssl_schannel;
1355#elif defined(USE_BEARSSL)
1356 &Curl_ssl_bearssl;
1357#else
1358#error "Missing struct Curl_ssl for selected SSL backend"
1359#endif
1360
1361static const struct Curl_ssl *available_backends[] = {
1362#if defined(USE_WOLFSSL)
1363 &Curl_ssl_wolfssl,
1364#endif
1365#if defined(USE_SECTRANSP)
1366 &Curl_ssl_sectransp,
1367#endif
1368#if defined(USE_GNUTLS)
1369 &Curl_ssl_gnutls,
1370#endif
1371#if defined(USE_MBEDTLS)
1372 &Curl_ssl_mbedtls,
1373#endif
1374#if defined(USE_OPENSSL)
1375 &Curl_ssl_openssl,
1376#endif
1377#if defined(USE_SCHANNEL)
1378 &Curl_ssl_schannel,
1379#endif
1380#if defined(USE_BEARSSL)
1381 &Curl_ssl_bearssl,
1382#endif
1383#if defined(USE_RUSTLS)
1384 &Curl_ssl_rustls,
1385#endif
1386 NULL
1387};
1388
1389static size_t multissl_version(char *buffer, size_t size)
1390{
1391 static const struct Curl_ssl *selected;
1392 static char backends[200];
1393 static size_t backends_len;
1394 const struct Curl_ssl *current;
1395
1396 current = Curl_ssl == &Curl_ssl_multi ? available_backends[0] : Curl_ssl;
1397
1398 if(current != selected) {
1399 char *p = backends;
1400 char *end = backends + sizeof(backends);
1401 int i;
1402
1403 selected = current;
1404
1405 backends[0] = '\0';
1406
1407 for(i = 0; available_backends[i]; ++i) {
1408 char vb[200];
1409 bool paren = (selected != available_backends[i]);
1410
1411 if(available_backends[i]->version(vb, sizeof(vb))) {
1412 p += msnprintf(p, end - p, "%s%s%s%s", (p != backends ? " " : ""),
1413 (paren ? "(" : ""), vb, (paren ? ")" : ""));
1414 }
1415 }
1416
1417 backends_len = p - backends;
1418 }
1419
1420 if(size) {
1421 if(backends_len < size)
1422 strcpy(buffer, backends);
1423 else
1424 *buffer = 0; /* did not fit */
1425 }
1426 return 0;
1427}
1428
1429static int multissl_setup(const struct Curl_ssl *backend)
1430{
1431 const char *env;
1432 char *env_tmp;
1433
1434 if(Curl_ssl != &Curl_ssl_multi)
1435 return 1;
1436
1437 if(backend) {
1438 Curl_ssl = backend;
1439 return 0;
1440 }
1441
1442 if(!available_backends[0])
1443 return 1;
1444
1445 env = env_tmp = curl_getenv("CURL_SSL_BACKEND");
1446#ifdef CURL_DEFAULT_SSL_BACKEND
1447 if(!env)
1448 env = CURL_DEFAULT_SSL_BACKEND;
1449#endif
1450 if(env) {
1451 int i;
1452 for(i = 0; available_backends[i]; i++) {
1453 if(strcasecompare(env, available_backends[i]->info.name)) {
1454 Curl_ssl = available_backends[i];
1455 free(env_tmp);
1456 return 0;
1457 }
1458 }
1459 }
1460
1461 /* Fall back to first available backend */
1462 Curl_ssl = available_backends[0];
1463 free(env_tmp);
1464 return 0;
1465}
1466
1467/* This function is used to select the SSL backend to use. It is called by
1468 curl_global_sslset (easy.c) which uses the global init lock. */
1469CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
1470 const curl_ssl_backend ***avail)
1471{
1472 int i;
1473
1474 if(avail)
1475 *avail = (const curl_ssl_backend **)&available_backends;
1476
1477 if(Curl_ssl != &Curl_ssl_multi)
1478 return id == Curl_ssl->info.id ||
1479 (name && strcasecompare(name, Curl_ssl->info.name)) ?
1480 CURLSSLSET_OK :
1481#if defined(CURL_WITH_MULTI_SSL)
1482 CURLSSLSET_TOO_LATE;
1483#else
1484 CURLSSLSET_UNKNOWN_BACKEND;
1485#endif
1486
1487 for(i = 0; available_backends[i]; i++) {
1488 if(available_backends[i]->info.id == id ||
1489 (name && strcasecompare(available_backends[i]->info.name, name))) {
1490 multissl_setup(available_backends[i]);
1491 return CURLSSLSET_OK;
1492 }
1493 }
1494
1495 return CURLSSLSET_UNKNOWN_BACKEND;
1496}
1497
1498#else /* USE_SSL */
1499CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
1500 const curl_ssl_backend ***avail)
1501{
1502 (void)id;
1503 (void)name;
1504 (void)avail;
1505 return CURLSSLSET_NO_BACKENDS;
1506}
1507
1508#endif /* !USE_SSL */
1509
1510#ifdef USE_SSL
1511
1512void Curl_ssl_peer_cleanup(struct ssl_peer *peer)
1513{
1514 if(peer->dispname != peer->hostname)
1515 free(peer->dispname);
1516 free(peer->sni);
1517 free(peer->hostname);
1518 peer->hostname = peer->sni = peer->dispname = NULL;
1519 peer->type = CURL_SSL_PEER_DNS;
1520}
1521
1522static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
1523{
1524 struct ssl_connect_data *connssl = cf->ctx;
1525 if(connssl) {
1526 Curl_ssl->close(cf, data);
1527 connssl->state = ssl_connection_none;
1528 Curl_ssl_peer_cleanup(&connssl->peer);
1529 }
1530 cf->connected = FALSE;
1531}
1532
1533static ssl_peer_type get_peer_type(const char *hostname)
1534{
1535 if(hostname && hostname[0]) {
1536#ifdef ENABLE_IPV6
1537 struct in6_addr addr;
1538#else
1539 struct in_addr addr;
1540#endif
1541 if(Curl_inet_pton(AF_INET, hostname, &addr))
1542 return CURL_SSL_PEER_IPV4;
1543#ifdef ENABLE_IPV6
1544 else if(Curl_inet_pton(AF_INET6, hostname, &addr)) {
1545 return CURL_SSL_PEER_IPV6;
1546 }
1547#endif
1548 }
1549 return CURL_SSL_PEER_DNS;
1550}
1551
1552CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
1553{
1554 struct ssl_connect_data *connssl = cf->ctx;
1555 const char *ehostname, *edispname;
1556 int eport;
1557
1558 /* We need the hostname for SNI negotiation. Once handshaked, this
1559 * remains the SNI hostname for the TLS connection. But when the
1560 * connection is reused, the settings in cf->conn might change.
1561 * So we keep a copy of the hostname we use for SNI.
1562 */
1563#ifndef CURL_DISABLE_PROXY
1564 if(Curl_ssl_cf_is_proxy(cf)) {
1565 ehostname = cf->conn->http_proxy.host.name;
1566 edispname = cf->conn->http_proxy.host.dispname;
1567 eport = cf->conn->http_proxy.port;
1568 }
1569 else
1570#endif
1571 {
1572 ehostname = cf->conn->host.name;
1573 edispname = cf->conn->host.dispname;
1574 eport = cf->conn->remote_port;
1575 }
1576
1577 /* change if ehostname changed */
1578 DEBUGASSERT(!ehostname || ehostname[0]);
1579 if(ehostname && (!peer->hostname
1580 || strcmp(ehostname, peer->hostname))) {
1581 Curl_ssl_peer_cleanup(peer);
1582 peer->hostname = strdup(ehostname);
1583 if(!peer->hostname) {
1584 Curl_ssl_peer_cleanup(peer);
1585 return CURLE_OUT_OF_MEMORY;
1586 }
1587 if(!edispname || !strcmp(ehostname, edispname))
1588 peer->dispname = peer->hostname;
1589 else {
1590 peer->dispname = strdup(edispname);
1591 if(!peer->dispname) {
1592 Curl_ssl_peer_cleanup(peer);
1593 return CURLE_OUT_OF_MEMORY;
1594 }
1595 }
1596
1597 peer->sni = NULL;
1598 peer->type = get_peer_type(peer->hostname);
1599 if(peer->type == CURL_SSL_PEER_DNS && peer->hostname[0]) {
1600 /* not an IP address, normalize according to RCC 6066 ch. 3,
1601 * max len of SNI is 2^16-1, no trailing dot */
1602 size_t len = strlen(peer->hostname);
1603 if(len && (peer->hostname[len-1] == '.'))
1604 len--;
1605 if(len < USHRT_MAX) {
1606 peer->sni = calloc(1, len + 1);
1607 if(!peer->sni) {
1608 Curl_ssl_peer_cleanup(peer);
1609 return CURLE_OUT_OF_MEMORY;
1610 }
1611 Curl_strntolower(peer->sni, peer->hostname, len);
1612 peer->sni[len] = 0;
1613 }
1614 }
1615
1616 }
1617 connssl->port = eport;
1618 return CURLE_OK;
1619}
1620
1621static void ssl_cf_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
1622{
1623 struct cf_call_data save;
1624
1625 CF_DATA_SAVE(save, cf, data);
1626 cf_close(cf, data);
1627 CF_DATA_RESTORE(cf, save);
1628 cf_ctx_free(cf->ctx);
1629 cf->ctx = NULL;
1630}
1631
1632static void ssl_cf_close(struct Curl_cfilter *cf,
1633 struct Curl_easy *data)
1634{
1635 struct cf_call_data save;
1636
1637 CF_DATA_SAVE(save, cf, data);
1638 cf_close(cf, data);
1639 if(cf->next)
1640 cf->next->cft->do_close(cf->next, data);
1641 CF_DATA_RESTORE(cf, save);
1642}
1643
1644static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
1645 struct Curl_easy *data,
1646 bool blocking, bool *done)
1647{
1648 struct ssl_connect_data *connssl = cf->ctx;
1649 struct cf_call_data save;
1650 CURLcode result;
1651
1652 if(cf->connected) {
1653 *done = TRUE;
1654 return CURLE_OK;
1655 }
1656
1657 CF_DATA_SAVE(save, cf, data);
1658 CURL_TRC_CF(data, cf, "cf_connect()");
1659 (void)connssl;
1660 DEBUGASSERT(data->conn);
1661 DEBUGASSERT(data->conn == cf->conn);
1662 DEBUGASSERT(connssl);
1663 DEBUGASSERT(cf->conn->host.name);
1664
1665 result = cf->next->cft->do_connect(cf->next, data, blocking, done);
1666 if(result || !*done)
1667 goto out;
1668
1669 *done = FALSE;
1670 result = Curl_ssl_peer_init(&connssl->peer, cf);
1671 if(result)
1672 goto out;
1673
1674 if(blocking) {
1675 result = ssl_connect(cf, data);
1676 *done = (result == CURLE_OK);
1677 }
1678 else {
1679 result = ssl_connect_nonblocking(cf, data, done);
1680 }
1681
1682 if(!result && *done) {
1683 cf->connected = TRUE;
1684 connssl->handshake_done = Curl_now();
1685 DEBUGASSERT(connssl->state == ssl_connection_complete);
1686 }
1687out:
1688 CURL_TRC_CF(data, cf, "cf_connect() -> %d, done=%d", result, *done);
1689 CF_DATA_RESTORE(cf, save);
1690 return result;
1691}
1692
1693static bool ssl_cf_data_pending(struct Curl_cfilter *cf,
1694 const struct Curl_easy *data)
1695{
1696 struct cf_call_data save;
1697 bool result;
1698
1699 CF_DATA_SAVE(save, cf, data);
1700 if(Curl_ssl->data_pending(cf, data))
1701 result = TRUE;
1702 else
1703 result = cf->next->cft->has_data_pending(cf->next, data);
1704 CF_DATA_RESTORE(cf, save);
1705 return result;
1706}
1707
1708static ssize_t ssl_cf_send(struct Curl_cfilter *cf,
1709 struct Curl_easy *data, const void *buf, size_t len,
1710 CURLcode *err)
1711{
1712 struct cf_call_data save;
1713 ssize_t nwritten;
1714
1715 CF_DATA_SAVE(save, cf, data);
1716 *err = CURLE_OK;
1717 nwritten = Curl_ssl->send_plain(cf, data, buf, len, err);
1718 CF_DATA_RESTORE(cf, save);
1719 return nwritten;
1720}
1721
1722static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
1723 struct Curl_easy *data, char *buf, size_t len,
1724 CURLcode *err)
1725{
1726 struct cf_call_data save;
1727 ssize_t nread;
1728
1729 CF_DATA_SAVE(save, cf, data);
1730 *err = CURLE_OK;
1731 nread = Curl_ssl->recv_plain(cf, data, buf, len, err);
1732 if(nread > 0) {
1733 DEBUGASSERT((size_t)nread <= len);
1734 }
1735 else if(nread == 0) {
1736 /* eof */
1737 *err = CURLE_OK;
1738 }
1739 CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len,
1740 nread, *err);
1741 CF_DATA_RESTORE(cf, save);
1742 return nread;
1743}
1744
1745static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf,
1746 struct Curl_easy *data,
1747 struct easy_pollset *ps)
1748{
1749 struct cf_call_data save;
1750
1751 if(!cf->connected) {
1752 CF_DATA_SAVE(save, cf, data);
1753 Curl_ssl->adjust_pollset(cf, data, ps);
1754 CF_DATA_RESTORE(cf, save);
1755 }
1756}
1757
1758static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
1759 struct Curl_easy *data,
1760 int event, int arg1, void *arg2)
1761{
1762 struct cf_call_data save;
1763
1764 (void)arg1;
1765 (void)arg2;
1766 switch(event) {
1767 case CF_CTRL_DATA_ATTACH:
1768 if(Curl_ssl->attach_data) {
1769 CF_DATA_SAVE(save, cf, data);
1770 Curl_ssl->attach_data(cf, data);
1771 CF_DATA_RESTORE(cf, save);
1772 }
1773 break;
1774 case CF_CTRL_DATA_DETACH:
1775 if(Curl_ssl->detach_data) {
1776 CF_DATA_SAVE(save, cf, data);
1777 Curl_ssl->detach_data(cf, data);
1778 CF_DATA_RESTORE(cf, save);
1779 }
1780 break;
1781 default:
1782 break;
1783 }
1784 return CURLE_OK;
1785}
1786
1787static CURLcode ssl_cf_query(struct Curl_cfilter *cf,
1788 struct Curl_easy *data,
1789 int query, int *pres1, void *pres2)
1790{
1791 struct ssl_connect_data *connssl = cf->ctx;
1792
1793 switch(query) {
1794 case CF_QUERY_TIMER_APPCONNECT: {
1795 struct curltime *when = pres2;
1796 if(cf->connected && !Curl_ssl_cf_is_proxy(cf))
1797 *when = connssl->handshake_done;
1798 return CURLE_OK;
1799 }
1800 default:
1801 break;
1802 }
1803 return cf->next?
1804 cf->next->cft->query(cf->next, data, query, pres1, pres2) :
1805 CURLE_UNKNOWN_OPTION;
1806}
1807
1808static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data,
1809 bool *input_pending)
1810{
1811 struct cf_call_data save;
1812 int result;
1813 /*
1814 * This function tries to determine connection status.
1815 *
1816 * Return codes:
1817 * 1 means the connection is still in place
1818 * 0 means the connection has been closed
1819 * -1 means the connection status is unknown
1820 */
1821 CF_DATA_SAVE(save, cf, data);
1822 result = Curl_ssl->check_cxn(cf, data);
1823 CF_DATA_RESTORE(cf, save);
1824 if(result > 0) {
1825 *input_pending = TRUE;
1826 return TRUE;
1827 }
1828 if(result == 0) {
1829 *input_pending = FALSE;
1830 return FALSE;
1831 }
1832 /* ssl backend does not know */
1833 return cf->next?
1834 cf->next->cft->is_alive(cf->next, data, input_pending) :
1835 FALSE; /* pessimistic in absence of data */
1836}
1837
1838struct Curl_cftype Curl_cft_ssl = {
1839 "SSL",
1840 CF_TYPE_SSL,
1841 CURL_LOG_LVL_NONE,
1842 ssl_cf_destroy,
1843 ssl_cf_connect,
1844 ssl_cf_close,
1845 Curl_cf_def_get_host,
1846 ssl_cf_adjust_pollset,
1847 ssl_cf_data_pending,
1848 ssl_cf_send,
1849 ssl_cf_recv,
1850 ssl_cf_cntrl,
1851 cf_ssl_is_alive,
1852 Curl_cf_def_conn_keep_alive,
1853 ssl_cf_query,
1854};
1855
1856#ifndef CURL_DISABLE_PROXY
1857
1858struct Curl_cftype Curl_cft_ssl_proxy = {
1859 "SSL-PROXY",
1860 CF_TYPE_SSL,
1861 CURL_LOG_LVL_NONE,
1862 ssl_cf_destroy,
1863 ssl_cf_connect,
1864 ssl_cf_close,
1865 Curl_cf_def_get_host,
1866 ssl_cf_adjust_pollset,
1867 ssl_cf_data_pending,
1868 ssl_cf_send,
1869 ssl_cf_recv,
1870 ssl_cf_cntrl,
1871 cf_ssl_is_alive,
1872 Curl_cf_def_conn_keep_alive,
1873 Curl_cf_def_query,
1874};
1875
1876#endif /* !CURL_DISABLE_PROXY */
1877
1878static CURLcode cf_ssl_create(struct Curl_cfilter **pcf,
1879 struct Curl_easy *data,
1880 struct connectdata *conn)
1881{
1882 struct Curl_cfilter *cf = NULL;
1883 struct ssl_connect_data *ctx;
1884 CURLcode result;
1885
1886 DEBUGASSERT(data->conn);
1887
1888 ctx = cf_ctx_new(data, alpn_get_spec(data->state.httpwant,
1889 conn->bits.tls_enable_alpn));
1890 if(!ctx) {
1891 result = CURLE_OUT_OF_MEMORY;
1892 goto out;
1893 }
1894
1895 result = Curl_cf_create(&cf, &Curl_cft_ssl, ctx);
1896
1897out:
1898 if(result)
1899 cf_ctx_free(ctx);
1900 *pcf = result? NULL : cf;
1901 return result;
1902}
1903
1904CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data,
1905 struct connectdata *conn,
1906 int sockindex)
1907{
1908 struct Curl_cfilter *cf;
1909 CURLcode result;
1910
1911 result = cf_ssl_create(&cf, data, conn);
1912 if(!result)
1913 Curl_conn_cf_add(data, conn, sockindex, cf);
1914 return result;
1915}
1916
1917CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at,
1918 struct Curl_easy *data)
1919{
1920 struct Curl_cfilter *cf;
1921 CURLcode result;
1922
1923 result = cf_ssl_create(&cf, data, cf_at->conn);
1924 if(!result)
1925 Curl_conn_cf_insert_after(cf_at, cf);
1926 return result;
1927}
1928
1929#ifndef CURL_DISABLE_PROXY
1930
1931static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf,
1932 struct Curl_easy *data,
1933 struct connectdata *conn)
1934{
1935 struct Curl_cfilter *cf = NULL;
1936 struct ssl_connect_data *ctx;
1937 CURLcode result;
1938 bool use_alpn = conn->bits.tls_enable_alpn;
1939 int httpwant = CURL_HTTP_VERSION_1_1;
1940
1941#ifdef USE_HTTP2
1942 if(conn->http_proxy.proxytype == CURLPROXY_HTTPS2) {
1943 use_alpn = TRUE;
1944 httpwant = CURL_HTTP_VERSION_2;
1945 }
1946#endif
1947
1948 ctx = cf_ctx_new(data, alpn_get_spec(httpwant, use_alpn));
1949 if(!ctx) {
1950 result = CURLE_OUT_OF_MEMORY;
1951 goto out;
1952 }
1953 result = Curl_cf_create(&cf, &Curl_cft_ssl_proxy, ctx);
1954
1955out:
1956 if(result)
1957 cf_ctx_free(ctx);
1958 *pcf = result? NULL : cf;
1959 return result;
1960}
1961
1962CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
1963 struct Curl_easy *data)
1964{
1965 struct Curl_cfilter *cf;
1966 CURLcode result;
1967
1968 result = cf_ssl_proxy_create(&cf, data, cf_at->conn);
1969 if(!result)
1970 Curl_conn_cf_insert_after(cf_at, cf);
1971 return result;
1972}
1973
1974#endif /* !CURL_DISABLE_PROXY */
1975
1976bool Curl_ssl_supports(struct Curl_easy *data, int option)
1977{
1978 (void)data;
1979 return (Curl_ssl->supports & option)? TRUE : FALSE;
1980}
1981
1982static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf)
1983{
1984 for(; cf; cf = cf->next) {
1985 if(cf->cft == &Curl_cft_ssl)
1986 return cf;
1987#ifndef CURL_DISABLE_PROXY
1988 if(cf->cft == &Curl_cft_ssl_proxy)
1989 return cf;
1990#endif
1991 }
1992 return NULL;
1993}
1994
1995
1996void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
1997 CURLINFO info, int n)
1998{
1999 void *result = NULL;
2000 (void)n;
2001 if(data->conn) {
2002 struct Curl_cfilter *cf;
2003 /* get first SSL filter in chain, if any is present */
2004 cf = get_ssl_filter(data->conn->cfilter[sockindex]);
2005 if(cf) {
2006 struct cf_call_data save;
2007 CF_DATA_SAVE(save, cf, data);
2008 result = Curl_ssl->get_internals(cf->ctx, info);
2009 CF_DATA_RESTORE(cf, save);
2010 }
2011 }
2012 return result;
2013}
2014
2015CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
2016 int sockindex)
2017{
2018 struct Curl_cfilter *cf, *head;
2019 CURLcode result = CURLE_OK;
2020
2021 (void)data;
2022 head = data->conn? data->conn->cfilter[sockindex] : NULL;
2023 for(cf = head; cf; cf = cf->next) {
2024 if(cf->cft == &Curl_cft_ssl) {
2025 if(Curl_ssl->shut_down(cf, data))
2026 result = CURLE_SSL_SHUTDOWN_FAILED;
2027 Curl_conn_cf_discard_sub(head, cf, data, FALSE);
2028 break;
2029 }
2030 }
2031 return result;
2032}
2033
2034bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf)
2035{
2036#ifndef CURL_DISABLE_PROXY
2037 return (cf->cft == &Curl_cft_ssl_proxy);
2038#else
2039 (void)cf;
2040 return FALSE;
2041#endif
2042}
2043
2044struct ssl_config_data *
2045Curl_ssl_cf_get_config(struct Curl_cfilter *cf, struct Curl_easy *data)
2046{
2047#ifdef CURL_DISABLE_PROXY
2048 (void)cf;
2049 return &data->set.ssl;
2050#else
2051 return Curl_ssl_cf_is_proxy(cf)? &data->set.proxy_ssl : &data->set.ssl;
2052#endif
2053}
2054
2055struct ssl_primary_config *
2056Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf)
2057{
2058#ifdef CURL_DISABLE_PROXY
2059 return &cf->conn->ssl_config;
2060#else
2061 return Curl_ssl_cf_is_proxy(cf)?
2062 &cf->conn->proxy_ssl_config : &cf->conn->ssl_config;
2063#endif
2064}
2065
2066CURLcode Curl_alpn_to_proto_buf(struct alpn_proto_buf *buf,
2067 const struct alpn_spec *spec)
2068{
2069 size_t i, len;
2070 int off = 0;
2071 unsigned char blen;
2072
2073 memset(buf, 0, sizeof(*buf));
2074 for(i = 0; spec && i < spec->count; ++i) {
2075 len = strlen(spec->entries[i]);
2076 if(len >= ALPN_NAME_MAX)
2077 return CURLE_FAILED_INIT;
2078 blen = (unsigned char)len;
2079 if(off + blen + 1 >= (int)sizeof(buf->data))
2080 return CURLE_FAILED_INIT;
2081 buf->data[off++] = blen;
2082 memcpy(buf->data + off, spec->entries[i], blen);
2083 off += blen;
2084 }
2085 buf->len = off;
2086 return CURLE_OK;
2087}
2088
2089CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf,
2090 const struct alpn_spec *spec)
2091{
2092 size_t i, len;
2093 size_t off = 0;
2094
2095 memset(buf, 0, sizeof(*buf));
2096 for(i = 0; spec && i < spec->count; ++i) {
2097 len = strlen(spec->entries[i]);
2098 if(len >= ALPN_NAME_MAX)
2099 return CURLE_FAILED_INIT;
2100 if(off + len + 2 >= sizeof(buf->data))
2101 return CURLE_FAILED_INIT;
2102 if(off)
2103 buf->data[off++] = ',';
2104 memcpy(buf->data + off, spec->entries[i], len);
2105 off += len;
2106 }
2107 buf->data[off] = '\0';
2108 buf->len = (int)off;
2109 return CURLE_OK;
2110}
2111
2112CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
2113 struct Curl_easy *data,
2114 const unsigned char *proto,
2115 size_t proto_len)
2116{
2117 int can_multi = 0;
2118 unsigned char *palpn =
2119#ifndef CURL_DISABLE_PROXY
2120 (cf->conn->bits.tunnel_proxy && Curl_ssl_cf_is_proxy(cf))?
2121 &cf->conn->proxy_alpn : &cf->conn->alpn
2122#else
2123 &cf->conn->alpn
2124#endif
2125 ;
2126
2127 if(proto && proto_len) {
2128 if(proto_len == ALPN_HTTP_1_1_LENGTH &&
2129 !memcmp(ALPN_HTTP_1_1, proto, ALPN_HTTP_1_1_LENGTH)) {
2130 *palpn = CURL_HTTP_VERSION_1_1;
2131 }
2132#ifdef USE_HTTP2
2133 else if(proto_len == ALPN_H2_LENGTH &&
2134 !memcmp(ALPN_H2, proto, ALPN_H2_LENGTH)) {
2135 *palpn = CURL_HTTP_VERSION_2;
2136 can_multi = 1;
2137 }
2138#endif
2139#ifdef USE_HTTP3
2140 else if(proto_len == ALPN_H3_LENGTH &&
2141 !memcmp(ALPN_H3, proto, ALPN_H3_LENGTH)) {
2142 *palpn = CURL_HTTP_VERSION_3;
2143 can_multi = 1;
2144 }
2145#endif
2146 else {
2147 *palpn = CURL_HTTP_VERSION_NONE;
2148 failf(data, "unsupported ALPN protocol: '%.*s'", (int)proto_len, proto);
2149 /* TODO: do we want to fail this? Previous code just ignored it and
2150 * some vtls backends even ignore the return code of this function. */
2151 /* return CURLE_NOT_BUILT_IN; */
2152 goto out;
2153 }
2154 infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, (int)proto_len, proto);
2155 }
2156 else {
2157 *palpn = CURL_HTTP_VERSION_NONE;
2158 infof(data, VTLS_INFOF_NO_ALPN);
2159 }
2160
2161out:
2162 if(!Curl_ssl_cf_is_proxy(cf))
2163 Curl_multiuse_state(data, can_multi?
2164 BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
2165 return CURLE_OK;
2166}
2167
2168#endif /* USE_SSL */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette