1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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 } 778 else { 779 Curl_pollset_set_in_only(data, ps, sock); 780 } 781 } 782 } 783} 784 785/* Selects an SSL crypto engine 786 */ 787CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine) 788{ 789 return Curl_ssl->set_engine(data, engine); 790} 791 792/* Selects the default SSL crypto engine 793 */ 794CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data) 795{ 796 return Curl_ssl->set_engine_default(data); 797} 798 799/* Return list of OpenSSL crypto engine names. */ 800struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data) 801{ 802 return Curl_ssl->engines_list(data); 803} 804 805/* 806 * This sets up a session ID cache to the specified size. Make sure this code 807 * is agnostic to what underlying SSL technology we use. 808 */ 809CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount) 810{ 811 struct Curl_ssl_session *session; 812 813 if(data->state.session) 814 /* this is just a precaution to prevent multiple inits */ 815 return CURLE_OK; 816 817 session = calloc(amount, sizeof(struct Curl_ssl_session)); 818 if(!session) 819 return CURLE_OUT_OF_MEMORY; 820 821 /* store the info in the SSL section */ 822 data->set.general_ssl.max_ssl_sessions = amount; 823 data->state.session = session; 824 data->state.sessionage = 1; /* this is brand new */ 825 return CURLE_OK; 826} 827 828static size_t multissl_version(char *buffer, size_t size); 829 830void Curl_ssl_version(char *buffer, size_t size) 831{ 832#ifdef CURL_WITH_MULTI_SSL 833 (void)multissl_version(buffer, size); 834#else 835 (void)Curl_ssl->version(buffer, size); 836#endif 837} 838 839void Curl_ssl_free_certinfo(struct Curl_easy *data) 840{ 841 struct curl_certinfo *ci = &data->info.certs; 842 843 if(ci->num_of_certs) { 844 /* free all individual lists used */ 845 int i; 846 for(i = 0; i<ci->num_of_certs; i++) { 847 curl_slist_free_all(ci->certinfo[i]); 848 ci->certinfo[i] = NULL; 849 } 850 851 free(ci->certinfo); /* free the actual array too */ 852 ci->certinfo = NULL; 853 ci->num_of_certs = 0; 854 } 855} 856 857CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num) 858{ 859 struct curl_certinfo *ci = &data->info.certs; 860 struct curl_slist **table; 861 862 /* Free any previous certificate information structures */ 863 Curl_ssl_free_certinfo(data); 864 865 /* Allocate the required certificate information structures */ 866 table = calloc((size_t) num, sizeof(struct curl_slist *)); 867 if(!table) 868 return CURLE_OUT_OF_MEMORY; 869 870 ci->num_of_certs = num; 871 ci->certinfo = table; 872 873 return CURLE_OK; 874} 875 876/* 877 * 'value' is NOT a null-terminated string 878 */ 879CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, 880 int certnum, 881 const char *label, 882 const char *value, 883 size_t valuelen) 884{ 885 struct curl_certinfo *ci = &data->info.certs; 886 struct curl_slist *nl; 887 CURLcode result = CURLE_OK; 888 struct dynbuf build; 889 890 Curl_dyn_init(&build, 10000); 891 892 if(Curl_dyn_add(&build, label) || 893 Curl_dyn_addn(&build, ":", 1) || 894 Curl_dyn_addn(&build, value, valuelen)) 895 return CURLE_OUT_OF_MEMORY; 896 897 nl = Curl_slist_append_nodup(ci->certinfo[certnum], 898 Curl_dyn_ptr(&build)); 899 if(!nl) { 900 Curl_dyn_free(&build); 901 curl_slist_free_all(ci->certinfo[certnum]); 902 result = CURLE_OUT_OF_MEMORY; 903 } 904 905 ci->certinfo[certnum] = nl; 906 return result; 907} 908 909CURLcode Curl_ssl_random(struct Curl_easy *data, 910 unsigned char *entropy, 911 size_t length) 912{ 913 return Curl_ssl->random(data, entropy, length); 914} 915 916/* 917 * Public key pem to der conversion 918 */ 919 920static CURLcode pubkey_pem_to_der(const char *pem, 921 unsigned char **der, size_t *der_len) 922{ 923 char *stripped_pem, *begin_pos, *end_pos; 924 size_t pem_count, stripped_pem_count = 0, pem_len; 925 CURLcode result; 926 927 /* if no pem, exit. */ 928 if(!pem) 929 return CURLE_BAD_CONTENT_ENCODING; 930 931 begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----"); 932 if(!begin_pos) 933 return CURLE_BAD_CONTENT_ENCODING; 934 935 pem_count = begin_pos - pem; 936 /* Invalid if not at beginning AND not directly following \n */ 937 if(0 != pem_count && '\n' != pem[pem_count - 1]) 938 return CURLE_BAD_CONTENT_ENCODING; 939 940 /* 26 is length of "-----BEGIN PUBLIC KEY-----" */ 941 pem_count += 26; 942 943 /* Invalid if not directly following \n */ 944 end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----"); 945 if(!end_pos) 946 return CURLE_BAD_CONTENT_ENCODING; 947 948 pem_len = end_pos - pem; 949 950 stripped_pem = malloc(pem_len - pem_count + 1); 951 if(!stripped_pem) 952 return CURLE_OUT_OF_MEMORY; 953 954 /* 955 * Here we loop through the pem array one character at a time between the 956 * correct indices, and place each character that is not '\n' or '\r' 957 * into the stripped_pem array, which should represent the raw base64 string 958 */ 959 while(pem_count < pem_len) { 960 if('\n' != pem[pem_count] && '\r' != pem[pem_count]) 961 stripped_pem[stripped_pem_count++] = pem[pem_count]; 962 ++pem_count; 963 } 964 /* Place the null terminator in the correct place */ 965 stripped_pem[stripped_pem_count] = '\0'; 966 967 result = Curl_base64_decode(stripped_pem, der, der_len); 968 969 Curl_safefree(stripped_pem); 970 971 return result; 972} 973 974/* 975 * Generic pinned public key check. 976 */ 977 978CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, 979 const char *pinnedpubkey, 980 const unsigned char *pubkey, size_t pubkeylen) 981{ 982 FILE *fp; 983 unsigned char *buf = NULL, *pem_ptr = NULL; 984 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; 985#ifdef CURL_DISABLE_VERBOSE_STRINGS 986 (void)data; 987#endif 988 989 /* if a path wasn't specified, don't pin */ 990 if(!pinnedpubkey) 991 return CURLE_OK; 992 if(!pubkey || !pubkeylen) 993 return result; 994 995 /* only do this if pinnedpubkey starts with "sha256//", length 8 */ 996 if(strncmp(pinnedpubkey, "sha256//", 8) == 0) { 997 CURLcode encode; 998 size_t encodedlen = 0; 999 char *encoded = NULL, *pinkeycopy, *begin_pos, *end_pos; 1000 unsigned char *sha256sumdigest; 1001 1002 if(!Curl_ssl->sha256sum) { 1003 /* without sha256 support, this cannot match */ 1004 return result; 1005 } 1006 1007 /* compute sha256sum of public key */ 1008 sha256sumdigest = malloc(CURL_SHA256_DIGEST_LENGTH); 1009 if(!sha256sumdigest) 1010 return CURLE_OUT_OF_MEMORY; 1011 encode = Curl_ssl->sha256sum(pubkey, pubkeylen, 1012 sha256sumdigest, CURL_SHA256_DIGEST_LENGTH); 1013 1014 if(!encode) 1015 encode = Curl_base64_encode((char *)sha256sumdigest, 1016 CURL_SHA256_DIGEST_LENGTH, &encoded, 1017 &encodedlen); 1018 Curl_safefree(sha256sumdigest); 1019 1020 if(encode) 1021 return encode; 1022 1023 infof(data, " public key hash: sha256//%s", encoded); 1024 1025 /* it starts with sha256//, copy so we can modify it */ 1026 pinkeycopy = strdup(pinnedpubkey); 1027 if(!pinkeycopy) { 1028 Curl_safefree(encoded); 1029 return CURLE_OUT_OF_MEMORY; 1030 } 1031 /* point begin_pos to the copy, and start extracting keys */ 1032 begin_pos = pinkeycopy; 1033 do { 1034 end_pos = strstr(begin_pos, ";sha256//"); 1035 /* 1036 * if there is an end_pos, null terminate, 1037 * otherwise it'll go to the end of the original string 1038 */ 1039 if(end_pos) 1040 end_pos[0] = '\0'; 1041 1042 /* compare base64 sha256 digests, 8 is the length of "sha256//" */ 1043 if(encodedlen == strlen(begin_pos + 8) && 1044 !memcmp(encoded, begin_pos + 8, encodedlen)) { 1045 result = CURLE_OK; 1046 break; 1047 } 1048 1049 /* 1050 * change back the null-terminator we changed earlier, 1051 * and look for next begin 1052 */ 1053 if(end_pos) { 1054 end_pos[0] = ';'; 1055 begin_pos = strstr(end_pos, "sha256//"); 1056 } 1057 } while(end_pos && begin_pos); 1058 Curl_safefree(encoded); 1059 Curl_safefree(pinkeycopy); 1060 return result; 1061 } 1062 1063 fp = fopen(pinnedpubkey, "rb"); 1064 if(!fp) 1065 return result; 1066 1067 do { 1068 long filesize; 1069 size_t size, pem_len; 1070 CURLcode pem_read; 1071 1072 /* Determine the file's size */ 1073 if(fseek(fp, 0, SEEK_END)) 1074 break; 1075 filesize = ftell(fp); 1076 if(fseek(fp, 0, SEEK_SET)) 1077 break; 1078 if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE) 1079 break; 1080 1081 /* 1082 * if the size of our certificate is bigger than the file 1083 * size then it can't match 1084 */ 1085 size = curlx_sotouz((curl_off_t) filesize); 1086 if(pubkeylen > size) 1087 break; 1088 1089 /* 1090 * Allocate buffer for the pinned key 1091 * With 1 additional byte for null terminator in case of PEM key 1092 */ 1093 buf = malloc(size + 1); 1094 if(!buf) 1095 break; 1096 1097 /* Returns number of elements read, which should be 1 */ 1098 if((int) fread(buf, size, 1, fp) != 1) 1099 break; 1100 1101 /* If the sizes are the same, it can't be base64 encoded, must be der */ 1102 if(pubkeylen == size) { 1103 if(!memcmp(pubkey, buf, pubkeylen)) 1104 result = CURLE_OK; 1105 break; 1106 } 1107 1108 /* 1109 * Otherwise we will assume it's PEM and try to decode it 1110 * after placing null terminator 1111 */ 1112 buf[size] = '\0'; 1113 pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len); 1114 /* if it wasn't read successfully, exit */ 1115 if(pem_read) 1116 break; 1117 1118 /* 1119 * if the size of our certificate doesn't match the size of 1120 * the decoded file, they can't be the same, otherwise compare 1121 */ 1122 if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen)) 1123 result = CURLE_OK; 1124 } while(0); 1125 1126 Curl_safefree(buf); 1127 Curl_safefree(pem_ptr); 1128 fclose(fp); 1129 1130 return result; 1131} 1132 1133/* 1134 * Check whether the SSL backend supports the status_request extension. 1135 */ 1136bool Curl_ssl_cert_status_request(void) 1137{ 1138 return Curl_ssl->cert_status_request(); 1139} 1140 1141/* 1142 * Check whether the SSL backend supports false start. 1143 */ 1144bool Curl_ssl_false_start(struct Curl_easy *data) 1145{ 1146 (void)data; 1147 return Curl_ssl->false_start(); 1148} 1149 1150/* 1151 * Default implementations for unsupported functions. 1152 */ 1153 1154int Curl_none_init(void) 1155{ 1156 return 1; 1157} 1158 1159void Curl_none_cleanup(void) 1160{ } 1161 1162int Curl_none_shutdown(struct Curl_cfilter *cf UNUSED_PARAM, 1163 struct Curl_easy *data UNUSED_PARAM) 1164{ 1165 (void)data; 1166 (void)cf; 1167 return 0; 1168} 1169 1170int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data) 1171{ 1172 (void)cf; 1173 (void)data; 1174 return -1; 1175} 1176 1177CURLcode Curl_none_random(struct Curl_easy *data UNUSED_PARAM, 1178 unsigned char *entropy UNUSED_PARAM, 1179 size_t length UNUSED_PARAM) 1180{ 1181 (void)data; 1182 (void)entropy; 1183 (void)length; 1184 return CURLE_NOT_BUILT_IN; 1185} 1186 1187void Curl_none_close_all(struct Curl_easy *data UNUSED_PARAM) 1188{ 1189 (void)data; 1190} 1191 1192void Curl_none_session_free(void *ptr UNUSED_PARAM) 1193{ 1194 (void)ptr; 1195} 1196 1197bool Curl_none_data_pending(struct Curl_cfilter *cf UNUSED_PARAM, 1198 const struct Curl_easy *data UNUSED_PARAM) 1199{ 1200 (void)cf; 1201 (void)data; 1202 return 0; 1203} 1204 1205bool Curl_none_cert_status_request(void) 1206{ 1207 return FALSE; 1208} 1209 1210CURLcode Curl_none_set_engine(struct Curl_easy *data UNUSED_PARAM, 1211 const char *engine UNUSED_PARAM) 1212{ 1213 (void)data; 1214 (void)engine; 1215 return CURLE_NOT_BUILT_IN; 1216} 1217 1218CURLcode Curl_none_set_engine_default(struct Curl_easy *data UNUSED_PARAM) 1219{ 1220 (void)data; 1221 return CURLE_NOT_BUILT_IN; 1222} 1223 1224struct curl_slist *Curl_none_engines_list(struct Curl_easy *data UNUSED_PARAM) 1225{ 1226 (void)data; 1227 return (struct curl_slist *)NULL; 1228} 1229 1230bool Curl_none_false_start(void) 1231{ 1232 return FALSE; 1233} 1234 1235static int multissl_init(void) 1236{ 1237 if(multissl_setup(NULL)) 1238 return 1; 1239 return Curl_ssl->init(); 1240} 1241 1242static CURLcode multissl_connect(struct Curl_cfilter *cf, 1243 struct Curl_easy *data) 1244{ 1245 if(multissl_setup(NULL)) 1246 return CURLE_FAILED_INIT; 1247 return Curl_ssl->connect_blocking(cf, data); 1248} 1249 1250static CURLcode multissl_connect_nonblocking(struct Curl_cfilter *cf, 1251 struct Curl_easy *data, 1252 bool *done) 1253{ 1254 if(multissl_setup(NULL)) 1255 return CURLE_FAILED_INIT; 1256 return Curl_ssl->connect_nonblocking(cf, data, done); 1257} 1258 1259static void multissl_adjust_pollset(struct Curl_cfilter *cf, 1260 struct Curl_easy *data, 1261 struct easy_pollset *ps) 1262{ 1263 if(multissl_setup(NULL)) 1264 return; 1265 Curl_ssl->adjust_pollset(cf, data, ps); 1266} 1267 1268static void *multissl_get_internals(struct ssl_connect_data *connssl, 1269 CURLINFO info) 1270{ 1271 if(multissl_setup(NULL)) 1272 return NULL; 1273 return Curl_ssl->get_internals(connssl, info); 1274} 1275 1276static void multissl_close(struct Curl_cfilter *cf, struct Curl_easy *data) 1277{ 1278 if(multissl_setup(NULL)) 1279 return; 1280 Curl_ssl->close(cf, data); 1281} 1282 1283static ssize_t multissl_recv_plain(struct Curl_cfilter *cf, 1284 struct Curl_easy *data, 1285 char *buf, size_t len, CURLcode *code) 1286{ 1287 if(multissl_setup(NULL)) 1288 return CURLE_FAILED_INIT; 1289 return Curl_ssl->recv_plain(cf, data, buf, len, code); 1290} 1291 1292static ssize_t multissl_send_plain(struct Curl_cfilter *cf, 1293 struct Curl_easy *data, 1294 const void *mem, size_t len, 1295 CURLcode *code) 1296{ 1297 if(multissl_setup(NULL)) 1298 return CURLE_FAILED_INIT; 1299 return Curl_ssl->send_plain(cf, data, mem, len, code); 1300} 1301 1302static const struct Curl_ssl Curl_ssl_multi = { 1303 { CURLSSLBACKEND_NONE, "multi" }, /* info */ 1304 0, /* supports nothing */ 1305 (size_t)-1, /* something insanely large to be on the safe side */ 1306 1307 multissl_init, /* init */ 1308 Curl_none_cleanup, /* cleanup */ 1309 multissl_version, /* version */ 1310 Curl_none_check_cxn, /* check_cxn */ 1311 Curl_none_shutdown, /* shutdown */ 1312 Curl_none_data_pending, /* data_pending */ 1313 Curl_none_random, /* random */ 1314 Curl_none_cert_status_request, /* cert_status_request */ 1315 multissl_connect, /* connect */ 1316 multissl_connect_nonblocking, /* connect_nonblocking */ 1317 multissl_adjust_pollset, /* adjust_pollset */ 1318 multissl_get_internals, /* get_internals */ 1319 multissl_close, /* close_one */ 1320 Curl_none_close_all, /* close_all */ 1321 Curl_none_session_free, /* session_free */ 1322 Curl_none_set_engine, /* set_engine */ 1323 Curl_none_set_engine_default, /* set_engine_default */ 1324 Curl_none_engines_list, /* engines_list */ 1325 Curl_none_false_start, /* false_start */ 1326 NULL, /* sha256sum */ 1327 NULL, /* associate_connection */ 1328 NULL, /* disassociate_connection */ 1329 NULL, /* free_multi_ssl_backend_data */ 1330 multissl_recv_plain, /* recv decrypted data */ 1331 multissl_send_plain, /* send data to encrypt */ 1332}; 1333 1334const struct Curl_ssl *Curl_ssl = 1335#if defined(CURL_WITH_MULTI_SSL) 1336 &Curl_ssl_multi; 1337#elif defined(USE_WOLFSSL) 1338 &Curl_ssl_wolfssl; 1339#elif defined(USE_SECTRANSP) 1340 &Curl_ssl_sectransp; 1341#elif defined(USE_GNUTLS) 1342 &Curl_ssl_gnutls; 1343#elif defined(USE_MBEDTLS) 1344 &Curl_ssl_mbedtls; 1345#elif defined(USE_RUSTLS) 1346 &Curl_ssl_rustls; 1347#elif defined(USE_OPENSSL) 1348 &Curl_ssl_openssl; 1349#elif defined(USE_SCHANNEL) 1350 &Curl_ssl_schannel; 1351#elif defined(USE_BEARSSL) 1352 &Curl_ssl_bearssl; 1353#else 1354#error "Missing struct Curl_ssl for selected SSL backend" 1355#endif 1356 1357static const struct Curl_ssl *available_backends[] = { 1358#if defined(USE_WOLFSSL) 1359 &Curl_ssl_wolfssl, 1360#endif 1361#if defined(USE_SECTRANSP) 1362 &Curl_ssl_sectransp, 1363#endif 1364#if defined(USE_GNUTLS) 1365 &Curl_ssl_gnutls, 1366#endif 1367#if defined(USE_MBEDTLS) 1368 &Curl_ssl_mbedtls, 1369#endif 1370#if defined(USE_OPENSSL) 1371 &Curl_ssl_openssl, 1372#endif 1373#if defined(USE_SCHANNEL) 1374 &Curl_ssl_schannel, 1375#endif 1376#if defined(USE_BEARSSL) 1377 &Curl_ssl_bearssl, 1378#endif 1379#if defined(USE_RUSTLS) 1380 &Curl_ssl_rustls, 1381#endif 1382 NULL 1383}; 1384 1385static size_t multissl_version(char *buffer, size_t size) 1386{ 1387 static const struct Curl_ssl *selected; 1388 static char backends[200]; 1389 static size_t backends_len; 1390 const struct Curl_ssl *current; 1391 1392 current = Curl_ssl == &Curl_ssl_multi ? available_backends[0] : Curl_ssl; 1393 1394 if(current != selected) { 1395 char *p = backends; 1396 char *end = backends + sizeof(backends); 1397 int i; 1398 1399 selected = current; 1400 1401 backends[0] = '\0'; 1402 1403 for(i = 0; available_backends[i]; ++i) { 1404 char vb[200]; 1405 bool paren = (selected != available_backends[i]); 1406 1407 if(available_backends[i]->version(vb, sizeof(vb))) { 1408 p += msnprintf(p, end - p, "%s%s%s%s", (p != backends ? " " : ""), 1409 (paren ? "(" : ""), vb, (paren ? ")" : "")); 1410 } 1411 } 1412 1413 backends_len = p - backends; 1414 } 1415 1416 if(size) { 1417 if(backends_len < size) 1418 strcpy(buffer, backends); 1419 else 1420 *buffer = 0; /* did not fit */ 1421 } 1422 return 0; 1423} 1424 1425static int multissl_setup(const struct Curl_ssl *backend) 1426{ 1427 const char *env; 1428 char *env_tmp; 1429 1430 if(Curl_ssl != &Curl_ssl_multi) 1431 return 1; 1432 1433 if(backend) { 1434 Curl_ssl = backend; 1435 return 0; 1436 } 1437 1438 if(!available_backends[0]) 1439 return 1; 1440 1441 env = env_tmp = curl_getenv("CURL_SSL_BACKEND"); 1442#ifdef CURL_DEFAULT_SSL_BACKEND 1443 if(!env) 1444 env = CURL_DEFAULT_SSL_BACKEND; 1445#endif 1446 if(env) { 1447 int i; 1448 for(i = 0; available_backends[i]; i++) { 1449 if(strcasecompare(env, available_backends[i]->info.name)) { 1450 Curl_ssl = available_backends[i]; 1451 free(env_tmp); 1452 return 0; 1453 } 1454 } 1455 } 1456 1457 /* Fall back to first available backend */ 1458 Curl_ssl = available_backends[0]; 1459 free(env_tmp); 1460 return 0; 1461} 1462 1463/* This function is used to select the SSL backend to use. It is called by 1464 curl_global_sslset (easy.c) which uses the global init lock. */ 1465CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, 1466 const curl_ssl_backend ***avail) 1467{ 1468 int i; 1469 1470 if(avail) 1471 *avail = (const curl_ssl_backend **)&available_backends; 1472 1473 if(Curl_ssl != &Curl_ssl_multi) 1474 return id == Curl_ssl->info.id || 1475 (name && strcasecompare(name, Curl_ssl->info.name)) ? 1476 CURLSSLSET_OK : 1477#if defined(CURL_WITH_MULTI_SSL) 1478 CURLSSLSET_TOO_LATE; 1479#else 1480 CURLSSLSET_UNKNOWN_BACKEND; 1481#endif 1482 1483 for(i = 0; available_backends[i]; i++) { 1484 if(available_backends[i]->info.id == id || 1485 (name && strcasecompare(available_backends[i]->info.name, name))) { 1486 multissl_setup(available_backends[i]); 1487 return CURLSSLSET_OK; 1488 } 1489 } 1490 1491 return CURLSSLSET_UNKNOWN_BACKEND; 1492} 1493 1494#else /* USE_SSL */ 1495CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, 1496 const curl_ssl_backend ***avail) 1497{ 1498 (void)id; 1499 (void)name; 1500 (void)avail; 1501 return CURLSSLSET_NO_BACKENDS; 1502} 1503 1504#endif /* !USE_SSL */ 1505 1506#ifdef USE_SSL 1507 1508void Curl_ssl_peer_cleanup(struct ssl_peer *peer) 1509{ 1510 if(peer->dispname != peer->hostname) 1511 free(peer->dispname); 1512 free(peer->sni); 1513 free(peer->hostname); 1514 peer->hostname = peer->sni = peer->dispname = NULL; 1515 peer->is_ip_address = FALSE; 1516} 1517 1518static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data) 1519{ 1520 struct ssl_connect_data *connssl = cf->ctx; 1521 if(connssl) { 1522 Curl_ssl->close(cf, data); 1523 connssl->state = ssl_connection_none; 1524 Curl_ssl_peer_cleanup(&connssl->peer); 1525 } 1526 cf->connected = FALSE; 1527} 1528 1529static int is_ip_address(const char *hostname) 1530{ 1531#ifdef ENABLE_IPV6 1532 struct in6_addr addr; 1533#else 1534 struct in_addr addr; 1535#endif 1536 return (hostname && hostname[0] && (Curl_inet_pton(AF_INET, hostname, &addr) 1537#ifdef ENABLE_IPV6 1538 || Curl_inet_pton(AF_INET6, hostname, &addr) 1539#endif 1540 )); 1541} 1542 1543CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf) 1544{ 1545 struct ssl_connect_data *connssl = cf->ctx; 1546 const char *ehostname, *edispname; 1547 int eport; 1548 1549 /* We need the hostname for SNI negotiation. Once handshaked, this 1550 * remains the SNI hostname for the TLS connection. But when the 1551 * connection is reused, the settings in cf->conn might change. 1552 * So we keep a copy of the hostname we use for SNI. 1553 */ 1554#ifndef CURL_DISABLE_PROXY 1555 if(Curl_ssl_cf_is_proxy(cf)) { 1556 ehostname = cf->conn->http_proxy.host.name; 1557 edispname = cf->conn->http_proxy.host.dispname; 1558 eport = cf->conn->http_proxy.port; 1559 } 1560 else 1561#endif 1562 { 1563 ehostname = cf->conn->host.name; 1564 edispname = cf->conn->host.dispname; 1565 eport = cf->conn->remote_port; 1566 } 1567 1568 /* change if ehostname changed */ 1569 if(ehostname && (!peer->hostname 1570 || strcmp(ehostname, peer->hostname))) { 1571 Curl_ssl_peer_cleanup(peer); 1572 peer->hostname = strdup(ehostname); 1573 if(!peer->hostname) { 1574 Curl_ssl_peer_cleanup(peer); 1575 return CURLE_OUT_OF_MEMORY; 1576 } 1577 if(!edispname || !strcmp(ehostname, edispname)) 1578 peer->dispname = peer->hostname; 1579 else { 1580 peer->dispname = strdup(edispname); 1581 if(!peer->dispname) { 1582 Curl_ssl_peer_cleanup(peer); 1583 return CURLE_OUT_OF_MEMORY; 1584 } 1585 } 1586 1587 peer->sni = NULL; 1588 peer->is_ip_address = is_ip_address(peer->hostname)? TRUE : FALSE; 1589 if(peer->hostname[0] && !peer->is_ip_address) { 1590 /* not an IP address, normalize according to RCC 6066 ch. 3, 1591 * max len of SNI is 2^16-1, no trailing dot */ 1592 size_t len = strlen(peer->hostname); 1593 if(len && (peer->hostname[len-1] == '.')) 1594 len--; 1595 if(len < USHRT_MAX) { 1596 peer->sni = calloc(1, len + 1); 1597 if(!peer->sni) { 1598 Curl_ssl_peer_cleanup(peer); 1599 return CURLE_OUT_OF_MEMORY; 1600 } 1601 Curl_strntolower(peer->sni, peer->hostname, len); 1602 peer->sni[len] = 0; 1603 } 1604 } 1605 1606 } 1607 connssl->port = eport; 1608 return CURLE_OK; 1609} 1610 1611static void ssl_cf_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) 1612{ 1613 struct cf_call_data save; 1614 1615 CF_DATA_SAVE(save, cf, data); 1616 cf_close(cf, data); 1617 CF_DATA_RESTORE(cf, save); 1618 cf_ctx_free(cf->ctx); 1619 cf->ctx = NULL; 1620} 1621 1622static void ssl_cf_close(struct Curl_cfilter *cf, 1623 struct Curl_easy *data) 1624{ 1625 struct cf_call_data save; 1626 1627 CF_DATA_SAVE(save, cf, data); 1628 cf_close(cf, data); 1629 if(cf->next) 1630 cf->next->cft->do_close(cf->next, data); 1631 CF_DATA_RESTORE(cf, save); 1632} 1633 1634static CURLcode ssl_cf_connect(struct Curl_cfilter *cf, 1635 struct Curl_easy *data, 1636 bool blocking, bool *done) 1637{ 1638 struct ssl_connect_data *connssl = cf->ctx; 1639 struct cf_call_data save; 1640 CURLcode result; 1641 1642 if(cf->connected) { 1643 *done = TRUE; 1644 return CURLE_OK; 1645 } 1646 1647 CF_DATA_SAVE(save, cf, data); 1648 CURL_TRC_CF(data, cf, "cf_connect()"); 1649 (void)connssl; 1650 DEBUGASSERT(data->conn); 1651 DEBUGASSERT(data->conn == cf->conn); 1652 DEBUGASSERT(connssl); 1653 DEBUGASSERT(cf->conn->host.name); 1654 1655 result = cf->next->cft->do_connect(cf->next, data, blocking, done); 1656 if(result || !*done) 1657 goto out; 1658 1659 *done = FALSE; 1660 result = Curl_ssl_peer_init(&connssl->peer, cf); 1661 if(result) 1662 goto out; 1663 1664 if(blocking) { 1665 result = ssl_connect(cf, data); 1666 *done = (result == CURLE_OK); 1667 } 1668 else { 1669 result = ssl_connect_nonblocking(cf, data, done); 1670 } 1671 1672 if(!result && *done) { 1673 cf->connected = TRUE; 1674 connssl->handshake_done = Curl_now(); 1675 DEBUGASSERT(connssl->state == ssl_connection_complete); 1676 } 1677out: 1678 CURL_TRC_CF(data, cf, "cf_connect() -> %d, done=%d", result, *done); 1679 CF_DATA_RESTORE(cf, save); 1680 return result; 1681} 1682 1683static bool ssl_cf_data_pending(struct Curl_cfilter *cf, 1684 const struct Curl_easy *data) 1685{ 1686 struct cf_call_data save; 1687 bool result; 1688 1689 CF_DATA_SAVE(save, cf, data); 1690 if(Curl_ssl->data_pending(cf, data)) 1691 result = TRUE; 1692 else 1693 result = cf->next->cft->has_data_pending(cf->next, data); 1694 CF_DATA_RESTORE(cf, save); 1695 return result; 1696} 1697 1698static ssize_t ssl_cf_send(struct Curl_cfilter *cf, 1699 struct Curl_easy *data, const void *buf, size_t len, 1700 CURLcode *err) 1701{ 1702 struct cf_call_data save; 1703 ssize_t nwritten; 1704 1705 CF_DATA_SAVE(save, cf, data); 1706 *err = CURLE_OK; 1707 nwritten = Curl_ssl->send_plain(cf, data, buf, len, err); 1708 CF_DATA_RESTORE(cf, save); 1709 return nwritten; 1710} 1711 1712static ssize_t ssl_cf_recv(struct Curl_cfilter *cf, 1713 struct Curl_easy *data, char *buf, size_t len, 1714 CURLcode *err) 1715{ 1716 struct cf_call_data save; 1717 ssize_t nread; 1718 size_t ntotal = 0; 1719 1720 CF_DATA_SAVE(save, cf, data); 1721 *err = CURLE_OK; 1722 /* Do receive until we fill the buffer somehwhat or EGAIN, error or EOF */ 1723 while(!ntotal || (len - ntotal) > (4*1024)) { 1724 *err = CURLE_OK; 1725 nread = Curl_ssl->recv_plain(cf, data, buf + ntotal, len - ntotal, err); 1726 if(nread < 0) { 1727 if(*err == CURLE_AGAIN && ntotal > 0) { 1728 /* we EAGAINed after having reed data, return the success amount */ 1729 *err = CURLE_OK; 1730 break; 1731 } 1732 /* we have a an error to report */ 1733 goto out; 1734 } 1735 else if(nread == 0) { 1736 /* eof */ 1737 break; 1738 } 1739 ntotal += (size_t)nread; 1740 DEBUGASSERT((size_t)ntotal <= len); 1741 } 1742 nread = (ssize_t)ntotal; 1743out: 1744 CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len, 1745 nread, *err); 1746 CF_DATA_RESTORE(cf, save); 1747 return nread; 1748} 1749 1750static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf, 1751 struct Curl_easy *data, 1752 struct easy_pollset *ps) 1753{ 1754 struct cf_call_data save; 1755 1756 if(!cf->connected) { 1757 CF_DATA_SAVE(save, cf, data); 1758 Curl_ssl->adjust_pollset(cf, data, ps); 1759 CF_DATA_RESTORE(cf, save); 1760 } 1761} 1762 1763static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf, 1764 struct Curl_easy *data, 1765 int event, int arg1, void *arg2) 1766{ 1767 struct cf_call_data save; 1768 1769 (void)arg1; 1770 (void)arg2; 1771 switch(event) { 1772 case CF_CTRL_DATA_ATTACH: 1773 if(Curl_ssl->attach_data) { 1774 CF_DATA_SAVE(save, cf, data); 1775 Curl_ssl->attach_data(cf, data); 1776 CF_DATA_RESTORE(cf, save); 1777 } 1778 break; 1779 case CF_CTRL_DATA_DETACH: 1780 if(Curl_ssl->detach_data) { 1781 CF_DATA_SAVE(save, cf, data); 1782 Curl_ssl->detach_data(cf, data); 1783 CF_DATA_RESTORE(cf, save); 1784 } 1785 break; 1786 default: 1787 break; 1788 } 1789 return CURLE_OK; 1790} 1791 1792static CURLcode ssl_cf_query(struct Curl_cfilter *cf, 1793 struct Curl_easy *data, 1794 int query, int *pres1, void *pres2) 1795{ 1796 struct ssl_connect_data *connssl = cf->ctx; 1797 1798 switch(query) { 1799 case CF_QUERY_TIMER_APPCONNECT: { 1800 struct curltime *when = pres2; 1801 if(cf->connected && !Curl_ssl_cf_is_proxy(cf)) 1802 *when = connssl->handshake_done; 1803 return CURLE_OK; 1804 } 1805 default: 1806 break; 1807 } 1808 return cf->next? 1809 cf->next->cft->query(cf->next, data, query, pres1, pres2) : 1810 CURLE_UNKNOWN_OPTION; 1811} 1812 1813static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data, 1814 bool *input_pending) 1815{ 1816 struct cf_call_data save; 1817 int result; 1818 /* 1819 * This function tries to determine connection status. 1820 * 1821 * Return codes: 1822 * 1 means the connection is still in place 1823 * 0 means the connection has been closed 1824 * -1 means the connection status is unknown 1825 */ 1826 CF_DATA_SAVE(save, cf, data); 1827 result = Curl_ssl->check_cxn(cf, data); 1828 CF_DATA_RESTORE(cf, save); 1829 if(result > 0) { 1830 *input_pending = TRUE; 1831 return TRUE; 1832 } 1833 if(result == 0) { 1834 *input_pending = FALSE; 1835 return FALSE; 1836 } 1837 /* ssl backend does not know */ 1838 return cf->next? 1839 cf->next->cft->is_alive(cf->next, data, input_pending) : 1840 FALSE; /* pessimistic in absence of data */ 1841} 1842 1843struct Curl_cftype Curl_cft_ssl = { 1844 "SSL", 1845 CF_TYPE_SSL, 1846 CURL_LOG_LVL_NONE, 1847 ssl_cf_destroy, 1848 ssl_cf_connect, 1849 ssl_cf_close, 1850 Curl_cf_def_get_host, 1851 ssl_cf_adjust_pollset, 1852 ssl_cf_data_pending, 1853 ssl_cf_send, 1854 ssl_cf_recv, 1855 ssl_cf_cntrl, 1856 cf_ssl_is_alive, 1857 Curl_cf_def_conn_keep_alive, 1858 ssl_cf_query, 1859}; 1860 1861#ifndef CURL_DISABLE_PROXY 1862 1863struct Curl_cftype Curl_cft_ssl_proxy = { 1864 "SSL-PROXY", 1865 CF_TYPE_SSL, 1866 CURL_LOG_LVL_NONE, 1867 ssl_cf_destroy, 1868 ssl_cf_connect, 1869 ssl_cf_close, 1870 Curl_cf_def_get_host, 1871 ssl_cf_adjust_pollset, 1872 ssl_cf_data_pending, 1873 ssl_cf_send, 1874 ssl_cf_recv, 1875 ssl_cf_cntrl, 1876 cf_ssl_is_alive, 1877 Curl_cf_def_conn_keep_alive, 1878 Curl_cf_def_query, 1879}; 1880 1881#endif /* !CURL_DISABLE_PROXY */ 1882 1883static CURLcode cf_ssl_create(struct Curl_cfilter **pcf, 1884 struct Curl_easy *data, 1885 struct connectdata *conn) 1886{ 1887 struct Curl_cfilter *cf = NULL; 1888 struct ssl_connect_data *ctx; 1889 CURLcode result; 1890 1891 DEBUGASSERT(data->conn); 1892 1893 ctx = cf_ctx_new(data, alpn_get_spec(data->state.httpwant, 1894 conn->bits.tls_enable_alpn)); 1895 if(!ctx) { 1896 result = CURLE_OUT_OF_MEMORY; 1897 goto out; 1898 } 1899 1900 result = Curl_cf_create(&cf, &Curl_cft_ssl, ctx); 1901 1902out: 1903 if(result) 1904 cf_ctx_free(ctx); 1905 *pcf = result? NULL : cf; 1906 return result; 1907} 1908 1909CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data, 1910 struct connectdata *conn, 1911 int sockindex) 1912{ 1913 struct Curl_cfilter *cf; 1914 CURLcode result; 1915 1916 result = cf_ssl_create(&cf, data, conn); 1917 if(!result) 1918 Curl_conn_cf_add(data, conn, sockindex, cf); 1919 return result; 1920} 1921 1922CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at, 1923 struct Curl_easy *data) 1924{ 1925 struct Curl_cfilter *cf; 1926 CURLcode result; 1927 1928 result = cf_ssl_create(&cf, data, cf_at->conn); 1929 if(!result) 1930 Curl_conn_cf_insert_after(cf_at, cf); 1931 return result; 1932} 1933 1934#ifndef CURL_DISABLE_PROXY 1935 1936static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf, 1937 struct Curl_easy *data, 1938 struct connectdata *conn) 1939{ 1940 struct Curl_cfilter *cf = NULL; 1941 struct ssl_connect_data *ctx; 1942 CURLcode result; 1943 bool use_alpn = conn->bits.tls_enable_alpn; 1944 int httpwant = CURL_HTTP_VERSION_1_1; 1945 1946#ifdef USE_HTTP2 1947 if(conn->http_proxy.proxytype == CURLPROXY_HTTPS2) { 1948 use_alpn = TRUE; 1949 httpwant = CURL_HTTP_VERSION_2; 1950 } 1951#endif 1952 1953 ctx = cf_ctx_new(data, alpn_get_spec(httpwant, use_alpn)); 1954 if(!ctx) { 1955 result = CURLE_OUT_OF_MEMORY; 1956 goto out; 1957 } 1958 result = Curl_cf_create(&cf, &Curl_cft_ssl_proxy, ctx); 1959 1960out: 1961 if(result) 1962 cf_ctx_free(ctx); 1963 *pcf = result? NULL : cf; 1964 return result; 1965} 1966 1967CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at, 1968 struct Curl_easy *data) 1969{ 1970 struct Curl_cfilter *cf; 1971 CURLcode result; 1972 1973 result = cf_ssl_proxy_create(&cf, data, cf_at->conn); 1974 if(!result) 1975 Curl_conn_cf_insert_after(cf_at, cf); 1976 return result; 1977} 1978 1979#endif /* !CURL_DISABLE_PROXY */ 1980 1981bool Curl_ssl_supports(struct Curl_easy *data, int option) 1982{ 1983 (void)data; 1984 return (Curl_ssl->supports & option)? TRUE : FALSE; 1985} 1986 1987static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf) 1988{ 1989 for(; cf; cf = cf->next) { 1990 if(cf->cft == &Curl_cft_ssl) 1991 return cf; 1992#ifndef CURL_DISABLE_PROXY 1993 if(cf->cft == &Curl_cft_ssl_proxy) 1994 return cf; 1995#endif 1996 } 1997 return NULL; 1998} 1999 2000 2001void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex, 2002 CURLINFO info, int n) 2003{ 2004 void *result = NULL; 2005 (void)n; 2006 if(data->conn) { 2007 struct Curl_cfilter *cf; 2008 /* get first SSL filter in chain, if any is present */ 2009 cf = get_ssl_filter(data->conn->cfilter[sockindex]); 2010 if(cf) { 2011 struct cf_call_data save; 2012 CF_DATA_SAVE(save, cf, data); 2013 result = Curl_ssl->get_internals(cf->ctx, info); 2014 CF_DATA_RESTORE(cf, save); 2015 } 2016 } 2017 return result; 2018} 2019 2020CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data, 2021 int sockindex) 2022{ 2023 struct Curl_cfilter *cf, *head; 2024 CURLcode result = CURLE_OK; 2025 2026 (void)data; 2027 head = data->conn? data->conn->cfilter[sockindex] : NULL; 2028 for(cf = head; cf; cf = cf->next) { 2029 if(cf->cft == &Curl_cft_ssl) { 2030 if(Curl_ssl->shut_down(cf, data)) 2031 result = CURLE_SSL_SHUTDOWN_FAILED; 2032 Curl_conn_cf_discard_sub(head, cf, data, FALSE); 2033 break; 2034 } 2035 } 2036 return result; 2037} 2038 2039bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf) 2040{ 2041#ifndef CURL_DISABLE_PROXY 2042 return (cf->cft == &Curl_cft_ssl_proxy); 2043#else 2044 (void)cf; 2045 return FALSE; 2046#endif 2047} 2048 2049struct ssl_config_data * 2050Curl_ssl_cf_get_config(struct Curl_cfilter *cf, struct Curl_easy *data) 2051{ 2052#ifdef CURL_DISABLE_PROXY 2053 (void)cf; 2054 return &data->set.ssl; 2055#else 2056 return Curl_ssl_cf_is_proxy(cf)? &data->set.proxy_ssl : &data->set.ssl; 2057#endif 2058} 2059 2060struct ssl_primary_config * 2061Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf) 2062{ 2063#ifdef CURL_DISABLE_PROXY 2064 return &cf->conn->ssl_config; 2065#else 2066 return Curl_ssl_cf_is_proxy(cf)? 2067 &cf->conn->proxy_ssl_config : &cf->conn->ssl_config; 2068#endif 2069} 2070 2071CURLcode Curl_alpn_to_proto_buf(struct alpn_proto_buf *buf, 2072 const struct alpn_spec *spec) 2073{ 2074 size_t i, len; 2075 int off = 0; 2076 unsigned char blen; 2077 2078 memset(buf, 0, sizeof(*buf)); 2079 for(i = 0; spec && i < spec->count; ++i) { 2080 len = strlen(spec->entries[i]); 2081 if(len >= ALPN_NAME_MAX) 2082 return CURLE_FAILED_INIT; 2083 blen = (unsigned char)len; 2084 if(off + blen + 1 >= (int)sizeof(buf->data)) 2085 return CURLE_FAILED_INIT; 2086 buf->data[off++] = blen; 2087 memcpy(buf->data + off, spec->entries[i], blen); 2088 off += blen; 2089 } 2090 buf->len = off; 2091 return CURLE_OK; 2092} 2093 2094CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf, 2095 const struct alpn_spec *spec) 2096{ 2097 size_t i, len; 2098 size_t off = 0; 2099 2100 memset(buf, 0, sizeof(*buf)); 2101 for(i = 0; spec && i < spec->count; ++i) { 2102 len = strlen(spec->entries[i]); 2103 if(len >= ALPN_NAME_MAX) 2104 return CURLE_FAILED_INIT; 2105 if(off + len + 2 >= sizeof(buf->data)) 2106 return CURLE_FAILED_INIT; 2107 if(off) 2108 buf->data[off++] = ','; 2109 memcpy(buf->data + off, spec->entries[i], len); 2110 off += len; 2111 } 2112 buf->data[off] = '\0'; 2113 buf->len = (int)off; 2114 return CURLE_OK; 2115} 2116 2117CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf, 2118 struct Curl_easy *data, 2119 const unsigned char *proto, 2120 size_t proto_len) 2121{ 2122 int can_multi = 0; 2123 unsigned char *palpn = 2124#ifndef CURL_DISABLE_PROXY 2125 (cf->conn->bits.tunnel_proxy && Curl_ssl_cf_is_proxy(cf))? 2126 &cf->conn->proxy_alpn : &cf->conn->alpn 2127#else 2128 &cf->conn->alpn 2129#endif 2130 ; 2131 2132 if(proto && proto_len) { 2133 if(proto_len == ALPN_HTTP_1_1_LENGTH && 2134 !memcmp(ALPN_HTTP_1_1, proto, ALPN_HTTP_1_1_LENGTH)) { 2135 *palpn = CURL_HTTP_VERSION_1_1; 2136 } 2137#ifdef USE_HTTP2 2138 else if(proto_len == ALPN_H2_LENGTH && 2139 !memcmp(ALPN_H2, proto, ALPN_H2_LENGTH)) { 2140 *palpn = CURL_HTTP_VERSION_2; 2141 can_multi = 1; 2142 } 2143#endif 2144#ifdef USE_HTTP3 2145 else if(proto_len == ALPN_H3_LENGTH && 2146 !memcmp(ALPN_H3, proto, ALPN_H3_LENGTH)) { 2147 *palpn = CURL_HTTP_VERSION_3; 2148 can_multi = 1; 2149 } 2150#endif 2151 else { 2152 *palpn = CURL_HTTP_VERSION_NONE; 2153 failf(data, "unsupported ALPN protocol: '%.*s'", (int)proto_len, proto); 2154 /* TODO: do we want to fail this? Previous code just ignored it and 2155 * some vtls backends even ignore the return code of this function. */ 2156 /* return CURLE_NOT_BUILT_IN; */ 2157 goto out; 2158 } 2159 infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, (int)proto_len, proto); 2160 } 2161 else { 2162 *palpn = CURL_HTTP_VERSION_NONE; 2163 infof(data, VTLS_INFOF_NO_ALPN); 2164 } 2165 2166out: 2167 if(!Curl_ssl_cf_is_proxy(cf)) 2168 Curl_multiuse_state(data, can_multi? 2169 BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); 2170 return CURLE_OK; 2171} 2172 2173#endif /* USE_SSL */ 2174