quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

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 */