rustls.c (44465B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Jacob Hoffman-Andrews, 9 * <github@hoffman-andrews.com> 10 * Copyright (C) kpcyrd, <kpcyrd@archlinux.org> 11 * Copyright (C) Daniel McCarney, <daniel@binaryparadox.net> 12 * 13 * This software is licensed as described in the file COPYING, which 14 * you should have received as part of this distribution. The terms 15 * are also available at https://curl.se/docs/copyright.html. 16 * 17 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 18 * copies of the Software, and permit persons to whom the Software is 19 * furnished to do so, under the terms of the COPYING file. 20 * 21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 22 * KIND, either express or implied. 23 * 24 * SPDX-License-Identifier: curl 25 * 26 ***************************************************************************/ 27 #include "../curl_setup.h" 28 29 #ifdef USE_RUSTLS 30 31 #include "../curl_printf.h" 32 33 #include <rustls.h> 34 35 #include "../curlx/inet_pton.h" 36 #include "../urldata.h" 37 #include "../sendf.h" 38 #include "vtls.h" 39 #include "vtls_int.h" 40 #include "rustls.h" 41 #include "keylog.h" 42 #include "../strerror.h" 43 #include "cipher_suite.h" 44 #include "x509asn1.h" 45 46 /* The last #include files should be: */ 47 #include "../curl_memory.h" 48 #include "../memdebug.h" 49 50 struct rustls_ssl_backend_data 51 { 52 const struct rustls_client_config *config; 53 struct rustls_connection *conn; 54 size_t plain_out_buffered; 55 BIT(data_in_pending); 56 BIT(sent_shutdown); 57 }; 58 59 /* For a given rustls_result error code, return the best-matching CURLcode. */ 60 static CURLcode map_error(const rustls_result r) 61 { 62 if(rustls_result_is_cert_error(r)) { 63 return CURLE_PEER_FAILED_VERIFICATION; 64 } 65 switch(r) { 66 case RUSTLS_RESULT_OK: 67 return CURLE_OK; 68 case RUSTLS_RESULT_NULL_PARAMETER: 69 return CURLE_BAD_FUNCTION_ARGUMENT; 70 default: 71 return CURLE_RECV_ERROR; 72 } 73 } 74 75 static void 76 rustls_failf(struct Curl_easy *data, const rustls_result rr, const char *msg) 77 { 78 char errorbuf[STRERROR_LEN]; 79 size_t errorlen; 80 rustls_error(rr, errorbuf, sizeof(errorbuf), &errorlen); 81 failf(data, "%s: %.*s", msg, (int)errorlen, errorbuf); 82 } 83 84 static bool 85 cr_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) 86 { 87 const struct ssl_connect_data *ctx = cf->ctx; 88 struct rustls_ssl_backend_data *backend; 89 90 (void)data; 91 DEBUGASSERT(ctx && ctx->backend); 92 backend = (struct rustls_ssl_backend_data *)ctx->backend; 93 return backend->data_in_pending; 94 } 95 96 struct io_ctx { 97 struct Curl_cfilter *cf; 98 struct Curl_easy *data; 99 }; 100 101 static int 102 read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n) 103 { 104 const struct io_ctx *io_ctx = userdata; 105 struct ssl_connect_data *const connssl = io_ctx->cf->ctx; 106 CURLcode result; 107 int ret = 0; 108 size_t nread; 109 110 result = Curl_conn_cf_recv(io_ctx->cf->next, io_ctx->data, 111 (char *)buf, len, &nread); 112 if(result) { 113 nread = 0; 114 /* !checksrc! disable ERRNOVAR 4 */ 115 if(CURLE_AGAIN == result) 116 ret = EAGAIN; 117 else 118 ret = EINVAL; 119 } 120 else if(nread == 0) 121 connssl->peer_closed = TRUE; 122 *out_n = (uintptr_t)nread; 123 CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %d, %zu", 124 len, result, nread); 125 return ret; 126 } 127 128 static int 129 write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n) 130 { 131 const struct io_ctx *io_ctx = userdata; 132 CURLcode result; 133 int ret = 0; 134 size_t nwritten; 135 136 result = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data, 137 (const char *)buf, len, FALSE, &nwritten); 138 if(result) { 139 nwritten = 0; 140 if(CURLE_AGAIN == result) 141 ret = EAGAIN; 142 else 143 ret = EINVAL; 144 } 145 *out_n = (uintptr_t)nwritten; 146 CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %d, %zu", 147 len, result, nwritten); 148 return ret; 149 } 150 151 static ssize_t tls_recv_more(struct Curl_cfilter *cf, 152 struct Curl_easy *data, CURLcode *err) 153 { 154 const struct ssl_connect_data *const connssl = cf->ctx; 155 struct rustls_ssl_backend_data *const backend = 156 (struct rustls_ssl_backend_data *)connssl->backend; 157 struct io_ctx io_ctx; 158 size_t tls_bytes_read = 0; 159 rustls_io_result io_error; 160 rustls_result rresult = 0; 161 162 io_ctx.cf = cf; 163 io_ctx.data = data; 164 io_error = rustls_connection_read_tls(backend->conn, read_cb, &io_ctx, 165 &tls_bytes_read); 166 if(io_error == EAGAIN || io_error == EWOULDBLOCK) { 167 *err = CURLE_AGAIN; 168 return -1; 169 } 170 else if(io_error) { 171 char buffer[STRERROR_LEN]; 172 failf(data, "reading from socket: %s", 173 Curl_strerror(io_error, buffer, sizeof(buffer))); 174 *err = CURLE_RECV_ERROR; 175 return -1; 176 } 177 178 rresult = rustls_connection_process_new_packets(backend->conn); 179 if(rresult != RUSTLS_RESULT_OK) { 180 rustls_failf(data, rresult, "rustls_connection_process_new_packets"); 181 *err = map_error(rresult); 182 return -1; 183 } 184 185 backend->data_in_pending = TRUE; 186 *err = CURLE_OK; 187 return (ssize_t)tls_bytes_read; 188 } 189 190 /* 191 * On each run: 192 * - Read a chunk of bytes from the socket into Rustls' TLS input buffer. 193 * - Tell Rustls to process any new packets. 194 * - Read out as many plaintext bytes from Rustls as possible, until hitting 195 * error, EOF, or EAGAIN/EWOULDBLOCK, or plainbuf/plainlen is filled up. 196 * 197 * it is okay to call this function with plainbuf == NULL and plainlen == 0. In 198 * that case, it will copy bytes from the socket into Rustls' TLS input 199 * buffer, and process packets, but will not consume bytes from Rustls' 200 * plaintext output buffer. 201 */ 202 static CURLcode 203 cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data, 204 char *plainbuf, size_t plainlen, size_t *pnread) 205 { 206 const struct ssl_connect_data *const connssl = cf->ctx; 207 struct rustls_ssl_backend_data *const backend = 208 (struct rustls_ssl_backend_data *)connssl->backend; 209 struct rustls_connection *rconn = NULL; 210 CURLcode result = CURLE_OK; 211 size_t n = 0; 212 rustls_result rresult = 0; 213 bool eof = FALSE; 214 215 DEBUGASSERT(backend); 216 *pnread = 0; 217 rconn = backend->conn; 218 219 while(*pnread < plainlen) { 220 if(!backend->data_in_pending) { 221 if(tls_recv_more(cf, data, &result) < 0) { 222 if(result != CURLE_AGAIN) { 223 goto out; 224 } 225 result = CURLE_OK; 226 break; 227 } 228 } 229 230 rresult = rustls_connection_read(rconn, 231 (uint8_t *)plainbuf + *pnread, 232 plainlen - *pnread, 233 &n); 234 if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) { 235 backend->data_in_pending = FALSE; 236 } 237 else if(rresult == RUSTLS_RESULT_UNEXPECTED_EOF) { 238 failf(data, "rustls: peer closed TCP connection " 239 "without first closing TLS connection"); 240 result = CURLE_RECV_ERROR; 241 goto out; 242 } 243 else if(rresult != RUSTLS_RESULT_OK) { 244 /* n always equals 0 in this case, do not need to check it */ 245 rustls_failf(data, rresult, "rustls_connection_read"); 246 result = CURLE_RECV_ERROR; 247 goto out; 248 } 249 else if(n == 0) { 250 /* n == 0 indicates clean EOF, but we may have read some other 251 plaintext bytes before we reached this. Break out of the loop 252 so we can figure out whether to return success or EOF. */ 253 eof = TRUE; 254 break; 255 } 256 else { 257 *pnread += n; 258 } 259 } 260 261 if(!eof && !*pnread) { 262 result = CURLE_AGAIN; 263 } 264 265 out: 266 CURL_TRC_CF(data, cf, "rustls_recv(len=%zu) -> %d, %zu", 267 plainlen, result, *pnread); 268 return result; 269 } 270 271 static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data, 272 struct rustls_connection *rconn) 273 { 274 struct io_ctx io_ctx; 275 rustls_io_result io_error; 276 size_t tlswritten = 0; 277 size_t tlswritten_total = 0; 278 279 io_ctx.cf = cf; 280 io_ctx.data = data; 281 282 while(rustls_connection_wants_write(rconn)) { 283 io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx, 284 &tlswritten); 285 if(io_error == EAGAIN || io_error == EWOULDBLOCK) { 286 CURL_TRC_CF(data, cf, "cf_send: EAGAIN after %zu bytes", 287 tlswritten_total); 288 return CURLE_AGAIN; 289 } 290 else if(io_error) { 291 char buffer[STRERROR_LEN]; 292 failf(data, "writing to socket: %s", 293 Curl_strerror(io_error, buffer, sizeof(buffer))); 294 return CURLE_SEND_ERROR; 295 } 296 if(tlswritten == 0) { 297 failf(data, "EOF in swrite"); 298 return CURLE_SEND_ERROR; 299 } 300 CURL_TRC_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten); 301 tlswritten_total += tlswritten; 302 } 303 return CURLE_OK; 304 } 305 306 /* 307 * On each call: 308 * - Copy `plainlen` bytes into Rustls' plaintext input buffer (if > 0). 309 * - Fully drain Rustls' plaintext output buffer into the socket until 310 * we get either an error or EAGAIN/EWOULDBLOCK. 311 * 312 * it is okay to call this function with plainbuf == NULL and plainlen == 0. 313 * In that case, it will not read anything into Rustls' plaintext input buffer. 314 * It will only drain Rustls' plaintext output buffer into the socket. 315 */ 316 static CURLcode 317 cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, 318 const void *plainbuf, size_t plainlen, size_t *pnwritten) 319 { 320 const struct ssl_connect_data *const connssl = cf->ctx; 321 struct rustls_ssl_backend_data *const backend = 322 (struct rustls_ssl_backend_data *)connssl->backend; 323 struct rustls_connection *rconn = NULL; 324 size_t plainwritten = 0; 325 const unsigned char *buf = plainbuf; 326 CURLcode result = CURLE_OK; 327 size_t blen = plainlen; 328 329 DEBUGASSERT(backend); 330 *pnwritten = 0; 331 rconn = backend->conn; 332 DEBUGASSERT(rconn); 333 334 CURL_TRC_CF(data, cf, "cf_send(len=%zu)", plainlen); 335 336 /* If a previous send blocked, we already added its plain bytes 337 * to rustsls and must not do that again. Flush the TLS bytes and, 338 * if successful, deduct the previous plain bytes from the current 339 * send. */ 340 if(backend->plain_out_buffered) { 341 result = cr_flush_out(cf, data, rconn); 342 CURL_TRC_CF(data, cf, "cf_send: flushing %zu previously added bytes -> %d", 343 backend->plain_out_buffered, result); 344 if(result) 345 return result; 346 if(blen > backend->plain_out_buffered) { 347 blen -= backend->plain_out_buffered; 348 buf += backend->plain_out_buffered; 349 } 350 else 351 blen = 0; 352 *pnwritten += (ssize_t)backend->plain_out_buffered; 353 backend->plain_out_buffered = 0; 354 } 355 356 if(blen > 0) { 357 rustls_result rresult; 358 CURL_TRC_CF(data, cf, "cf_send: adding %zu plain bytes to Rustls", blen); 359 rresult = rustls_connection_write(rconn, buf, blen, &plainwritten); 360 if(rresult != RUSTLS_RESULT_OK) { 361 rustls_failf(data, rresult, "rustls_connection_write"); 362 result = CURLE_WRITE_ERROR; 363 goto out; 364 } 365 else if(plainwritten == 0) { 366 failf(data, "rustls_connection_write: EOF"); 367 result = CURLE_WRITE_ERROR; 368 goto out; 369 } 370 } 371 372 result = cr_flush_out(cf, data, rconn); 373 if(result) { 374 if(CURLE_AGAIN == result) { 375 /* The TLS bytes may have been partially written, but we fail the 376 * complete send() and remember how much we already added to Rustls. */ 377 backend->plain_out_buffered = plainwritten; 378 if(*pnwritten) { 379 result = CURLE_OK; 380 } 381 } 382 goto out; 383 } 384 else 385 *pnwritten += (ssize_t)plainwritten; 386 387 out: 388 CURL_TRC_CF(data, cf, "rustls_send(len=%zu) -> %d, %zd", 389 plainlen, result, *pnwritten); 390 return result; 391 } 392 393 /* A server certificate verify callback for Rustls that always returns 394 RUSTLS_RESULT_OK, or in other words disable certificate verification. */ 395 static uint32_t 396 cr_verify_none(void *userdata UNUSED_PARAM, 397 const rustls_verify_server_cert_params *params UNUSED_PARAM) 398 { 399 return RUSTLS_RESULT_OK; 400 } 401 402 static int 403 read_file_into(const char *filename, 404 struct dynbuf *out) 405 { 406 FILE *f = fopen(filename, FOPEN_READTEXT); 407 if(!f) { 408 return 0; 409 } 410 411 while(!feof(f)) { 412 uint8_t buf[256]; 413 const size_t rr = fread(buf, 1, sizeof(buf), f); 414 if(rr == 0 || 415 CURLE_OK != curlx_dyn_addn(out, buf, rr)) { 416 fclose(f); 417 return 0; 418 } 419 } 420 421 return fclose(f) == 0; 422 } 423 424 static void 425 cr_get_selected_ciphers(struct Curl_easy *data, 426 const char *ciphers12, 427 const char *ciphers13, 428 const struct rustls_supported_ciphersuite **selected, 429 size_t *selected_size) 430 { 431 const size_t supported_len = *selected_size; 432 const size_t default_len = rustls_default_crypto_provider_ciphersuites_len(); 433 const struct rustls_supported_ciphersuite *entry; 434 const char *ciphers = ciphers12; 435 size_t count = 0, default13_count = 0, i, j; 436 const char *ptr, *end; 437 438 DEBUGASSERT(default_len <= supported_len); 439 440 if(!ciphers13) { 441 /* Add default TLSv1.3 ciphers to selection */ 442 for(j = 0; j < default_len; j++) { 443 entry = rustls_default_crypto_provider_ciphersuites_get(j); 444 if(rustls_supported_ciphersuite_protocol_version(entry) != 445 RUSTLS_TLS_VERSION_TLSV1_3) 446 continue; 447 448 selected[count++] = entry; 449 } 450 451 default13_count = count; 452 453 if(!ciphers) 454 ciphers = ""; 455 } 456 else 457 ciphers = ciphers13; 458 459 add_ciphers: 460 for(ptr = ciphers; ptr[0] != '\0' && count < supported_len; ptr = end) { 461 uint16_t id = Curl_cipher_suite_walk_str(&ptr, &end); 462 463 /* Check if cipher is supported */ 464 if(id) { 465 for(i = 0; i < supported_len; i++) { 466 entry = rustls_default_crypto_provider_ciphersuites_get(i); 467 if(rustls_supported_ciphersuite_get_suite(entry) == id) 468 break; 469 } 470 if(i == supported_len) 471 id = 0; 472 } 473 if(!id) { 474 if(ptr[0] != '\0') 475 infof(data, "rustls: unknown cipher in list: \"%.*s\"", 476 (int) (end - ptr), ptr); 477 continue; 478 } 479 480 /* No duplicates allowed (so selected cannot overflow) */ 481 for(i = 0; i < count && selected[i] != entry; i++); 482 if(i < count) { 483 if(i >= default13_count) 484 infof(data, "rustls: duplicate cipher in list: \"%.*s\"", 485 (int) (end - ptr), ptr); 486 continue; 487 } 488 489 selected[count++] = entry; 490 } 491 492 if(ciphers == ciphers13 && ciphers12) { 493 ciphers = ciphers12; 494 goto add_ciphers; 495 } 496 497 if(!ciphers12) { 498 /* Add default TLSv1.2 ciphers to selection */ 499 for(j = 0; j < default_len; j++) { 500 entry = rustls_default_crypto_provider_ciphersuites_get(j); 501 if(rustls_supported_ciphersuite_protocol_version(entry) == 502 RUSTLS_TLS_VERSION_TLSV1_3) 503 continue; 504 505 /* No duplicates allowed (so selected cannot overflow) */ 506 for(i = 0; i < count && selected[i] != entry; i++); 507 if(i < count) 508 continue; 509 510 selected[count++] = entry; 511 } 512 } 513 514 *selected_size = count; 515 } 516 517 static void 518 cr_keylog_log_cb(struct rustls_str label, 519 const uint8_t *client_random, size_t client_random_len, 520 const uint8_t *secret, size_t secret_len) 521 { 522 char clabel[KEYLOG_LABEL_MAXLEN]; 523 (void)client_random_len; 524 DEBUGASSERT(client_random_len == CLIENT_RANDOM_SIZE); 525 /* Turning a "rustls_str" into a null delimited "c" string */ 526 msnprintf(clabel, label.len + 1, "%.*s", (int)label.len, label.data); 527 Curl_tls_keylog_write(clabel, client_random, secret, secret_len); 528 } 529 530 static CURLcode 531 init_config_builder(struct Curl_easy *data, 532 const struct ssl_primary_config *conn_config, 533 struct rustls_client_config_builder **config_builder) 534 { 535 const struct rustls_supported_ciphersuite **cipher_suites = NULL; 536 struct rustls_crypto_provider_builder *custom_provider_builder = NULL; 537 const struct rustls_crypto_provider *custom_provider = NULL; 538 539 uint16_t tls_versions[2] = { 540 RUSTLS_TLS_VERSION_TLSV1_2, 541 RUSTLS_TLS_VERSION_TLSV1_3, 542 }; 543 size_t tls_versions_len = 2; 544 size_t cipher_suites_len = 545 rustls_default_crypto_provider_ciphersuites_len(); 546 547 CURLcode result = CURLE_OK; 548 rustls_result rr; 549 550 switch(conn_config->version) { 551 case CURL_SSLVERSION_DEFAULT: 552 case CURL_SSLVERSION_TLSv1: 553 case CURL_SSLVERSION_TLSv1_0: 554 case CURL_SSLVERSION_TLSv1_1: 555 case CURL_SSLVERSION_TLSv1_2: 556 break; 557 case CURL_SSLVERSION_TLSv1_3: 558 tls_versions[0] = RUSTLS_TLS_VERSION_TLSV1_3; 559 tls_versions_len = 1; 560 break; 561 default: 562 failf(data, "rustls: unsupported minimum TLS version value"); 563 result = CURLE_BAD_FUNCTION_ARGUMENT; 564 goto cleanup; 565 } 566 567 switch(conn_config->version_max) { 568 case CURL_SSLVERSION_MAX_DEFAULT: 569 case CURL_SSLVERSION_MAX_NONE: 570 case CURL_SSLVERSION_MAX_TLSv1_3: 571 break; 572 case CURL_SSLVERSION_MAX_TLSv1_2: 573 if(tls_versions[0] == RUSTLS_TLS_VERSION_TLSV1_2) { 574 tls_versions_len = 1; 575 break; 576 } 577 FALLTHROUGH(); 578 case CURL_SSLVERSION_MAX_TLSv1_1: 579 case CURL_SSLVERSION_MAX_TLSv1_0: 580 default: 581 failf(data, "rustls: unsupported maximum TLS version value"); 582 result = CURLE_BAD_FUNCTION_ARGUMENT; 583 goto cleanup; 584 } 585 586 #if defined(USE_ECH) 587 if(ECH_ENABLED(data)) { 588 tls_versions[0] = RUSTLS_TLS_VERSION_TLSV1_3; 589 tls_versions_len = 1; 590 infof(data, "rustls: ECH enabled, forcing TLSv1.3"); 591 } 592 #endif /* USE_ECH */ 593 594 cipher_suites = malloc(sizeof(cipher_suites) * (cipher_suites_len)); 595 if(!cipher_suites) { 596 result = CURLE_OUT_OF_MEMORY; 597 goto cleanup; 598 } 599 600 cr_get_selected_ciphers(data, 601 conn_config->cipher_list, 602 conn_config->cipher_list13, 603 cipher_suites, &cipher_suites_len); 604 if(cipher_suites_len == 0) { 605 failf(data, "rustls: no supported cipher in list"); 606 result = CURLE_SSL_CIPHER; 607 goto cleanup; 608 } 609 610 rr = rustls_crypto_provider_builder_new_from_default( 611 &custom_provider_builder); 612 if(rr != RUSTLS_RESULT_OK) { 613 rustls_failf(data, rr, 614 "failed to create crypto provider builder from default"); 615 result = CURLE_SSL_CIPHER; 616 goto cleanup; 617 } 618 619 rr = 620 rustls_crypto_provider_builder_set_cipher_suites( 621 custom_provider_builder, 622 cipher_suites, 623 cipher_suites_len); 624 if(rr != RUSTLS_RESULT_OK) { 625 rustls_failf(data, rr, 626 "failed to set ciphersuites for crypto provider builder"); 627 result = CURLE_SSL_CIPHER; 628 goto cleanup; 629 } 630 631 rr = rustls_crypto_provider_builder_build( 632 custom_provider_builder, &custom_provider); 633 if(rr != RUSTLS_RESULT_OK) { 634 rustls_failf(data, rr, "failed to build custom crypto provider"); 635 result = CURLE_SSL_CIPHER; 636 goto cleanup; 637 } 638 639 rr = rustls_client_config_builder_new_custom(custom_provider, 640 tls_versions, 641 tls_versions_len, 642 config_builder); 643 if(rr != RUSTLS_RESULT_OK) { 644 rustls_failf(data, rr, "failed to create client config builder"); 645 result = CURLE_SSL_CIPHER; 646 goto cleanup; 647 } 648 649 cleanup: 650 if(cipher_suites) { 651 free(cipher_suites); 652 } 653 if(custom_provider_builder) { 654 rustls_crypto_provider_builder_free(custom_provider_builder); 655 } 656 if(custom_provider) { 657 rustls_crypto_provider_free(custom_provider); 658 } 659 return result; 660 } 661 662 static void 663 init_config_builder_alpn(struct Curl_easy *data, 664 const struct ssl_connect_data *connssl, 665 struct rustls_client_config_builder *config_builder) { 666 struct alpn_proto_buf proto; 667 rustls_slice_bytes alpn[ALPN_ENTRIES_MAX]; 668 size_t i; 669 670 for(i = 0; i < connssl->alpn->count; ++i) { 671 alpn[i].data = (const uint8_t *)connssl->alpn->entries[i]; 672 alpn[i].len = strlen(connssl->alpn->entries[i]); 673 } 674 rustls_client_config_builder_set_alpn_protocols(config_builder, alpn, 675 connssl->alpn->count); 676 Curl_alpn_to_proto_str(&proto, connssl->alpn); 677 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); 678 } 679 680 static CURLcode 681 init_config_builder_verifier_crl( 682 struct Curl_easy *data, 683 const struct ssl_primary_config *conn_config, 684 struct rustls_web_pki_server_cert_verifier_builder *builder) 685 { 686 CURLcode result = CURLE_OK; 687 struct dynbuf crl_contents; 688 rustls_result rr; 689 690 curlx_dyn_init(&crl_contents, DYN_CRLFILE_SIZE); 691 if(!read_file_into(conn_config->CRLfile, &crl_contents)) { 692 failf(data, "rustls: failed to read revocation list file"); 693 result = CURLE_SSL_CRL_BADFILE; 694 goto cleanup; 695 } 696 697 rr = rustls_web_pki_server_cert_verifier_builder_add_crl( 698 builder, 699 curlx_dyn_uptr(&crl_contents), 700 curlx_dyn_len(&crl_contents)); 701 if(rr != RUSTLS_RESULT_OK) { 702 rustls_failf(data, rr, "failed to parse revocation list"); 703 result = CURLE_SSL_CRL_BADFILE; 704 goto cleanup; 705 } 706 707 cleanup: 708 curlx_dyn_free(&crl_contents); 709 return result; 710 } 711 712 static CURLcode 713 init_config_builder_verifier(struct Curl_easy *data, 714 struct rustls_client_config_builder *builder, 715 const struct ssl_primary_config *conn_config, 716 const struct curl_blob *ca_info_blob, 717 const char * const ssl_cafile) { 718 const struct rustls_root_cert_store *roots = NULL; 719 struct rustls_root_cert_store_builder *roots_builder = NULL; 720 struct rustls_web_pki_server_cert_verifier_builder *verifier_builder = NULL; 721 struct rustls_server_cert_verifier *server_cert_verifier = NULL; 722 rustls_result rr = RUSTLS_RESULT_OK; 723 CURLcode result = CURLE_OK; 724 725 roots_builder = rustls_root_cert_store_builder_new(); 726 if(ca_info_blob) { 727 rr = rustls_root_cert_store_builder_add_pem(roots_builder, 728 ca_info_blob->data, 729 ca_info_blob->len, 730 1); 731 if(rr != RUSTLS_RESULT_OK) { 732 rustls_failf(data, rr, "failed to parse trusted certificates from blob"); 733 734 result = CURLE_SSL_CACERT_BADFILE; 735 goto cleanup; 736 } 737 } 738 else if(ssl_cafile) { 739 rr = rustls_root_cert_store_builder_load_roots_from_file(roots_builder, 740 ssl_cafile, 741 1); 742 if(rr != RUSTLS_RESULT_OK) { 743 rustls_failf(data, rr, "failed to load trusted certificates"); 744 745 result = CURLE_SSL_CACERT_BADFILE; 746 goto cleanup; 747 } 748 } 749 750 rr = rustls_root_cert_store_builder_build(roots_builder, &roots); 751 if(rr != RUSTLS_RESULT_OK) { 752 rustls_failf(data, rr, "failed to build trusted root certificate store"); 753 result = CURLE_SSL_CACERT_BADFILE; 754 } 755 756 verifier_builder = rustls_web_pki_server_cert_verifier_builder_new(roots); 757 758 if(conn_config->CRLfile) { 759 result = init_config_builder_verifier_crl(data, 760 conn_config, 761 verifier_builder); 762 if(result != CURLE_OK) { 763 goto cleanup; 764 } 765 } 766 767 rr = rustls_web_pki_server_cert_verifier_builder_build( 768 verifier_builder, &server_cert_verifier); 769 if(rr != RUSTLS_RESULT_OK) { 770 rustls_failf(data, rr, "failed to build certificate verifier"); 771 result = CURLE_SSL_CACERT_BADFILE; 772 goto cleanup; 773 } 774 775 rustls_client_config_builder_set_server_verifier(builder, 776 server_cert_verifier); 777 cleanup: 778 if(roots_builder) { 779 rustls_root_cert_store_builder_free(roots_builder); 780 } 781 if(roots) { 782 rustls_root_cert_store_free(roots); 783 } 784 if(verifier_builder) { 785 rustls_web_pki_server_cert_verifier_builder_free(verifier_builder); 786 } 787 if(server_cert_verifier) { 788 rustls_server_cert_verifier_free(server_cert_verifier); 789 } 790 791 return result; 792 } 793 794 static CURLcode 795 init_config_builder_platform_verifier( 796 struct Curl_easy *data, 797 struct rustls_client_config_builder *builder) 798 { 799 struct rustls_server_cert_verifier *server_cert_verifier = NULL; 800 CURLcode result = CURLE_OK; 801 rustls_result rr; 802 803 rr = rustls_platform_server_cert_verifier(&server_cert_verifier); 804 if(rr != RUSTLS_RESULT_OK) { 805 rustls_failf(data, rr, "failed to create platform certificate verifier"); 806 result = CURLE_SSL_CACERT_BADFILE; 807 goto cleanup; 808 } 809 810 rustls_client_config_builder_set_server_verifier(builder, 811 server_cert_verifier); 812 813 cleanup: 814 if(server_cert_verifier) { 815 rustls_server_cert_verifier_free(server_cert_verifier); 816 } 817 return result; 818 } 819 820 static CURLcode 821 init_config_builder_keylog(struct Curl_easy *data, 822 struct rustls_client_config_builder *builder) 823 { 824 rustls_result rr; 825 826 Curl_tls_keylog_open(); 827 if(!Curl_tls_keylog_enabled()) { 828 return CURLE_OK; 829 } 830 831 rr = rustls_client_config_builder_set_key_log(builder, 832 cr_keylog_log_cb, 833 NULL); 834 if(rr != RUSTLS_RESULT_OK) { 835 rustls_failf(data, rr, "rustls_client_config_builder_set_key_log"); 836 Curl_tls_keylog_close(); 837 return map_error(rr); 838 } 839 840 return CURLE_OK; 841 } 842 843 static CURLcode 844 init_config_builder_client_auth(struct Curl_easy *data, 845 const struct ssl_primary_config *conn_config, 846 const struct ssl_config_data *ssl_config, 847 struct rustls_client_config_builder *builder) 848 { 849 struct dynbuf cert_contents; 850 struct dynbuf key_contents; 851 rustls_result rr; 852 const struct rustls_certified_key *certified_key = NULL; 853 CURLcode result = CURLE_OK; 854 855 if(conn_config->clientcert && !ssl_config->key) { 856 failf(data, "rustls: must provide key with certificate '%s'", 857 conn_config->clientcert); 858 return CURLE_SSL_CERTPROBLEM; 859 } 860 else if(!conn_config->clientcert && ssl_config->key) { 861 failf(data, "rustls: must provide certificate with key '%s'", 862 ssl_config->key); 863 return CURLE_SSL_CERTPROBLEM; 864 } 865 866 curlx_dyn_init(&cert_contents, DYN_CERTFILE_SIZE); 867 curlx_dyn_init(&key_contents, DYN_KEYFILE_SIZE); 868 869 if(!read_file_into(conn_config->clientcert, &cert_contents)) { 870 failf(data, "rustls: failed to read client certificate file: '%s'", 871 conn_config->clientcert); 872 result = CURLE_SSL_CERTPROBLEM; 873 goto cleanup; 874 } 875 876 if(!read_file_into(ssl_config->key, &key_contents)) { 877 failf(data, "rustls: failed to read key file: '%s'", ssl_config->key); 878 result = CURLE_SSL_CERTPROBLEM; 879 goto cleanup; 880 } 881 882 rr = rustls_certified_key_build(curlx_dyn_uptr(&cert_contents), 883 curlx_dyn_len(&cert_contents), 884 curlx_dyn_uptr(&key_contents), 885 curlx_dyn_len(&key_contents), 886 &certified_key); 887 if(rr != RUSTLS_RESULT_OK) { 888 rustls_failf(data, rr, "rustls: failed to build certified key"); 889 result = CURLE_SSL_CERTPROBLEM; 890 goto cleanup; 891 } 892 893 rr = rustls_certified_key_keys_match(certified_key); 894 if(rr != RUSTLS_RESULT_OK) { 895 rustls_failf(data, 896 rr, 897 "rustls: client certificate and keypair files do not match:"); 898 899 result = CURLE_SSL_CERTPROBLEM; 900 goto cleanup; 901 } 902 903 rr = rustls_client_config_builder_set_certified_key(builder, 904 &certified_key, 905 1); 906 if(rr != RUSTLS_RESULT_OK) { 907 rustls_failf(data, rr, "rustls: failed to set certified key"); 908 result = CURLE_SSL_CERTPROBLEM; 909 goto cleanup; 910 } 911 912 cleanup: 913 curlx_dyn_free(&cert_contents); 914 curlx_dyn_free(&key_contents); 915 if(certified_key) { 916 rustls_certified_key_free(certified_key); 917 } 918 return result; 919 } 920 921 #if defined(USE_ECH) 922 static CURLcode 923 init_config_builder_ech(struct Curl_easy *data, 924 const struct ssl_connect_data *connssl, 925 struct rustls_client_config_builder *builder) 926 { 927 const rustls_hpke *hpke = rustls_supported_hpke(); 928 unsigned char *ech_config = NULL; 929 size_t ech_config_len = 0; 930 struct Curl_dns_entry *dns = NULL; 931 struct Curl_https_rrinfo *rinfo = NULL; 932 CURLcode result = CURLE_OK; 933 rustls_result rr; 934 935 if(!hpke) { 936 failf(data, 937 "rustls: ECH unavailable, rustls-ffi built without " 938 "HPKE compatible crypto provider"); 939 result = CURLE_SSL_CONNECT_ERROR; 940 goto cleanup; 941 } 942 943 if(data->set.str[STRING_ECH_PUBLIC]) { 944 failf(data, "rustls: ECH outername not supported"); 945 result = CURLE_SSL_CONNECT_ERROR; 946 goto cleanup; 947 } 948 949 if(data->set.tls_ech == CURLECH_GREASE) { 950 rr = rustls_client_config_builder_enable_ech_grease(builder, hpke); 951 if(rr != RUSTLS_RESULT_OK) { 952 rustls_failf(data, rr, "rustls: failed to configure ECH GREASE"); 953 result = CURLE_SSL_CONNECT_ERROR; 954 goto cleanup; 955 } 956 return CURLE_OK; 957 } 958 959 if(data->set.tls_ech & CURLECH_CLA_CFG && data->set.str[STRING_ECH_CONFIG]) { 960 const char *b64 = data->set.str[STRING_ECH_CONFIG]; 961 size_t decode_result; 962 if(!b64) { 963 infof(data, "rustls: ECHConfig from command line empty"); 964 result = CURLE_SSL_CONNECT_ERROR; 965 goto cleanup; 966 } 967 /* rustls-ffi expects the raw TLS encoded ECHConfigList bytes */ 968 decode_result = curlx_base64_decode(b64, &ech_config, &ech_config_len); 969 if(decode_result || !ech_config) { 970 infof(data, "rustls: cannot base64 decode ECHConfig from command line"); 971 result = CURLE_SSL_CONNECT_ERROR; 972 goto cleanup; 973 } 974 } 975 else { 976 if(connssl->peer.hostname) { 977 dns = Curl_dnscache_get(data, connssl->peer.hostname, 978 connssl->peer.port, data->conn->ip_version); 979 } 980 if(!dns) { 981 failf(data, "rustls: ECH requested but no DNS info available"); 982 result = CURLE_SSL_CONNECT_ERROR; 983 goto cleanup; 984 } 985 rinfo = dns->hinfo; 986 if(!rinfo || !rinfo->echconfiglist) { 987 failf(data, "rustls: ECH requested but no ECHConfig available"); 988 result = CURLE_SSL_CONNECT_ERROR; 989 goto cleanup; 990 } 991 ech_config = rinfo->echconfiglist; 992 ech_config_len = rinfo->echconfiglist_len; 993 } 994 995 rr = rustls_client_config_builder_enable_ech(builder, 996 ech_config, 997 ech_config_len, 998 hpke); 999 if(rr != RUSTLS_RESULT_OK) { 1000 rustls_failf(data, rr, "rustls: failed to configure ECH"); 1001 result = CURLE_SSL_CONNECT_ERROR; 1002 goto cleanup; 1003 } 1004 cleanup: 1005 /* if we base64 decoded, we can free now */ 1006 if(data->set.tls_ech & CURLECH_CLA_CFG && data->set.str[STRING_ECH_CONFIG]) { 1007 free(ech_config); 1008 } 1009 if(dns) { 1010 Curl_resolv_unlink(data, &dns); 1011 } 1012 return result; 1013 } 1014 #endif /* USE_ECH */ 1015 1016 static CURLcode 1017 cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, 1018 struct rustls_ssl_backend_data *const backend) 1019 { 1020 const struct ssl_connect_data *connssl = cf->ctx; 1021 const struct ssl_primary_config *conn_config = 1022 Curl_ssl_cf_get_primary_config(cf); 1023 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); 1024 struct rustls_connection *rconn = NULL; 1025 struct rustls_client_config_builder *config_builder = NULL; 1026 1027 const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; 1028 const char * const ssl_cafile = 1029 /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ 1030 (ca_info_blob ? NULL : conn_config->CAfile); 1031 CURLcode result = CURLE_OK; 1032 rustls_result rr; 1033 1034 DEBUGASSERT(backend); 1035 rconn = backend->conn; 1036 1037 result = init_config_builder(data, conn_config, &config_builder); 1038 if(result != CURLE_OK) { 1039 return result; 1040 } 1041 1042 if(connssl->alpn) { 1043 init_config_builder_alpn(data, connssl, config_builder); 1044 } 1045 1046 if(!conn_config->verifypeer) { 1047 rustls_client_config_builder_dangerous_set_certificate_verifier( 1048 config_builder, cr_verify_none); 1049 } 1050 else if(ssl_config->native_ca_store) { 1051 result = init_config_builder_platform_verifier(data, config_builder); 1052 if(result != CURLE_OK) { 1053 rustls_client_config_builder_free(config_builder); 1054 return result; 1055 } 1056 } 1057 else if(ca_info_blob || ssl_cafile) { 1058 result = init_config_builder_verifier(data, 1059 config_builder, 1060 conn_config, 1061 ca_info_blob, 1062 ssl_cafile); 1063 if(result != CURLE_OK) { 1064 rustls_client_config_builder_free(config_builder); 1065 return result; 1066 } 1067 } 1068 1069 if(conn_config->clientcert || ssl_config->key) { 1070 result = init_config_builder_client_auth(data, 1071 conn_config, 1072 ssl_config, 1073 config_builder); 1074 if(result != CURLE_OK) { 1075 rustls_client_config_builder_free(config_builder); 1076 return result; 1077 } 1078 } 1079 1080 #if defined(USE_ECH) 1081 if(ECH_ENABLED(data)) { 1082 result = init_config_builder_ech(data, connssl, config_builder); 1083 if(result != CURLE_OK && data->set.tls_ech & CURLECH_HARD) { 1084 rustls_client_config_builder_free(config_builder); 1085 return result; 1086 } 1087 } 1088 #endif /* USE_ECH */ 1089 1090 result = init_config_builder_keylog(data, config_builder); 1091 if(result != CURLE_OK) { 1092 rustls_client_config_builder_free(config_builder); 1093 return result; 1094 } 1095 1096 rr = rustls_client_config_builder_build( 1097 config_builder, 1098 &backend->config); 1099 if(rr != RUSTLS_RESULT_OK) { 1100 rustls_failf(data, rr, "failed to build client config"); 1101 rustls_client_config_builder_free(config_builder); 1102 rustls_client_config_free(backend->config); 1103 return CURLE_SSL_CONNECT_ERROR; 1104 } 1105 1106 DEBUGASSERT(rconn == NULL); 1107 rr = rustls_client_connection_new(backend->config, 1108 connssl->peer.hostname, 1109 &rconn); 1110 if(rr != RUSTLS_RESULT_OK) { 1111 rustls_failf(data, result, "rustls_client_connection_new"); 1112 return CURLE_COULDNT_CONNECT; 1113 } 1114 DEBUGASSERT(rconn); 1115 rustls_connection_set_userdata(rconn, backend); 1116 backend->conn = rconn; 1117 1118 return result; 1119 } 1120 1121 static void 1122 cr_set_negotiated_alpn(struct Curl_cfilter *cf, struct Curl_easy *data, 1123 const struct rustls_connection *rconn) 1124 { 1125 struct ssl_connect_data *const connssl = cf->ctx; 1126 const uint8_t *protocol = NULL; 1127 size_t len = 0; 1128 1129 rustls_connection_get_alpn_protocol(rconn, &protocol, &len); 1130 Curl_alpn_set_negotiated(cf, data, connssl, protocol, len); 1131 } 1132 1133 /* Given an established network connection, do a TLS handshake. 1134 * 1135 * This function will set `*done` to true once the handshake is complete. 1136 * This function never reads the value of `*done*`. 1137 */ 1138 static CURLcode 1139 cr_connect(struct Curl_cfilter *cf, 1140 struct Curl_easy *data, bool *done) 1141 { 1142 struct ssl_connect_data *const connssl = cf->ctx; 1143 const struct rustls_ssl_backend_data *const backend = 1144 (struct rustls_ssl_backend_data *)connssl->backend; 1145 const struct rustls_connection *rconn = NULL; 1146 CURLcode tmperr = CURLE_OK; 1147 int result; 1148 bool wants_read; 1149 bool wants_write; 1150 1151 DEBUGASSERT(backend); 1152 1153 CURL_TRC_CF(data, cf, "cr_connect, state=%d", connssl->state); 1154 *done = FALSE; 1155 1156 if(!backend->conn) { 1157 result = cr_init_backend(cf, data, 1158 (struct rustls_ssl_backend_data *)connssl->backend); 1159 CURL_TRC_CF(data, cf, "cr_connect, init backend -> %d", result); 1160 if(result != CURLE_OK) { 1161 return result; 1162 } 1163 connssl->state = ssl_connection_negotiating; 1164 } 1165 rconn = backend->conn; 1166 1167 /* Read/write data until the handshake is done or the socket would block. */ 1168 for(;;) { 1169 /* 1170 * Connection has been established according to Rustls. Set send/recv 1171 * handlers, and update the state machine. 1172 */ 1173 connssl->io_need = CURL_SSL_IO_NEED_NONE; 1174 if(!rustls_connection_is_handshaking(rconn)) { 1175 /* Rustls claims it is no longer handshaking *before* it has 1176 * send its FINISHED message off. We attempt to let it write 1177 * one more time. Oh my. 1178 */ 1179 size_t nwritten; 1180 cr_set_negotiated_alpn(cf, data, rconn); 1181 tmperr = cr_send(cf, data, NULL, 0, &nwritten); 1182 if(tmperr == CURLE_AGAIN) { 1183 connssl->io_need = CURL_SSL_IO_NEED_SEND; 1184 return CURLE_OK; 1185 } 1186 else if(tmperr != CURLE_OK) { 1187 return tmperr; 1188 } 1189 /* REALLY Done with the handshake. */ 1190 { 1191 const uint16_t proto = 1192 rustls_connection_get_protocol_version(rconn); 1193 const rustls_str ciphersuite_name = 1194 rustls_connection_get_negotiated_ciphersuite_name(rconn); 1195 const rustls_str kex_group_name = 1196 rustls_connection_get_negotiated_key_exchange_group_name(rconn); 1197 const char *ver = "TLS version unknown"; 1198 if(proto == RUSTLS_TLS_VERSION_TLSV1_3) 1199 ver = "TLSv1.3"; 1200 if(proto == RUSTLS_TLS_VERSION_TLSV1_2) 1201 ver = "TLSv1.2"; 1202 infof(data, 1203 "rustls: handshake complete, %s, ciphersuite: %.*s, " 1204 "key exchange group: %.*s", 1205 ver, 1206 (int) ciphersuite_name.len, 1207 ciphersuite_name.data, 1208 (int) kex_group_name.len, 1209 kex_group_name.data); 1210 } 1211 if(data->set.ssl.certinfo) { 1212 size_t num_certs = 0; 1213 while(rustls_connection_get_peer_certificate(rconn, (int)num_certs)) { 1214 num_certs++; 1215 } 1216 result = Curl_ssl_init_certinfo(data, (int)num_certs); 1217 if(result) 1218 return result; 1219 for(size_t i = 0; i < num_certs; i++) { 1220 const rustls_certificate *cert; 1221 const unsigned char *der_data; 1222 size_t der_len; 1223 rustls_result rresult = RUSTLS_RESULT_OK; 1224 cert = rustls_connection_get_peer_certificate(rconn, i); 1225 DEBUGASSERT(cert); /* Should exist since we counted already */ 1226 rresult = rustls_certificate_get_der(cert, &der_data, &der_len); 1227 if(rresult != RUSTLS_RESULT_OK) { 1228 char errorbuf[255]; 1229 size_t errorlen; 1230 rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen); 1231 failf(data, 1232 "Failed getting DER of server certificate #%ld: %.*s", i, 1233 (int)errorlen, errorbuf); 1234 return map_error(rresult); 1235 } 1236 { 1237 const char *beg; 1238 const char *end; 1239 beg = (const char *)der_data; 1240 end = (const char *)(der_data + der_len); 1241 result = Curl_extract_certinfo(data, (int)i, beg, end); 1242 if(result) 1243 return result; 1244 } 1245 } 1246 } 1247 1248 connssl->state = ssl_connection_complete; 1249 *done = TRUE; 1250 return CURLE_OK; 1251 } 1252 1253 connssl->connecting_state = ssl_connect_2; 1254 wants_read = rustls_connection_wants_read(rconn); 1255 wants_write = rustls_connection_wants_write(rconn) || 1256 backend->plain_out_buffered; 1257 DEBUGASSERT(wants_read || wants_write); 1258 1259 if(wants_write) { 1260 size_t nwritten; 1261 CURL_TRC_CF(data, cf, "rustls_connection wants us to write_tls."); 1262 tmperr = cr_send(cf, data, NULL, 0, &nwritten); 1263 if(tmperr == CURLE_AGAIN) { 1264 CURL_TRC_CF(data, cf, "writing would block"); 1265 connssl->io_need = CURL_SSL_IO_NEED_SEND; 1266 return CURLE_OK; 1267 } 1268 else if(tmperr != CURLE_OK) { 1269 return tmperr; 1270 } 1271 } 1272 1273 if(wants_read) { 1274 CURL_TRC_CF(data, cf, "rustls_connection wants us to read_tls."); 1275 if(tls_recv_more(cf, data, &tmperr) < 0) { 1276 if(tmperr == CURLE_AGAIN) { 1277 CURL_TRC_CF(data, cf, "reading would block"); 1278 connssl->io_need = CURL_SSL_IO_NEED_RECV; 1279 return CURLE_OK; 1280 } 1281 else if(tmperr == CURLE_RECV_ERROR) { 1282 return CURLE_SSL_CONNECT_ERROR; 1283 } 1284 else { 1285 return tmperr; 1286 } 1287 } 1288 } 1289 } 1290 1291 /* We should never fall through the loop. We should return either because 1292 the handshake is done or because we cannot read/write without blocking. */ 1293 DEBUGASSERT(FALSE); 1294 } 1295 1296 static void * 1297 cr_get_internals(struct ssl_connect_data *connssl, 1298 CURLINFO info UNUSED_PARAM) 1299 { 1300 struct rustls_ssl_backend_data *backend = 1301 (struct rustls_ssl_backend_data *)connssl->backend; 1302 DEBUGASSERT(backend); 1303 return &backend->conn; 1304 } 1305 1306 static CURLcode 1307 cr_shutdown(struct Curl_cfilter *cf, 1308 struct Curl_easy *data, 1309 const bool send_shutdown, bool *done) 1310 { 1311 struct ssl_connect_data *connssl = cf->ctx; 1312 struct rustls_ssl_backend_data *backend = 1313 (struct rustls_ssl_backend_data *)connssl->backend; 1314 CURLcode result = CURLE_OK; 1315 size_t i, nread, nwritten; 1316 1317 DEBUGASSERT(backend); 1318 if(!backend->conn || cf->shutdown) { 1319 *done = TRUE; 1320 goto out; 1321 } 1322 1323 connssl->io_need = CURL_SSL_IO_NEED_NONE; 1324 *done = FALSE; 1325 1326 if(!backend->sent_shutdown) { 1327 /* do this only once */ 1328 backend->sent_shutdown = TRUE; 1329 if(send_shutdown) { 1330 rustls_connection_send_close_notify(backend->conn); 1331 } 1332 } 1333 1334 result = cr_send(cf, data, NULL, 0, &nwritten); 1335 if(result) { 1336 if(result == CURLE_AGAIN) { 1337 connssl->io_need = CURL_SSL_IO_NEED_SEND; 1338 result = CURLE_OK; 1339 goto out; 1340 } 1341 DEBUGASSERT(result); 1342 CURL_TRC_CF(data, cf, "shutdown send failed: %d", result); 1343 goto out; 1344 } 1345 1346 for(i = 0; i < 10; ++i) { 1347 char buf[1024]; 1348 result = cr_recv(cf, data, buf, (int)sizeof(buf), &nread); 1349 if(result) 1350 break; 1351 } 1352 1353 if(result == CURLE_AGAIN) { 1354 connssl->io_need = CURL_SSL_IO_NEED_RECV; 1355 result = CURLE_OK; 1356 } 1357 else if(result) { 1358 DEBUGASSERT(result); 1359 CURL_TRC_CF(data, cf, "shutdown, error: %d", result); 1360 } 1361 else if(nread == 0) { 1362 /* We got the close notify alert and are done. */ 1363 *done = TRUE; 1364 } 1365 1366 out: 1367 cf->shutdown = (result || *done); 1368 return result; 1369 } 1370 1371 static void 1372 cr_close(struct Curl_cfilter *cf, struct Curl_easy *data) 1373 { 1374 const struct ssl_connect_data *connssl = cf->ctx; 1375 struct rustls_ssl_backend_data *backend = 1376 (struct rustls_ssl_backend_data *)connssl->backend; 1377 1378 (void)data; 1379 DEBUGASSERT(backend); 1380 if(backend->conn) { 1381 rustls_connection_free(backend->conn); 1382 backend->conn = NULL; 1383 } 1384 if(backend->config) { 1385 rustls_client_config_free(backend->config); 1386 backend->config = NULL; 1387 } 1388 } 1389 1390 static size_t cr_version(char *buffer, size_t size) 1391 { 1392 const struct rustls_str ver = rustls_version(); 1393 return msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data); 1394 } 1395 1396 static CURLcode 1397 cr_random(struct Curl_easy *data, unsigned char *entropy, size_t length) 1398 { 1399 rustls_result rresult = 0; 1400 (void)data; 1401 rresult = 1402 rustls_default_crypto_provider_random(entropy, length); 1403 return map_error(rresult); 1404 } 1405 1406 static void cr_cleanup(void) 1407 { 1408 Curl_tls_keylog_close(); 1409 } 1410 1411 const struct Curl_ssl Curl_ssl_rustls = { 1412 { CURLSSLBACKEND_RUSTLS, "rustls" }, 1413 SSLSUPP_CAINFO_BLOB | /* supports */ 1414 SSLSUPP_HTTPS_PROXY | 1415 SSLSUPP_CIPHER_LIST | 1416 SSLSUPP_TLS13_CIPHERSUITES | 1417 SSLSUPP_CERTINFO | 1418 SSLSUPP_ECH, 1419 sizeof(struct rustls_ssl_backend_data), 1420 1421 NULL, /* init */ 1422 cr_cleanup, /* cleanup */ 1423 cr_version, /* version */ 1424 cr_shutdown, /* shutdown */ 1425 cr_data_pending, /* data_pending */ 1426 cr_random, /* random */ 1427 NULL, /* cert_status_request */ 1428 cr_connect, /* connect */ 1429 Curl_ssl_adjust_pollset, /* adjust_pollset */ 1430 cr_get_internals, /* get_internals */ 1431 cr_close, /* close_one */ 1432 NULL, /* close_all */ 1433 NULL, /* set_engine */ 1434 NULL, /* set_engine_default */ 1435 NULL, /* engines_list */ 1436 NULL, /* sha256sum */ 1437 cr_recv, /* recv decrypted data */ 1438 cr_send, /* send data to encrypt */ 1439 NULL, /* get_channel_binding */ 1440 }; 1441 1442 #endif /* USE_RUSTLS */