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