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