xref: /curl/lib/vtls/rustls.c (revision 3a35901a)
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  *
12  * This software is licensed as described in the file COPYING, which
13  * you should have received as part of this distribution. The terms
14  * are also available at https://curl.se/docs/copyright.html.
15  *
16  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
17  * copies of the Software, and permit persons to whom the Software is
18  * furnished to do so, under the terms of the COPYING file.
19  *
20  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21  * KIND, either express or implied.
22  *
23  * SPDX-License-Identifier: curl
24  *
25  ***************************************************************************/
26 #include "curl_setup.h"
27 
28 #ifdef USE_RUSTLS
29 
30 #include "curl_printf.h"
31 
32 #include <errno.h>
33 #include <rustls.h>
34 
35 #include "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 "select.h"
42 #include "strerror.h"
43 #include "multiif.h"
44 #include "connect.h" /* for the connect timeout */
45 #include "cipher_suite.h"
46 #include "rand.h"
47 
48 struct rustls_ssl_backend_data
49 {
50   const struct rustls_client_config *config;
51   struct rustls_connection *conn;
52   size_t plain_out_buffered;
53   BIT(data_in_pending);
54   BIT(sent_shutdown);
55 };
56 
57 /* For a given rustls_result error code, return the best-matching CURLcode. */
map_error(rustls_result r)58 static CURLcode map_error(rustls_result r)
59 {
60   if(rustls_result_is_cert_error(r)) {
61     return CURLE_PEER_FAILED_VERIFICATION;
62   }
63   switch(r) {
64     case RUSTLS_RESULT_OK:
65       return CURLE_OK;
66     case RUSTLS_RESULT_NULL_PARAMETER:
67       return CURLE_BAD_FUNCTION_ARGUMENT;
68     default:
69       return CURLE_RECV_ERROR;
70   }
71 }
72 
73 static bool
cr_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)74 cr_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data)
75 {
76   struct ssl_connect_data *ctx = cf->ctx;
77   struct rustls_ssl_backend_data *backend;
78 
79   (void)data;
80   DEBUGASSERT(ctx && ctx->backend);
81   backend = (struct rustls_ssl_backend_data *)ctx->backend;
82   return backend->data_in_pending;
83 }
84 
85 struct io_ctx {
86   struct Curl_cfilter *cf;
87   struct Curl_easy *data;
88 };
89 
90 static int
read_cb(void * userdata,uint8_t * buf,uintptr_t len,uintptr_t * out_n)91 read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
92 {
93   struct io_ctx *io_ctx = userdata;
94   struct ssl_connect_data *const connssl = io_ctx->cf->ctx;
95   CURLcode result;
96   int ret = 0;
97   ssize_t nread = Curl_conn_cf_recv(io_ctx->cf->next, io_ctx->data,
98                                     (char *)buf, len, &result);
99   if(nread < 0) {
100     nread = 0;
101     if(CURLE_AGAIN == result)
102       ret = EAGAIN;
103     else
104       ret = EINVAL;
105   }
106   else if(nread == 0)
107     connssl->peer_closed = TRUE;
108   *out_n = (uintptr_t)nread;
109   CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %zd, %d",
110               len, nread, result);
111   return ret;
112 }
113 
114 static int
write_cb(void * userdata,const uint8_t * buf,uintptr_t len,uintptr_t * out_n)115 write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
116 {
117   struct io_ctx *io_ctx = userdata;
118   CURLcode result;
119   int ret = 0;
120   ssize_t nwritten = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data,
121                                        (const char *)buf, len, FALSE,
122                                        &result);
123   if(nwritten < 0) {
124     nwritten = 0;
125     if(CURLE_AGAIN == result)
126       ret = EAGAIN;
127     else
128       ret = EINVAL;
129   }
130   *out_n = (uintptr_t)nwritten;
131   CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d",
132               len, nwritten, result);
133   return ret;
134 }
135 
tls_recv_more(struct Curl_cfilter * cf,struct Curl_easy * data,CURLcode * err)136 static ssize_t tls_recv_more(struct Curl_cfilter *cf,
137                              struct Curl_easy *data, CURLcode *err)
138 {
139   struct ssl_connect_data *const connssl = cf->ctx;
140   struct rustls_ssl_backend_data *const backend =
141     (struct rustls_ssl_backend_data *)connssl->backend;
142   struct io_ctx io_ctx;
143   size_t tls_bytes_read = 0;
144   rustls_io_result io_error;
145   rustls_result rresult = 0;
146 
147   io_ctx.cf = cf;
148   io_ctx.data = data;
149   io_error = rustls_connection_read_tls(backend->conn, read_cb, &io_ctx,
150                                         &tls_bytes_read);
151   if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
152     *err = CURLE_AGAIN;
153     return -1;
154   }
155   else if(io_error) {
156     char buffer[STRERROR_LEN];
157     failf(data, "reading from socket: %s",
158           Curl_strerror(io_error, buffer, sizeof(buffer)));
159     *err = CURLE_RECV_ERROR;
160     return -1;
161   }
162 
163   rresult = rustls_connection_process_new_packets(backend->conn);
164   if(rresult != RUSTLS_RESULT_OK) {
165     char errorbuf[255];
166     size_t errorlen;
167     rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
168     failf(data, "rustls_connection_process_new_packets: %.*s",
169       (int)errorlen, errorbuf);
170     *err = map_error(rresult);
171     return -1;
172   }
173 
174   backend->data_in_pending = TRUE;
175   *err = CURLE_OK;
176   return (ssize_t)tls_bytes_read;
177 }
178 
179 /*
180  * On each run:
181  *  - Read a chunk of bytes from the socket into Rustls' TLS input buffer.
182  *  - Tell Rustls to process any new packets.
183  *  - Read out as many plaintext bytes from Rustls as possible, until hitting
184  *    error, EOF, or EAGAIN/EWOULDBLOCK, or plainbuf/plainlen is filled up.
185  *
186  * it is okay to call this function with plainbuf == NULL and plainlen == 0. In
187  * that case, it will copy bytes from the socket into Rustls' TLS input
188  * buffer, and process packets, but will not consume bytes from Rustls'
189  * plaintext output buffer.
190  */
191 static ssize_t
cr_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * plainbuf,size_t plainlen,CURLcode * err)192 cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
193             char *plainbuf, size_t plainlen, CURLcode *err)
194 {
195   struct ssl_connect_data *const connssl = cf->ctx;
196   struct rustls_ssl_backend_data *const backend =
197     (struct rustls_ssl_backend_data *)connssl->backend;
198   struct rustls_connection *rconn = NULL;
199   size_t n = 0;
200   size_t plain_bytes_copied = 0;
201   rustls_result rresult = 0;
202   ssize_t nread;
203   bool eof = FALSE;
204 
205   DEBUGASSERT(backend);
206   rconn = backend->conn;
207 
208   while(plain_bytes_copied < plainlen) {
209     if(!backend->data_in_pending) {
210       if(tls_recv_more(cf, data, err) < 0) {
211         if(*err != CURLE_AGAIN) {
212           nread = -1;
213           goto out;
214         }
215         break;
216       }
217     }
218 
219     rresult = rustls_connection_read(rconn,
220                                      (uint8_t *)plainbuf + plain_bytes_copied,
221                                      plainlen - plain_bytes_copied,
222                                      &n);
223     if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) {
224       backend->data_in_pending = FALSE;
225     }
226     else if(rresult == RUSTLS_RESULT_UNEXPECTED_EOF) {
227       failf(data, "rustls: peer closed TCP connection "
228             "without first closing TLS connection");
229       *err = CURLE_RECV_ERROR;
230       nread = -1;
231       goto out;
232     }
233     else if(rresult != RUSTLS_RESULT_OK) {
234       /* n always equals 0 in this case, do not need to check it */
235       char errorbuf[255];
236       size_t errorlen;
237       rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
238       failf(data, "rustls_connection_read: %.*s", (int)errorlen, errorbuf);
239       *err = CURLE_RECV_ERROR;
240       nread = -1;
241       goto out;
242     }
243     else if(n == 0) {
244       /* n == 0 indicates clean EOF, but we may have read some other
245          plaintext bytes before we reached this. Break out of the loop
246          so we can figure out whether to return success or EOF. */
247       eof = TRUE;
248       break;
249     }
250     else {
251       plain_bytes_copied += n;
252     }
253   }
254 
255   if(plain_bytes_copied) {
256     *err = CURLE_OK;
257     nread = (ssize_t)plain_bytes_copied;
258   }
259   else if(eof) {
260     *err = CURLE_OK;
261     nread = 0;
262   }
263   else {
264     *err = CURLE_AGAIN;
265     nread = -1;
266   }
267 
268 out:
269   CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d",
270               plainlen, nread, *err);
271   return nread;
272 }
273 
cr_flush_out(struct Curl_cfilter * cf,struct Curl_easy * data,struct rustls_connection * rconn)274 static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data,
275                              struct rustls_connection *rconn)
276 {
277   struct io_ctx io_ctx;
278   rustls_io_result io_error;
279   size_t tlswritten = 0;
280   size_t tlswritten_total = 0;
281   CURLcode result = CURLE_OK;
282 
283   io_ctx.cf = cf;
284   io_ctx.data = data;
285 
286   while(rustls_connection_wants_write(rconn)) {
287     io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx,
288                                            &tlswritten);
289     if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
290       CURL_TRC_CF(data, cf, "cf_send: EAGAIN after %zu bytes",
291                   tlswritten_total);
292       return CURLE_AGAIN;
293     }
294     else if(io_error) {
295       char buffer[STRERROR_LEN];
296       failf(data, "writing to socket: %s",
297             Curl_strerror(io_error, buffer, sizeof(buffer)));
298       return CURLE_SEND_ERROR;
299     }
300     if(tlswritten == 0) {
301       failf(data, "EOF in swrite");
302       return CURLE_SEND_ERROR;
303     }
304     CURL_TRC_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten);
305     tlswritten_total += tlswritten;
306   }
307   return result;
308 }
309 
310 /*
311  * On each call:
312  *  - Copy `plainlen` bytes into Rustls' plaintext input buffer (if > 0).
313  *  - Fully drain Rustls' plaintext output buffer into the socket until
314  *    we get either an error or EAGAIN/EWOULDBLOCK.
315  *
316  * it is okay to call this function with plainbuf == NULL and plainlen == 0.
317  * In that case, it will not read anything into Rustls' plaintext input buffer.
318  * It will only drain Rustls' plaintext output buffer into the socket.
319  */
320 static ssize_t
cr_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * plainbuf,size_t plainlen,CURLcode * err)321 cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
322         const void *plainbuf, size_t plainlen, CURLcode *err)
323 {
324   struct ssl_connect_data *const connssl = cf->ctx;
325   struct rustls_ssl_backend_data *const backend =
326     (struct rustls_ssl_backend_data *)connssl->backend;
327   struct rustls_connection *rconn = NULL;
328   size_t plainwritten = 0;
329   rustls_result rresult;
330   char errorbuf[256];
331   size_t errorlen;
332   const unsigned char *buf = plainbuf;
333   size_t blen = plainlen;
334   ssize_t nwritten = 0;
335 
336   DEBUGASSERT(backend);
337   rconn = backend->conn;
338   DEBUGASSERT(rconn);
339 
340   CURL_TRC_CF(data, cf, "cf_send(len=%zu)", plainlen);
341 
342   /* If a previous send blocked, we already added its plain bytes
343    * to rustsls and must not do that again. Flush the TLS bytes and,
344    * if successful, deduct the previous plain bytes from the current
345    * send. */
346   if(backend->plain_out_buffered) {
347     *err = cr_flush_out(cf, data, rconn);
348     CURL_TRC_CF(data, cf, "cf_send: flushing %zu previously added bytes -> %d",
349                 backend->plain_out_buffered, *err);
350     if(*err)
351       return -1;
352     if(blen > backend->plain_out_buffered) {
353       blen -= backend->plain_out_buffered;
354       buf += backend->plain_out_buffered;
355     }
356     else
357       blen = 0;
358     nwritten += (ssize_t)backend->plain_out_buffered;
359     backend->plain_out_buffered = 0;
360   }
361 
362   if(blen > 0) {
363     CURL_TRC_CF(data, cf, "cf_send: adding %zu plain bytes to Rustls", blen);
364     rresult = rustls_connection_write(rconn, buf, blen, &plainwritten);
365     if(rresult != RUSTLS_RESULT_OK) {
366       rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
367       failf(data, "rustls_connection_write: %.*s", (int)errorlen, errorbuf);
368       *err = CURLE_WRITE_ERROR;
369       return -1;
370     }
371     else if(plainwritten == 0) {
372       failf(data, "rustls_connection_write: EOF");
373       *err = CURLE_WRITE_ERROR;
374       return -1;
375     }
376   }
377 
378   *err = cr_flush_out(cf, data, rconn);
379   if(*err) {
380     if(CURLE_AGAIN == *err) {
381       /* The TLS bytes may have been partially written, but we fail the
382        * complete send() and remember how much we already added to Rustls. */
383       CURL_TRC_CF(data, cf, "cf_send: EAGAIN, remember we added %zu plain"
384                   " bytes already to Rustls", blen);
385       backend->plain_out_buffered = plainwritten;
386       if(nwritten) {
387         *err = CURLE_OK;
388         return (ssize_t)nwritten;
389       }
390     }
391     return -1;
392   }
393   else
394     nwritten += (ssize_t)plainwritten;
395 
396   CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %d, %zd",
397               plainlen, *err, nwritten);
398   return nwritten;
399 }
400 
401 /* A server certificate verify callback for Rustls that always returns
402    RUSTLS_RESULT_OK, or in other words disable certificate verification. */
403 static uint32_t
cr_verify_none(void * userdata UNUSED_PARAM,const rustls_verify_server_cert_params * params UNUSED_PARAM)404 cr_verify_none(void *userdata UNUSED_PARAM,
405                const rustls_verify_server_cert_params *params UNUSED_PARAM)
406 {
407   return RUSTLS_RESULT_OK;
408 }
409 
410 static int
read_file_into(const char * filename,struct dynbuf * out)411 read_file_into(const char *filename,
412                struct dynbuf *out)
413 {
414   FILE *f = fopen(filename, FOPEN_READTEXT);
415   if(!f) {
416     return 0;
417   }
418 
419   while(!feof(f)) {
420     uint8_t buf[256];
421     size_t rr = fread(buf, 1, sizeof(buf), f);
422     if(rr == 0 ||
423        CURLE_OK != Curl_dyn_addn(out, buf, rr)) {
424       fclose(f);
425       return 0;
426     }
427   }
428 
429   return fclose(f) == 0;
430 }
431 
432 static void
cr_get_selected_ciphers(struct Curl_easy * data,const char * ciphers12,const char * ciphers13,const struct rustls_supported_ciphersuite ** selected,size_t * selected_size)433 cr_get_selected_ciphers(struct Curl_easy *data,
434                         const char *ciphers12,
435                         const char *ciphers13,
436                         const struct rustls_supported_ciphersuite **selected,
437                         size_t *selected_size)
438 {
439   size_t supported_len = *selected_size;
440   size_t default_len = rustls_default_crypto_provider_ciphersuites_len();
441   const struct rustls_supported_ciphersuite *entry;
442   const char *ciphers = ciphers12;
443   size_t count = 0, default13_count = 0, i, j;
444   const char *ptr, *end;
445 
446   DEBUGASSERT(default_len <= supported_len);
447 
448   if(!ciphers13) {
449     /* Add default TLSv1.3 ciphers to selection */
450     for(j = 0; j < default_len; j++) {
451       entry = rustls_default_crypto_provider_ciphersuites_get(j);
452       if(rustls_supported_ciphersuite_protocol_version(entry) !=
453          RUSTLS_TLS_VERSION_TLSV1_3)
454         continue;
455 
456       selected[count++] = entry;
457     }
458 
459     default13_count = count;
460 
461     if(!ciphers)
462       ciphers = "";
463   }
464   else
465     ciphers = ciphers13;
466 
467 add_ciphers:
468   for(ptr = ciphers; ptr[0] != '\0' && count < supported_len; ptr = end) {
469     uint16_t id = Curl_cipher_suite_walk_str(&ptr, &end);
470 
471     /* Check if cipher is supported */
472     if(id) {
473       for(i = 0; i < supported_len; i++) {
474         entry = rustls_default_crypto_provider_ciphersuites_get(i);
475         if(rustls_supported_ciphersuite_get_suite(entry) == id)
476           break;
477       }
478       if(i == supported_len)
479         id = 0;
480     }
481     if(!id) {
482       if(ptr[0] != '\0')
483         infof(data, "rustls: unknown cipher in list: \"%.*s\"",
484               (int) (end - ptr), ptr);
485       continue;
486     }
487 
488     /* No duplicates allowed (so selected cannot overflow) */
489     for(i = 0; i < count && selected[i] != entry; i++);
490     if(i < count) {
491       if(i >= default13_count)
492         infof(data, "rustls: duplicate cipher in list: \"%.*s\"",
493               (int) (end - ptr), ptr);
494       continue;
495     }
496 
497     selected[count++] = entry;
498   }
499 
500   if(ciphers == ciphers13 && ciphers12) {
501     ciphers = ciphers12;
502     goto add_ciphers;
503   }
504 
505   if(!ciphers12) {
506     /* Add default TLSv1.2 ciphers to selection */
507     for(j = 0; j < default_len; j++) {
508       entry = rustls_default_crypto_provider_ciphersuites_get(j);
509       if(rustls_supported_ciphersuite_protocol_version(entry) ==
510           RUSTLS_TLS_VERSION_TLSV1_3)
511         continue;
512 
513       /* No duplicates allowed (so selected cannot overflow) */
514       for(i = 0; i < count && selected[i] != entry; i++);
515       if(i < count)
516         continue;
517 
518       selected[count++] = entry;
519     }
520   }
521 
522   *selected_size = count;
523 }
524 
525 static CURLcode
cr_init_backend(struct Curl_cfilter * cf,struct Curl_easy * data,struct rustls_ssl_backend_data * const backend)526 cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
527                 struct rustls_ssl_backend_data *const backend)
528 {
529   struct ssl_connect_data *connssl = cf->ctx;
530   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
531   struct rustls_crypto_provider_builder *custom_provider_builder = NULL;
532   const struct rustls_crypto_provider *custom_provider = NULL;
533   struct rustls_connection *rconn = NULL;
534   struct rustls_client_config_builder *config_builder = NULL;
535   const struct rustls_root_cert_store *roots = NULL;
536   struct rustls_root_cert_store_builder *roots_builder = NULL;
537   struct rustls_web_pki_server_cert_verifier_builder *verifier_builder = NULL;
538   struct rustls_server_cert_verifier *server_cert_verifier = NULL;
539   const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
540   const char * const ssl_cafile =
541     /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
542     (ca_info_blob ? NULL : conn_config->CAfile);
543   const bool verifypeer = conn_config->verifypeer;
544   char errorbuf[256];
545   size_t errorlen;
546   rustls_result result;
547 
548   DEBUGASSERT(backend);
549   rconn = backend->conn;
550 
551   {
552     uint16_t tls_versions[2] = {
553         RUSTLS_TLS_VERSION_TLSV1_2,
554         RUSTLS_TLS_VERSION_TLSV1_3,
555     };
556     size_t tls_versions_len = 2;
557     const struct rustls_supported_ciphersuite **cipher_suites;
558     size_t cipher_suites_len =
559       rustls_default_crypto_provider_ciphersuites_len();
560 
561     switch(conn_config->version) {
562     case CURL_SSLVERSION_DEFAULT:
563     case CURL_SSLVERSION_TLSv1:
564     case CURL_SSLVERSION_TLSv1_0:
565     case CURL_SSLVERSION_TLSv1_1:
566     case CURL_SSLVERSION_TLSv1_2:
567       break;
568     case CURL_SSLVERSION_TLSv1_3:
569       tls_versions[0] = RUSTLS_TLS_VERSION_TLSV1_3;
570       tls_versions_len = 1;
571       break;
572     default:
573       failf(data, "rustls: unsupported minimum TLS version value");
574       return CURLE_BAD_FUNCTION_ARGUMENT;
575     }
576 
577     switch(conn_config->version_max) {
578     case CURL_SSLVERSION_MAX_DEFAULT:
579     case CURL_SSLVERSION_MAX_NONE:
580     case CURL_SSLVERSION_MAX_TLSv1_3:
581       break;
582     case CURL_SSLVERSION_MAX_TLSv1_2:
583       if(tls_versions[0] == RUSTLS_TLS_VERSION_TLSV1_2) {
584         tls_versions_len = 1;
585         break;
586       }
587       FALLTHROUGH();
588     case CURL_SSLVERSION_MAX_TLSv1_1:
589     case CURL_SSLVERSION_MAX_TLSv1_0:
590     default:
591       failf(data, "rustls: unsupported maximum TLS version value");
592       return CURLE_BAD_FUNCTION_ARGUMENT;
593     }
594 
595     cipher_suites = malloc(sizeof(cipher_suites) * (cipher_suites_len));
596     if(!cipher_suites)
597       return CURLE_OUT_OF_MEMORY;
598 
599     cr_get_selected_ciphers(data,
600                             conn_config->cipher_list,
601                             conn_config->cipher_list13,
602                             cipher_suites, &cipher_suites_len);
603     if(cipher_suites_len == 0) {
604       failf(data, "rustls: no supported cipher in list");
605       free(cipher_suites);
606       return CURLE_SSL_CIPHER;
607     }
608 
609     result = rustls_crypto_provider_builder_new_from_default(
610       &custom_provider_builder);
611     if(result != RUSTLS_RESULT_OK) {
612       failf(data,
613             "rustls: failed to create crypto provider builder from default");
614       return CURLE_SSL_CIPHER;
615     }
616 
617     result =
618       rustls_crypto_provider_builder_set_cipher_suites(
619         custom_provider_builder,
620         cipher_suites,
621         cipher_suites_len);
622     if(result != RUSTLS_RESULT_OK) {
623       failf(data,
624             "rustls: failed to set ciphersuites for crypto provider builder");
625       rustls_crypto_provider_builder_free(custom_provider_builder);
626       return CURLE_SSL_CIPHER;
627     }
628 
629     result = rustls_crypto_provider_builder_build(
630       custom_provider_builder, &custom_provider);
631     if(result != RUSTLS_RESULT_OK) {
632       failf(data, "rustls: failed to build custom crypto provider");
633       rustls_crypto_provider_builder_free(custom_provider_builder);
634       return CURLE_SSL_CIPHER;
635     }
636 
637     result = rustls_client_config_builder_new_custom(custom_provider,
638                                                      tls_versions,
639                                                      tls_versions_len,
640                                                      &config_builder);
641     free(cipher_suites);
642     if(result != RUSTLS_RESULT_OK) {
643       failf(data, "rustls: failed to create client config");
644       return CURLE_SSL_CIPHER;
645     }
646   }
647 
648   rustls_crypto_provider_builder_free(custom_provider_builder);
649   rustls_crypto_provider_free(custom_provider);
650 
651   if(connssl->alpn) {
652     struct alpn_proto_buf proto;
653     rustls_slice_bytes alpn[ALPN_ENTRIES_MAX];
654     size_t i;
655 
656     for(i = 0; i < connssl->alpn->count; ++i) {
657       alpn[i].data = (const uint8_t *)connssl->alpn->entries[i];
658       alpn[i].len = strlen(connssl->alpn->entries[i]);
659     }
660     rustls_client_config_builder_set_alpn_protocols(config_builder, alpn,
661                                                     connssl->alpn->count);
662     Curl_alpn_to_proto_str(&proto, connssl->alpn);
663     infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
664   }
665   if(!verifypeer) {
666     rustls_client_config_builder_dangerous_set_certificate_verifier(
667       config_builder, cr_verify_none);
668   }
669   else if(ca_info_blob || ssl_cafile) {
670     roots_builder = rustls_root_cert_store_builder_new();
671 
672     if(ca_info_blob) {
673       /* Enable strict parsing only if verification is not disabled. */
674       result = rustls_root_cert_store_builder_add_pem(roots_builder,
675                                                       ca_info_blob->data,
676                                                       ca_info_blob->len,
677                                                       verifypeer);
678       if(result != RUSTLS_RESULT_OK) {
679         failf(data, "rustls: failed to parse trusted certificates from blob");
680         rustls_root_cert_store_builder_free(roots_builder);
681         rustls_client_config_builder_free(config_builder);
682         return CURLE_SSL_CACERT_BADFILE;
683       }
684     }
685     else if(ssl_cafile) {
686       /* Enable strict parsing only if verification is not disabled. */
687       result = rustls_root_cert_store_builder_load_roots_from_file(
688         roots_builder, ssl_cafile, verifypeer);
689       if(result != RUSTLS_RESULT_OK) {
690         failf(data, "rustls: failed to load trusted certificates");
691         rustls_root_cert_store_builder_free(roots_builder);
692         rustls_client_config_builder_free(config_builder);
693         return CURLE_SSL_CACERT_BADFILE;
694       }
695     }
696 
697     result = rustls_root_cert_store_builder_build(roots_builder, &roots);
698     rustls_root_cert_store_builder_free(roots_builder);
699     if(result != RUSTLS_RESULT_OK) {
700       failf(data, "rustls: failed to build trusted root certificate store");
701       rustls_client_config_builder_free(config_builder);
702       return CURLE_SSL_CACERT_BADFILE;
703     }
704 
705     verifier_builder = rustls_web_pki_server_cert_verifier_builder_new(roots);
706     rustls_root_cert_store_free(roots);
707 
708     if(conn_config->CRLfile) {
709       struct dynbuf crl_contents;
710       Curl_dyn_init(&crl_contents, SIZE_MAX);
711       if(!read_file_into(conn_config->CRLfile, &crl_contents)) {
712         failf(data, "rustls: failed to read revocation list file");
713         Curl_dyn_free(&crl_contents);
714         rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
715         return CURLE_SSL_CRL_BADFILE;
716       }
717 
718       result = rustls_web_pki_server_cert_verifier_builder_add_crl(
719         verifier_builder,
720         Curl_dyn_uptr(&crl_contents),
721         Curl_dyn_len(&crl_contents));
722       Curl_dyn_free(&crl_contents);
723       if(result != RUSTLS_RESULT_OK) {
724         failf(data, "rustls: failed to parse revocation list");
725         rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
726         return CURLE_SSL_CRL_BADFILE;
727       }
728     }
729 
730     result = rustls_web_pki_server_cert_verifier_builder_build(
731       verifier_builder, &server_cert_verifier);
732     rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
733     if(result != RUSTLS_RESULT_OK) {
734       failf(data, "rustls: failed to build certificate verifier");
735       rustls_server_cert_verifier_free(server_cert_verifier);
736       rustls_client_config_builder_free(config_builder);
737       return CURLE_SSL_CACERT_BADFILE;
738     }
739 
740     rustls_client_config_builder_set_server_verifier(config_builder,
741                                                      server_cert_verifier);
742     rustls_server_cert_verifier_free(server_cert_verifier);
743   }
744 
745   result = rustls_client_config_builder_build(
746     config_builder,
747     &backend->config);
748   if(result != RUSTLS_RESULT_OK) {
749     failf(data, "rustls: failed to build client config");
750     rustls_client_config_free(backend->config);
751     return CURLE_SSL_CONNECT_ERROR;
752   }
753 
754   DEBUGASSERT(rconn == NULL);
755   result = rustls_client_connection_new(backend->config,
756                                         connssl->peer.hostname, &rconn);
757   if(result != RUSTLS_RESULT_OK) {
758     rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
759     failf(data, "rustls_client_connection_new: %.*s", (int)errorlen, errorbuf);
760     return CURLE_COULDNT_CONNECT;
761   }
762   DEBUGASSERT(rconn);
763   rustls_connection_set_userdata(rconn, backend);
764   backend->conn = rconn;
765   return CURLE_OK;
766 }
767 
768 static void
cr_set_negotiated_alpn(struct Curl_cfilter * cf,struct Curl_easy * data,const struct rustls_connection * rconn)769 cr_set_negotiated_alpn(struct Curl_cfilter *cf, struct Curl_easy *data,
770   const struct rustls_connection *rconn)
771 {
772   struct ssl_connect_data *const connssl = cf->ctx;
773   const uint8_t *protocol = NULL;
774   size_t len = 0;
775 
776   rustls_connection_get_alpn_protocol(rconn, &protocol, &len);
777   Curl_alpn_set_negotiated(cf, data, connssl, protocol, len);
778 }
779 
780 /* Given an established network connection, do a TLS handshake.
781  *
782  * If `blocking` is true, this function will block until the handshake is
783  * complete. Otherwise it will return as soon as I/O would block.
784  *
785  * For the non-blocking I/O case, this function will set `*done` to true
786  * once the handshake is complete. This function never reads the value of
787  * `*done*`.
788  */
789 static CURLcode
cr_connect_common(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)790 cr_connect_common(struct Curl_cfilter *cf,
791                   struct Curl_easy *data,
792                   bool blocking,
793                   bool *done)
794 {
795   struct ssl_connect_data *const connssl = cf->ctx;
796   curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
797   struct rustls_ssl_backend_data *const backend =
798     (struct rustls_ssl_backend_data *)connssl->backend;
799   struct rustls_connection *rconn = NULL;
800   CURLcode tmperr = CURLE_OK;
801   int result;
802   int what;
803   bool wants_read;
804   bool wants_write;
805   curl_socket_t writefd;
806   curl_socket_t readfd;
807   timediff_t timeout_ms;
808   timediff_t socket_check_timeout;
809 
810   DEBUGASSERT(backend);
811 
812   CURL_TRC_CF(data, cf, "cr_connect_common, state=%d", connssl->state);
813   *done = FALSE;
814   if(!backend->conn) {
815     result = cr_init_backend(cf, data,
816                (struct rustls_ssl_backend_data *)connssl->backend);
817     CURL_TRC_CF(data, cf, "cr_connect_common, init backend -> %d", result);
818     if(result != CURLE_OK) {
819       return result;
820     }
821     connssl->state = ssl_connection_negotiating;
822   }
823 
824   rconn = backend->conn;
825 
826   /* Read/write data until the handshake is done or the socket would block. */
827   for(;;) {
828     /*
829     * Connection has been established according to Rustls. Set send/recv
830     * handlers, and update the state machine.
831     */
832     connssl->io_need = CURL_SSL_IO_NEED_NONE;
833     if(!rustls_connection_is_handshaking(rconn)) {
834       /* Rustls claims it is no longer handshaking *before* it has
835        * send its FINISHED message off. We attempt to let it write
836        * one more time. Oh my.
837        */
838       cr_set_negotiated_alpn(cf, data, rconn);
839       cr_send(cf, data, NULL, 0, &tmperr);
840       if(tmperr == CURLE_AGAIN) {
841         connssl->io_need = CURL_SSL_IO_NEED_SEND;
842         return CURLE_OK;
843       }
844       else if(tmperr != CURLE_OK) {
845         return tmperr;
846       }
847       /* REALLY Done with the handshake. */
848       {
849         uint16_t proto = rustls_connection_get_protocol_version(rconn);
850         uint16_t cipher = rustls_connection_get_negotiated_ciphersuite(rconn);
851         char buf[64] = "";
852         const char *ver = "TLS version unknown";
853         if(proto == RUSTLS_TLS_VERSION_TLSV1_3)
854           ver = "TLSv1.3";
855         if(proto == RUSTLS_TLS_VERSION_TLSV1_2)
856           ver = "TLSv1.2";
857         Curl_cipher_suite_get_str(cipher, buf, sizeof(buf), TRUE);
858         infof(data, "rustls: handshake complete, %s, cipher: %s",
859               ver, buf);
860       }
861       connssl->state = ssl_connection_complete;
862       *done = TRUE;
863       return CURLE_OK;
864     }
865 
866     connssl->connecting_state = ssl_connect_2;
867     wants_read = rustls_connection_wants_read(rconn);
868     wants_write = rustls_connection_wants_write(rconn) ||
869                   backend->plain_out_buffered;
870     DEBUGASSERT(wants_read || wants_write);
871     writefd = wants_write ? sockfd : CURL_SOCKET_BAD;
872     readfd = wants_read ? sockfd : CURL_SOCKET_BAD;
873 
874     /* check allowed time left */
875     timeout_ms = Curl_timeleft(data, NULL, TRUE);
876 
877     if(timeout_ms < 0) {
878       /* no need to continue if time already is up */
879       failf(data, "rustls: operation timed out before socket check");
880       return CURLE_OPERATION_TIMEDOUT;
881     }
882 
883     socket_check_timeout = blocking ? timeout_ms : 0;
884 
885     what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
886                              socket_check_timeout);
887     if(what < 0) {
888       /* fatal error */
889       failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
890       return CURLE_SSL_CONNECT_ERROR;
891     }
892     if(blocking && 0 == what) {
893       failf(data, "rustls: connection timeout after %" FMT_TIMEDIFF_T " ms",
894             socket_check_timeout);
895       return CURLE_OPERATION_TIMEDOUT;
896     }
897     if(0 == what) {
898       CURL_TRC_CF(data, cf, "Curl_socket_check: %s would block",
899             wants_read && wants_write ? "writing and reading" :
900             wants_write ? "writing" : "reading");
901       if(wants_write)
902         connssl->io_need |= CURL_SSL_IO_NEED_SEND;
903       if(wants_read)
904         connssl->io_need |= CURL_SSL_IO_NEED_RECV;
905       return CURLE_OK;
906     }
907     /* socket is readable or writable */
908 
909     if(wants_write) {
910       CURL_TRC_CF(data, cf, "rustls_connection wants us to write_tls.");
911       cr_send(cf, data, NULL, 0, &tmperr);
912       if(tmperr == CURLE_AGAIN) {
913         CURL_TRC_CF(data, cf, "writing would block");
914         /* fall through */
915       }
916       else if(tmperr != CURLE_OK) {
917         return tmperr;
918       }
919     }
920 
921     if(wants_read) {
922       CURL_TRC_CF(data, cf, "rustls_connection wants us to read_tls.");
923       if(tls_recv_more(cf, data, &tmperr) < 0) {
924         if(tmperr == CURLE_AGAIN) {
925           CURL_TRC_CF(data, cf, "reading would block");
926           /* fall through */
927         }
928         else if(tmperr == CURLE_RECV_ERROR) {
929           return CURLE_SSL_CONNECT_ERROR;
930         }
931         else {
932           return tmperr;
933         }
934       }
935     }
936   }
937 
938   /* We should never fall through the loop. We should return either because
939      the handshake is done or because we cannot read/write without blocking. */
940   DEBUGASSERT(FALSE);
941 }
942 
943 static CURLcode
cr_connect_nonblocking(struct Curl_cfilter * cf,struct Curl_easy * data,bool * done)944 cr_connect_nonblocking(struct Curl_cfilter *cf,
945                        struct Curl_easy *data, bool *done)
946 {
947   return cr_connect_common(cf, data, false, done);
948 }
949 
950 static CURLcode
cr_connect_blocking(struct Curl_cfilter * cf,struct Curl_easy * data)951 cr_connect_blocking(struct Curl_cfilter *cf, struct Curl_easy *data)
952 {
953   bool done; /* unused */
954   return cr_connect_common(cf, data, true, &done);
955 }
956 
957 static void *
cr_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)958 cr_get_internals(struct ssl_connect_data *connssl,
959                  CURLINFO info UNUSED_PARAM)
960 {
961   struct rustls_ssl_backend_data *backend =
962     (struct rustls_ssl_backend_data *)connssl->backend;
963   DEBUGASSERT(backend);
964   return &backend->conn;
965 }
966 
967 static CURLcode
cr_shutdown(struct Curl_cfilter * cf,struct Curl_easy * data,bool send_shutdown,bool * done)968 cr_shutdown(struct Curl_cfilter *cf,
969             struct Curl_easy *data,
970             bool send_shutdown, bool *done)
971 {
972   struct ssl_connect_data *connssl = cf->ctx;
973   struct rustls_ssl_backend_data *backend =
974     (struct rustls_ssl_backend_data *)connssl->backend;
975   CURLcode result = CURLE_OK;
976   ssize_t nwritten, nread;
977   char buf[1024];
978   size_t i;
979 
980   DEBUGASSERT(backend);
981   if(!backend->conn || cf->shutdown) {
982     *done = TRUE;
983     goto out;
984   }
985 
986   connssl->io_need = CURL_SSL_IO_NEED_NONE;
987   *done = FALSE;
988 
989   if(!backend->sent_shutdown) {
990     /* do this only once */
991     backend->sent_shutdown = TRUE;
992     if(send_shutdown) {
993       rustls_connection_send_close_notify(backend->conn);
994     }
995   }
996 
997   nwritten = cr_send(cf, data, NULL, 0, &result);
998   if(nwritten < 0) {
999     if(result == CURLE_AGAIN) {
1000       connssl->io_need = CURL_SSL_IO_NEED_SEND;
1001       result = CURLE_OK;
1002       goto out;
1003     }
1004     DEBUGASSERT(result);
1005     CURL_TRC_CF(data, cf, "shutdown send failed: %d", result);
1006     goto out;
1007   }
1008 
1009   for(i = 0; i < 10; ++i) {
1010     nread = cr_recv(cf, data, buf, (int)sizeof(buf), &result);
1011     if(nread <= 0)
1012       break;
1013   }
1014 
1015   if(nread > 0) {
1016     /* still data coming in? */
1017   }
1018   else if(nread == 0) {
1019     /* We got the close notify alert and are done. */
1020     *done = TRUE;
1021   }
1022   else if(result == CURLE_AGAIN) {
1023     connssl->io_need = CURL_SSL_IO_NEED_RECV;
1024     result = CURLE_OK;
1025   }
1026   else {
1027     DEBUGASSERT(result);
1028     CURL_TRC_CF(data, cf, "shutdown, error: %d", result);
1029   }
1030 
1031 out:
1032   cf->shutdown = (result || *done);
1033   return result;
1034 }
1035 
1036 static void
cr_close(struct Curl_cfilter * cf,struct Curl_easy * data)1037 cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
1038 {
1039   struct ssl_connect_data *connssl = cf->ctx;
1040   struct rustls_ssl_backend_data *backend =
1041     (struct rustls_ssl_backend_data *)connssl->backend;
1042 
1043   (void)data;
1044   DEBUGASSERT(backend);
1045   if(backend->conn) {
1046     rustls_connection_free(backend->conn);
1047     backend->conn = NULL;
1048   }
1049   if(backend->config) {
1050     rustls_client_config_free(backend->config);
1051     backend->config = NULL;
1052   }
1053 }
1054 
cr_version(char * buffer,size_t size)1055 static size_t cr_version(char *buffer, size_t size)
1056 {
1057   struct rustls_str ver = rustls_version();
1058   return msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data);
1059 }
1060 
1061 static CURLcode
cr_random(struct Curl_easy * data,unsigned char * entropy,size_t length)1062 cr_random(struct Curl_easy *data, unsigned char *entropy, size_t length)
1063 {
1064   rustls_result rresult = 0;
1065   (void)data;
1066   rresult =
1067     rustls_default_crypto_provider_random(entropy, length);
1068   return map_error(rresult);
1069 }
1070 
1071 const struct Curl_ssl Curl_ssl_rustls = {
1072   { CURLSSLBACKEND_RUSTLS, "rustls" },
1073   SSLSUPP_CAINFO_BLOB |            /* supports */
1074   SSLSUPP_HTTPS_PROXY |
1075   SSLSUPP_CIPHER_LIST |
1076   SSLSUPP_TLS13_CIPHERSUITES,
1077   sizeof(struct rustls_ssl_backend_data),
1078 
1079   Curl_none_init,                  /* init */
1080   Curl_none_cleanup,               /* cleanup */
1081   cr_version,                      /* version */
1082   Curl_none_check_cxn,             /* check_cxn */
1083   cr_shutdown,                     /* shutdown */
1084   cr_data_pending,                 /* data_pending */
1085   cr_random,                       /* random */
1086   Curl_none_cert_status_request,   /* cert_status_request */
1087   cr_connect_blocking,             /* connect */
1088   cr_connect_nonblocking,          /* connect_nonblocking */
1089   Curl_ssl_adjust_pollset,         /* adjust_pollset */
1090   cr_get_internals,                /* get_internals */
1091   cr_close,                        /* close_one */
1092   Curl_none_close_all,             /* close_all */
1093   Curl_none_set_engine,            /* set_engine */
1094   Curl_none_set_engine_default,    /* set_engine_default */
1095   Curl_none_engines_list,          /* engines_list */
1096   Curl_none_false_start,           /* false_start */
1097   NULL,                            /* sha256sum */
1098   NULL,                            /* associate_connection */
1099   NULL,                            /* disassociate_connection */
1100   cr_recv,                         /* recv decrypted data */
1101   cr_send,                         /* send data to encrypt */
1102   NULL,                            /* get_channel_binding */
1103 };
1104 
1105 #endif /* USE_RUSTLS */
1106