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#include "curl_setup.h" 26 27#if defined(ENABLE_QUIC) && \ 28 (defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_WOLFSSL)) 29 30#ifdef USE_OPENSSL 31#include <openssl/err.h> 32#include "vtls/openssl.h" 33#elif defined(USE_GNUTLS) 34#include <gnutls/abstract.h> 35#include <gnutls/gnutls.h> 36#include <gnutls/x509.h> 37#include <gnutls/crypto.h> 38#include <nettle/sha2.h> 39#include "vtls/gtls.h" 40#elif defined(USE_WOLFSSL) 41#include <wolfssl/options.h> 42#include <wolfssl/ssl.h> 43#include <wolfssl/quic.h> 44#include "vtls/wolfssl.h" 45#endif 46 47#include "urldata.h" 48#include "curl_trc.h" 49#include "cfilters.h" 50#include "multiif.h" 51#include "vtls/keylog.h" 52#include "vtls/vtls.h" 53#include "vquic-tls.h" 54 55/* The last 3 #include files should be in this order */ 56#include "curl_printf.h" 57#include "curl_memory.h" 58#include "memdebug.h" 59 60#ifndef ARRAYSIZE 61#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) 62#endif 63 64#ifdef USE_OPENSSL 65#define QUIC_CIPHERS \ 66 "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \ 67 "POLY1305_SHA256:TLS_AES_128_CCM_SHA256" 68#define QUIC_GROUPS "P-256:X25519:P-384:P-521" 69#elif defined(USE_GNUTLS) 70#define QUIC_PRIORITY \ 71 "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \ 72 "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \ 73 "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \ 74 "%DISABLE_TLS13_COMPAT_MODE" 75#elif defined(USE_WOLFSSL) 76#define QUIC_CIPHERS \ 77 "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \ 78 "POLY1305_SHA256:TLS_AES_128_CCM_SHA256" 79#define QUIC_GROUPS "P-256:P-384:P-521" 80#endif 81 82 83#ifdef USE_OPENSSL 84 85static void keylog_callback(const SSL *ssl, const char *line) 86{ 87 (void)ssl; 88 Curl_tls_keylog_write_line(line); 89} 90 91static CURLcode curl_ossl_init_ctx(struct quic_tls_ctx *ctx, 92 struct Curl_cfilter *cf, 93 struct Curl_easy *data, 94 Curl_vquic_tls_ctx_setup *ctx_setup) 95{ 96 struct ssl_primary_config *conn_config; 97 CURLcode result = CURLE_FAILED_INIT; 98 99 DEBUGASSERT(!ctx->ssl_ctx); 100#ifdef USE_OPENSSL_QUIC 101 ctx->ssl_ctx = SSL_CTX_new(OSSL_QUIC_client_method()); 102#else 103 ctx->ssl_ctx = SSL_CTX_new(TLS_method()); 104#endif 105 if(!ctx->ssl_ctx) { 106 result = CURLE_OUT_OF_MEMORY; 107 goto out; 108 } 109 conn_config = Curl_ssl_cf_get_primary_config(cf); 110 if(!conn_config) { 111 result = CURLE_FAILED_INIT; 112 goto out; 113 } 114 115 if(ctx_setup) { 116 result = ctx_setup(ctx, cf, data); 117 if(result) 118 goto out; 119 } 120 121 SSL_CTX_set_default_verify_paths(ctx->ssl_ctx); 122 123 { 124 const char *curves = conn_config->curves ? 125 conn_config->curves : QUIC_GROUPS; 126 if(!SSL_CTX_set1_curves_list(ctx->ssl_ctx, curves)) { 127 failf(data, "failed setting curves list for QUIC: '%s'", curves); 128 return CURLE_SSL_CIPHER; 129 } 130 } 131 132#ifndef OPENSSL_IS_BORINGSSL 133 { 134 const char *ciphers13 = conn_config->cipher_list13 ? 135 conn_config->cipher_list13 : QUIC_CIPHERS; 136 if(SSL_CTX_set_ciphersuites(ctx->ssl_ctx, ciphers13) != 1) { 137 failf(data, "failed setting QUIC cipher suite: %s", ciphers13); 138 return CURLE_SSL_CIPHER; 139 } 140 infof(data, "QUIC cipher selection: %s", ciphers13); 141 } 142#endif 143 144 /* Open the file if a TLS or QUIC backend has not done this before. */ 145 Curl_tls_keylog_open(); 146 if(Curl_tls_keylog_enabled()) { 147 SSL_CTX_set_keylog_callback(ctx->ssl_ctx, keylog_callback); 148 } 149 150 /* OpenSSL always tries to verify the peer, this only says whether it should 151 * fail to connect if the verification fails, or if it should continue 152 * anyway. In the latter case the result of the verification is checked with 153 * SSL_get_verify_result() below. */ 154 SSL_CTX_set_verify(ctx->ssl_ctx, conn_config->verifypeer ? 155 SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); 156 157 /* give application a chance to interfere with SSL set up. */ 158 if(data->set.ssl.fsslctx) { 159 /* When a user callback is installed to modify the SSL_CTX, 160 * we need to do the full initialization before calling it. 161 * See: #11800 */ 162 if(!ctx->x509_store_setup) { 163 result = Curl_ssl_setup_x509_store(cf, data, ctx->ssl_ctx); 164 if(result) 165 goto out; 166 ctx->x509_store_setup = TRUE; 167 } 168 Curl_set_in_callback(data, true); 169 result = (*data->set.ssl.fsslctx)(data, ctx->ssl_ctx, 170 data->set.ssl.fsslctxp); 171 Curl_set_in_callback(data, false); 172 if(result) { 173 failf(data, "error signaled by ssl ctx callback"); 174 goto out; 175 } 176 } 177 result = CURLE_OK; 178 179out: 180 if(result && ctx->ssl_ctx) { 181 SSL_CTX_free(ctx->ssl_ctx); 182 ctx->ssl_ctx = NULL; 183 } 184 return result; 185} 186 187static CURLcode curl_ossl_set_client_cert(struct quic_tls_ctx *ctx, 188 struct Curl_cfilter *cf, 189 struct Curl_easy *data) 190{ 191 SSL_CTX *ssl_ctx = ctx->ssl_ctx; 192 const struct ssl_config_data *ssl_config; 193 194 ssl_config = Curl_ssl_cf_get_config(cf, data); 195 DEBUGASSERT(ssl_config); 196 197 if(ssl_config->primary.clientcert || 198 ssl_config->primary.cert_blob || 199 ssl_config->cert_type) { 200 return Curl_ossl_set_client_cert( 201 data, ssl_ctx, ssl_config->primary.clientcert, 202 ssl_config->primary.cert_blob, ssl_config->cert_type, 203 ssl_config->key, ssl_config->key_blob, 204 ssl_config->key_type, ssl_config->key_passwd); 205 } 206 207 return CURLE_OK; 208} 209 210/** SSL callbacks ***/ 211 212static CURLcode curl_ossl_init_ssl(struct quic_tls_ctx *ctx, 213 struct Curl_easy *data, 214 struct ssl_peer *peer, 215 const char *alpn, size_t alpn_len, 216 void *user_data) 217{ 218 DEBUGASSERT(!ctx->ssl); 219 ctx->ssl = SSL_new(ctx->ssl_ctx); 220 221 SSL_set_app_data(ctx->ssl, user_data); 222 SSL_set_connect_state(ctx->ssl); 223#ifndef USE_OPENSSL_QUIC 224 SSL_set_quic_use_legacy_codepoint(ctx->ssl, 0); 225#endif 226 227 if(alpn) 228 SSL_set_alpn_protos(ctx->ssl, (const uint8_t *)alpn, (int)alpn_len); 229 230 if(peer->sni) { 231 if(!SSL_set_tlsext_host_name(ctx->ssl, peer->sni)) { 232 failf(data, "Failed set SNI"); 233 SSL_free(ctx->ssl); 234 ctx->ssl = NULL; 235 return CURLE_QUIC_CONNECT_ERROR; 236 } 237 } 238 return CURLE_OK; 239} 240 241#elif defined(USE_GNUTLS) 242static int keylog_callback(gnutls_session_t session, const char *label, 243 const gnutls_datum_t *secret) 244{ 245 gnutls_datum_t crandom; 246 gnutls_datum_t srandom; 247 248 gnutls_session_get_random(session, &crandom, &srandom); 249 if(crandom.size != 32) { 250 return -1; 251 } 252 253 Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size); 254 return 0; 255} 256 257static CURLcode curl_gtls_init_ctx(struct quic_tls_ctx *ctx, 258 struct Curl_cfilter *cf, 259 struct Curl_easy *data, 260 struct ssl_peer *peer, 261 const char *alpn, size_t alpn_len, 262 Curl_vquic_tls_ctx_setup *ctx_setup, 263 void *user_data) 264{ 265 struct ssl_primary_config *conn_config; 266 CURLcode result; 267 gnutls_datum_t alpns[5]; 268 /* this will need some attention when HTTPS proxy over QUIC get fixed */ 269 long * const pverifyresult = &data->set.ssl.certverifyresult; 270 int rc; 271 272 conn_config = Curl_ssl_cf_get_primary_config(cf); 273 if(!conn_config) 274 return CURLE_FAILED_INIT; 275 276 DEBUGASSERT(ctx->gtls == NULL); 277 ctx->gtls = calloc(1, sizeof(*(ctx->gtls))); 278 if(!ctx->gtls) 279 return CURLE_OUT_OF_MEMORY; 280 281 result = gtls_client_init(data, conn_config, &data->set.ssl, 282 peer, ctx->gtls, pverifyresult); 283 if(result) 284 return result; 285 286 gnutls_session_set_ptr(ctx->gtls->session, user_data); 287 288 if(ctx_setup) { 289 result = ctx_setup(ctx, cf, data); 290 if(result) 291 return result; 292 } 293 294 rc = gnutls_priority_set_direct(ctx->gtls->session, QUIC_PRIORITY, NULL); 295 if(rc < 0) { 296 CURL_TRC_CF(data, cf, "gnutls_priority_set_direct failed: %s\n", 297 gnutls_strerror(rc)); 298 return CURLE_QUIC_CONNECT_ERROR; 299 } 300 301 /* Open the file if a TLS or QUIC backend has not done this before. */ 302 Curl_tls_keylog_open(); 303 if(Curl_tls_keylog_enabled()) { 304 gnutls_session_set_keylog_function(ctx->gtls->session, keylog_callback); 305 } 306 307 /* convert the ALPN string from our arguments to a list of strings 308 * that gnutls wants and will convert internally back to this very 309 * string for sending to the server. nice. */ 310 if(alpn) { 311 size_t i, alen = alpn_len; 312 unsigned char *s = (unsigned char *)alpn; 313 unsigned char slen; 314 for(i = 0; (i < ARRAYSIZE(alpns)) && alen; ++i) { 315 slen = s[0]; 316 if(slen >= alen) 317 return CURLE_FAILED_INIT; 318 alpns[i].data = s + 1; 319 alpns[i].size = slen; 320 s += slen + 1; 321 alen -= (size_t)slen + 1; 322 } 323 if(alen) /* not all alpn chars used, wrong format or too many */ 324 return CURLE_FAILED_INIT; 325 if(i) { 326 gnutls_alpn_set_protocols(ctx->gtls->session, 327 alpns, (unsigned int)i, 328 GNUTLS_ALPN_MANDATORY); 329 } 330 } 331 332 return CURLE_OK; 333} 334#elif defined(USE_WOLFSSL) 335 336#if defined(HAVE_SECRET_CALLBACK) 337static void keylog_callback(const WOLFSSL *ssl, const char *line) 338{ 339 (void)ssl; 340 Curl_tls_keylog_write_line(line); 341} 342#endif 343 344static CURLcode curl_wssl_init_ctx(struct quic_tls_ctx *ctx, 345 struct Curl_cfilter *cf, 346 struct Curl_easy *data, 347 Curl_vquic_tls_ctx_setup *ctx_setup) 348{ 349 struct ssl_primary_config *conn_config; 350 CURLcode result = CURLE_FAILED_INIT; 351 352 conn_config = Curl_ssl_cf_get_primary_config(cf); 353 if(!conn_config) { 354 result = CURLE_FAILED_INIT; 355 goto out; 356 } 357 358 ctx->ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); 359 if(!ctx->ssl_ctx) { 360 result = CURLE_OUT_OF_MEMORY; 361 goto out; 362 } 363 364 if(ctx_setup) { 365 result = ctx_setup(ctx, cf, data); 366 if(result) 367 goto out; 368 } 369 370 wolfSSL_CTX_set_default_verify_paths(ctx->ssl_ctx); 371 372 if(wolfSSL_CTX_set_cipher_list(ctx->ssl_ctx, conn_config->cipher_list13 ? 373 conn_config->cipher_list13 : 374 QUIC_CIPHERS) != 1) { 375 char error_buffer[256]; 376 ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer)); 377 failf(data, "wolfSSL failed to set ciphers: %s", error_buffer); 378 result = CURLE_BAD_FUNCTION_ARGUMENT; 379 goto out; 380 } 381 382 if(wolfSSL_CTX_set1_groups_list(ctx->ssl_ctx, conn_config->curves ? 383 conn_config->curves : 384 (char *)QUIC_GROUPS) != 1) { 385 failf(data, "wolfSSL failed to set curves"); 386 result = CURLE_BAD_FUNCTION_ARGUMENT; 387 goto out; 388 } 389 390 /* Open the file if a TLS or QUIC backend has not done this before. */ 391 Curl_tls_keylog_open(); 392 if(Curl_tls_keylog_enabled()) { 393#if defined(HAVE_SECRET_CALLBACK) 394 wolfSSL_CTX_set_keylog_callback(ctx->ssl_ctx, keylog_callback); 395#else 396 failf(data, "wolfSSL was built without keylog callback"); 397 result = CURLE_NOT_BUILT_IN; 398 goto out; 399#endif 400 } 401 402 if(conn_config->verifypeer) { 403 const char * const ssl_cafile = conn_config->CAfile; 404 const char * const ssl_capath = conn_config->CApath; 405 406 wolfSSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL); 407 if(ssl_cafile || ssl_capath) { 408 /* tell wolfSSL where to find CA certificates that are used to verify 409 the server's certificate. */ 410 int rc = 411 wolfSSL_CTX_load_verify_locations_ex(ctx->ssl_ctx, ssl_cafile, 412 ssl_capath, 413 WOLFSSL_LOAD_FLAG_IGNORE_ERR); 414 if(SSL_SUCCESS != rc) { 415 /* Fail if we insist on successfully verifying the server. */ 416 failf(data, "error setting certificate verify locations:" 417 " CAfile: %s CApath: %s", 418 ssl_cafile ? ssl_cafile : "none", 419 ssl_capath ? ssl_capath : "none"); 420 result = CURLE_SSL_CACERT; 421 goto out; 422 } 423 infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); 424 infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); 425 } 426#ifdef CURL_CA_FALLBACK 427 else { 428 /* verifying the peer without any CA certificates won't work so 429 use wolfssl's built-in default as fallback */ 430 wolfSSL_CTX_set_default_verify_paths(ctx->ssl_ctx); 431 } 432#endif 433 } 434 else { 435 wolfSSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_NONE, NULL); 436 } 437 438 /* give application a chance to interfere with SSL set up. */ 439 if(data->set.ssl.fsslctx) { 440 Curl_set_in_callback(data, true); 441 result = (*data->set.ssl.fsslctx)(data, ctx->ssl_ctx, 442 data->set.ssl.fsslctxp); 443 Curl_set_in_callback(data, false); 444 if(result) { 445 failf(data, "error signaled by ssl ctx callback"); 446 goto out; 447 } 448 } 449 result = CURLE_OK; 450 451out: 452 if(result && ctx->ssl_ctx) { 453 SSL_CTX_free(ctx->ssl_ctx); 454 ctx->ssl_ctx = NULL; 455 } 456 return result; 457} 458 459/** SSL callbacks ***/ 460 461static CURLcode curl_wssl_init_ssl(struct quic_tls_ctx *ctx, 462 struct Curl_easy *data, 463 struct ssl_peer *peer, 464 const char *alpn, size_t alpn_len, 465 void *user_data) 466{ 467 (void)data; 468 DEBUGASSERT(!ctx->ssl); 469 DEBUGASSERT(ctx->ssl_ctx); 470 ctx->ssl = wolfSSL_new(ctx->ssl_ctx); 471 472 wolfSSL_set_app_data(ctx->ssl, user_data); 473 wolfSSL_set_connect_state(ctx->ssl); 474 wolfSSL_set_quic_use_legacy_codepoint(ctx->ssl, 0); 475 476 if(alpn) 477 wolfSSL_set_alpn_protos(ctx->ssl, (const unsigned char *)alpn, 478 (int)alpn_len); 479 480 if(peer->sni) { 481 wolfSSL_UseSNI(ctx->ssl, WOLFSSL_SNI_HOST_NAME, 482 peer->sni, (unsigned short)strlen(peer->sni)); 483 } 484 485 return CURLE_OK; 486} 487#endif /* defined(USE_WOLFSSL) */ 488 489CURLcode Curl_vquic_tls_init(struct quic_tls_ctx *ctx, 490 struct Curl_cfilter *cf, 491 struct Curl_easy *data, 492 struct ssl_peer *peer, 493 const char *alpn, size_t alpn_len, 494 Curl_vquic_tls_ctx_setup *ctx_setup, 495 void *user_data) 496{ 497 CURLcode result; 498 499#ifdef USE_OPENSSL 500 result = curl_ossl_init_ctx(ctx, cf, data, ctx_setup); 501 if(result) 502 return result; 503 504 result = curl_ossl_set_client_cert(ctx, cf, data); 505 if(result) 506 return result; 507 508 return curl_ossl_init_ssl(ctx, data, peer, alpn, alpn_len, user_data); 509#elif defined(USE_GNUTLS) 510 (void)result; 511 return curl_gtls_init_ctx(ctx, cf, data, peer, alpn, alpn_len, 512 ctx_setup, user_data); 513#elif defined(USE_WOLFSSL) 514 result = curl_wssl_init_ctx(ctx, cf, data, ctx_setup); 515 if(result) 516 return result; 517 518 return curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, user_data); 519#else 520#error "no TLS lib in used, should not happen" 521 return CURLE_FAILED_INIT; 522#endif 523} 524 525void Curl_vquic_tls_cleanup(struct quic_tls_ctx *ctx) 526{ 527#ifdef USE_OPENSSL 528 if(ctx->ssl) 529 SSL_free(ctx->ssl); 530 if(ctx->ssl_ctx) 531 SSL_CTX_free(ctx->ssl_ctx); 532#elif defined(USE_GNUTLS) 533 if(ctx->gtls) { 534 if(ctx->gtls->cred) 535 gnutls_certificate_free_credentials(ctx->gtls->cred); 536 if(ctx->gtls->session) 537 gnutls_deinit(ctx->gtls->session); 538 free(ctx->gtls); 539 } 540#elif defined(USE_WOLFSSL) 541 if(ctx->ssl) 542 wolfSSL_free(ctx->ssl); 543 if(ctx->ssl_ctx) 544 wolfSSL_CTX_free(ctx->ssl_ctx); 545#endif 546 memset(ctx, 0, sizeof(*ctx)); 547} 548 549CURLcode Curl_vquic_tls_before_recv(struct quic_tls_ctx *ctx, 550 struct Curl_cfilter *cf, 551 struct Curl_easy *data) 552{ 553#ifdef USE_OPENSSL 554 if(!ctx->x509_store_setup) { 555 CURLcode result = Curl_ssl_setup_x509_store(cf, data, ctx->ssl_ctx); 556 if(result) 557 return result; 558 ctx->x509_store_setup = TRUE; 559 } 560#else 561 (void)ctx; (void)cf; (void)data; 562#endif 563 return CURLE_OK; 564} 565 566CURLcode Curl_vquic_tls_verify_peer(struct quic_tls_ctx *ctx, 567 struct Curl_cfilter *cf, 568 struct Curl_easy *data, 569 struct ssl_peer *peer) 570{ 571 struct ssl_primary_config *conn_config; 572 CURLcode result = CURLE_OK; 573 574 conn_config = Curl_ssl_cf_get_primary_config(cf); 575 if(!conn_config) 576 return CURLE_FAILED_INIT; 577 578 if(conn_config->verifyhost) { 579#ifdef USE_OPENSSL 580 X509 *server_cert; 581 server_cert = SSL_get1_peer_certificate(ctx->ssl); 582 if(!server_cert) { 583 return CURLE_PEER_FAILED_VERIFICATION; 584 } 585 result = Curl_ossl_verifyhost(data, cf->conn, peer, server_cert); 586 X509_free(server_cert); 587 if(result) 588 return result; 589#elif defined(USE_GNUTLS) 590 result = Curl_gtls_verifyserver(data, ctx->gtls->session, 591 conn_config, &data->set.ssl, peer, 592 data->set.str[STRING_SSL_PINNEDPUBLICKEY]); 593 if(result) 594 return result; 595#elif defined(USE_WOLFSSL) 596 if(!peer->sni || 597 wolfSSL_check_domain_name(ctx->ssl, peer->sni) == SSL_FAILURE) 598 return CURLE_PEER_FAILED_VERIFICATION; 599#endif 600 infof(data, "Verified certificate just fine"); 601 } 602 else 603 infof(data, "Skipped certificate verification"); 604#ifdef USE_OPENSSL 605 if(data->set.ssl.certinfo) 606 /* asked to gather certificate info */ 607 (void)Curl_ossl_certchain(data, ctx->ssl); 608#endif 609 return result; 610} 611 612 613#endif /* !ENABLE_QUIC && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */ 614