1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 2019 - 2021, Michael Forney, <mforney@mforney.org>
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22#include "curl_setup.h"
23
24#ifdef USE_BEARSSL
25
26#include <bearssl.h>
27
28#include "bearssl.h"
29#include "urldata.h"
30#include "sendf.h"
31#include "inet_pton.h"
32#include "vtls.h"
33#include "connect.h"
34#include "select.h"
35#include "multiif.h"
36#include "curl_printf.h"
37#include "curl_memory.h"
38
39struct x509_context {
40 const br_x509_class *vtable;
41 br_x509_minimal_context minimal;
42 bool verifyhost;
43 bool verifypeer;
44};
45
46struct ssl_backend_data {
47 br_ssl_client_context ctx;
48 struct x509_context x509;
49 unsigned char buf[BR_SSL_BUFSIZE_BIDI];
50 br_x509_trust_anchor *anchors;
51 size_t anchors_len;
52 const char *protocols[2];
53 /* SSL client context is active */
54 bool active;
55 /* size of pending write, yet to be flushed */
56 size_t pending_write;
57};
58
59struct cafile_parser {
60 CURLcode err;
61 bool in_cert;
62 br_x509_decoder_context xc;
63 /* array of trust anchors loaded from CAfile */
64 br_x509_trust_anchor *anchors;
65 size_t anchors_len;
66 /* buffer for DN data */
67 unsigned char dn[1024];
68 size_t dn_len;
69};
70
71#define CAFILE_SOURCE_PATH 1
72#define CAFILE_SOURCE_BLOB 2
73struct cafile_source {
74 const int type;
75 const char * const data;
76 const size_t len;
77};
78
79static void append_dn(void *ctx, const void *buf, size_t len)
80{
81 struct cafile_parser *ca = ctx;
82
83 if(ca->err != CURLE_OK || !ca->in_cert)
84 return;
85 if(sizeof(ca->dn) - ca->dn_len < len) {
86 ca->err = CURLE_FAILED_INIT;
87 return;
88 }
89 memcpy(ca->dn + ca->dn_len, buf, len);
90 ca->dn_len += len;
91}
92
93static void x509_push(void *ctx, const void *buf, size_t len)
94{
95 struct cafile_parser *ca = ctx;
96
97 if(ca->in_cert)
98 br_x509_decoder_push(&ca->xc, buf, len);
99}
100
101static CURLcode load_cafile(struct cafile_source *source,
102 br_x509_trust_anchor **anchors,
103 size_t *anchors_len)
104{
105 struct cafile_parser ca;
106 br_pem_decoder_context pc;
107 br_x509_trust_anchor *ta;
108 size_t ta_size;
109 br_x509_trust_anchor *new_anchors;
110 size_t new_anchors_len;
111 br_x509_pkey *pkey;
112 FILE *fp = 0;
113 unsigned char buf[BUFSIZ];
114 const unsigned char *p;
115 const char *name;
116 size_t n, i, pushed;
117
118 DEBUGASSERT(source->type == CAFILE_SOURCE_PATH
119 || source->type == CAFILE_SOURCE_BLOB);
120
121 if(source->type == CAFILE_SOURCE_PATH) {
122 fp = fopen(source->data, "rb");
123 if(!fp)
124 return CURLE_SSL_CACERT_BADFILE;
125 }
126
127 if(source->type == CAFILE_SOURCE_BLOB && source->len > (size_t)INT_MAX)
128 return CURLE_SSL_CACERT_BADFILE;
129
130 ca.err = CURLE_OK;
131 ca.in_cert = FALSE;
132 ca.anchors = NULL;
133 ca.anchors_len = 0;
134 br_pem_decoder_init(&pc);
135 br_pem_decoder_setdest(&pc, x509_push, &ca);
136 do {
137 if(source->type == CAFILE_SOURCE_PATH) {
138 n = fread(buf, 1, sizeof(buf), fp);
139 if(n == 0)
140 break;
141 p = buf;
142 }
143 else if(source->type == CAFILE_SOURCE_BLOB) {
144 n = source->len;
145 p = (unsigned char *) source->data;
146 }
147 while(n) {
148 pushed = br_pem_decoder_push(&pc, p, n);
149 if(ca.err)
150 goto fail;
151 p += pushed;
152 n -= pushed;
153
154 switch(br_pem_decoder_event(&pc)) {
155 case 0:
156 break;
157 case BR_PEM_BEGIN_OBJ:
158 name = br_pem_decoder_name(&pc);
159 if(strcmp(name, "CERTIFICATE") && strcmp(name, "X509 CERTIFICATE"))
160 break;
161 br_x509_decoder_init(&ca.xc, append_dn, &ca);
162 if(ca.anchors_len == SIZE_MAX / sizeof(ca.anchors[0])) {
163 ca.err = CURLE_OUT_OF_MEMORY;
164 goto fail;
165 }
166 new_anchors_len = ca.anchors_len + 1;
167 new_anchors = realloc(ca.anchors,
168 new_anchors_len * sizeof(ca.anchors[0]));
169 if(!new_anchors) {
170 ca.err = CURLE_OUT_OF_MEMORY;
171 goto fail;
172 }
173 ca.anchors = new_anchors;
174 ca.anchors_len = new_anchors_len;
175 ca.in_cert = TRUE;
176 ca.dn_len = 0;
177 ta = &ca.anchors[ca.anchors_len - 1];
178 ta->dn.data = NULL;
179 break;
180 case BR_PEM_END_OBJ:
181 if(!ca.in_cert)
182 break;
183 ca.in_cert = FALSE;
184 if(br_x509_decoder_last_error(&ca.xc)) {
185 ca.err = CURLE_SSL_CACERT_BADFILE;
186 goto fail;
187 }
188 ta->flags = 0;
189 if(br_x509_decoder_isCA(&ca.xc))
190 ta->flags |= BR_X509_TA_CA;
191 pkey = br_x509_decoder_get_pkey(&ca.xc);
192 if(!pkey) {
193 ca.err = CURLE_SSL_CACERT_BADFILE;
194 goto fail;
195 }
196 ta->pkey = *pkey;
197
198 /* calculate space needed for trust anchor data */
199 ta_size = ca.dn_len;
200 switch(pkey->key_type) {
201 case BR_KEYTYPE_RSA:
202 ta_size += pkey->key.rsa.nlen + pkey->key.rsa.elen;
203 break;
204 case BR_KEYTYPE_EC:
205 ta_size += pkey->key.ec.qlen;
206 break;
207 default:
208 ca.err = CURLE_FAILED_INIT;
209 goto fail;
210 }
211
212 /* fill in trust anchor DN and public key data */
213 ta->dn.data = malloc(ta_size);
214 if(!ta->dn.data) {
215 ca.err = CURLE_OUT_OF_MEMORY;
216 goto fail;
217 }
218 memcpy(ta->dn.data, ca.dn, ca.dn_len);
219 ta->dn.len = ca.dn_len;
220 switch(pkey->key_type) {
221 case BR_KEYTYPE_RSA:
222 ta->pkey.key.rsa.n = ta->dn.data + ta->dn.len;
223 memcpy(ta->pkey.key.rsa.n, pkey->key.rsa.n, pkey->key.rsa.nlen);
224 ta->pkey.key.rsa.e = ta->pkey.key.rsa.n + ta->pkey.key.rsa.nlen;
225 memcpy(ta->pkey.key.rsa.e, pkey->key.rsa.e, pkey->key.rsa.elen);
226 break;
227 case BR_KEYTYPE_EC:
228 ta->pkey.key.ec.q = ta->dn.data + ta->dn.len;
229 memcpy(ta->pkey.key.ec.q, pkey->key.ec.q, pkey->key.ec.qlen);
230 break;
231 }
232 break;
233 default:
234 ca.err = CURLE_SSL_CACERT_BADFILE;
235 goto fail;
236 }
237 }
238 } while(source->type != CAFILE_SOURCE_BLOB);
239 if(fp && ferror(fp))
240 ca.err = CURLE_READ_ERROR;
241
242fail:
243 if(fp)
244 fclose(fp);
245 if(ca.err == CURLE_OK) {
246 *anchors = ca.anchors;
247 *anchors_len = ca.anchors_len;
248 }
249 else {
250 for(i = 0; i < ca.anchors_len; ++i)
251 free(ca.anchors[i].dn.data);
252 free(ca.anchors);
253 }
254
255 return ca.err;
256}
257
258static void x509_start_chain(const br_x509_class **ctx,
259 const char *server_name)
260{
261 struct x509_context *x509 = (struct x509_context *)ctx;
262
263 if(!x509->verifyhost)
264 server_name = NULL;
265 x509->minimal.vtable->start_chain(&x509->minimal.vtable, server_name);
266}
267
268static void x509_start_cert(const br_x509_class **ctx, uint32_t length)
269{
270 struct x509_context *x509 = (struct x509_context *)ctx;
271
272 x509->minimal.vtable->start_cert(&x509->minimal.vtable, length);
273}
274
275static void x509_append(const br_x509_class **ctx, const unsigned char *buf,
276 size_t len)
277{
278 struct x509_context *x509 = (struct x509_context *)ctx;
279
280 x509->minimal.vtable->append(&x509->minimal.vtable, buf, len);
281}
282
283static void x509_end_cert(const br_x509_class **ctx)
284{
285 struct x509_context *x509 = (struct x509_context *)ctx;
286
287 x509->minimal.vtable->end_cert(&x509->minimal.vtable);
288}
289
290static unsigned x509_end_chain(const br_x509_class **ctx)
291{
292 struct x509_context *x509 = (struct x509_context *)ctx;
293 unsigned err;
294
295 err = x509->minimal.vtable->end_chain(&x509->minimal.vtable);
296 if(err && !x509->verifypeer) {
297 /* ignore any X.509 errors */
298 err = BR_ERR_OK;
299 }
300
301 return err;
302}
303
304static const br_x509_pkey *x509_get_pkey(const br_x509_class *const *ctx,
305 unsigned *usages)
306{
307 struct x509_context *x509 = (struct x509_context *)ctx;
308
309 return x509->minimal.vtable->get_pkey(&x509->minimal.vtable, usages);
310}
311
312static const br_x509_class x509_vtable = {
313 sizeof(struct x509_context),
314 x509_start_chain,
315 x509_start_cert,
316 x509_append,
317 x509_end_cert,
318 x509_end_chain,
319 x509_get_pkey
320};
321
322static CURLcode bearssl_connect_step1(struct Curl_easy *data,
323 struct connectdata *conn, int sockindex)
324{
325 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
326 struct ssl_backend_data *backend = connssl->backend;
327 const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
328 const char * const ssl_cafile =
329 /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
330 (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
331 const char *hostname = SSL_HOST_NAME();
332 const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
333 const bool verifyhost = SSL_CONN_CONFIG(verifyhost);
334 CURLcode ret;
335 unsigned version_min, version_max;
336#ifdef ENABLE_IPV6
337 struct in6_addr addr;
338#else
339 struct in_addr addr;
340#endif
341
342 switch(SSL_CONN_CONFIG(version)) {
343 case CURL_SSLVERSION_SSLv2:
344 failf(data, "BearSSL does not support SSLv2");
345 return CURLE_SSL_CONNECT_ERROR;
346 case CURL_SSLVERSION_SSLv3:
347 failf(data, "BearSSL does not support SSLv3");
348 return CURLE_SSL_CONNECT_ERROR;
349 case CURL_SSLVERSION_TLSv1_0:
350 version_min = BR_TLS10;
351 version_max = BR_TLS10;
352 break;
353 case CURL_SSLVERSION_TLSv1_1:
354 version_min = BR_TLS11;
355 version_max = BR_TLS11;
356 break;
357 case CURL_SSLVERSION_TLSv1_2:
358 version_min = BR_TLS12;
359 version_max = BR_TLS12;
360 break;
361 case CURL_SSLVERSION_DEFAULT:
362 case CURL_SSLVERSION_TLSv1:
363 version_min = BR_TLS10;
364 version_max = BR_TLS12;
365 break;
366 default:
367 failf(data, "BearSSL: unknown CURLOPT_SSLVERSION");
368 return CURLE_SSL_CONNECT_ERROR;
369 }
370
371 if(ca_info_blob) {
372 struct cafile_source source = {
373 CAFILE_SOURCE_BLOB,
374 ca_info_blob->data,
375 ca_info_blob->len,
376 };
377 ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
378 if(ret != CURLE_OK) {
379 if(verifypeer) {
380 failf(data, "error importing CA certificate blob");
381 return ret;
382 }
383 /* Only warn if no certificate verification is required. */
384 infof(data, "error importing CA certificate blob, continuing anyway");
385 }
386 }
387
388 if(ssl_cafile) {
389 struct cafile_source source = {
390 CAFILE_SOURCE_PATH,
391 ssl_cafile,
392 0,
393 };
394 ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
395 if(ret != CURLE_OK) {
396 if(verifypeer) {
397 failf(data, "error setting certificate verify locations."
398 " CAfile: %s", ssl_cafile);
399 return ret;
400 }
401 infof(data, "error setting certificate verify locations,"
402 " continuing anyway:");
403 }
404 }
405
406 /* initialize SSL context */
407 br_ssl_client_init_full(&backend->ctx, &backend->x509.minimal,
408 backend->anchors, backend->anchors_len);
409 br_ssl_engine_set_versions(&backend->ctx.eng, version_min, version_max);
410 br_ssl_engine_set_buffer(&backend->ctx.eng, backend->buf,
411 sizeof(backend->buf), 1);
412
413 /* initialize X.509 context */
414 backend->x509.vtable = &x509_vtable;
415 backend->x509.verifypeer = verifypeer;
416 backend->x509.verifyhost = verifyhost;
417 br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable);
418
419 if(SSL_SET_OPTION(primary.sessionid)) {
420 void *session;
421
422 Curl_ssl_sessionid_lock(data);
423 if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE,
424 &session, NULL, sockindex)) {
425 br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
426 infof(data, "BearSSL: re-using session ID");
427 }
428 Curl_ssl_sessionid_unlock(data);
429 }
430
431 if(conn->bits.tls_enable_alpn) {
432 int cur = 0;
433
434 /* NOTE: when adding more protocols here, increase the size of the
435 * protocols array in `struct ssl_backend_data`.
436 */
437
438#ifdef USE_HTTP2
439 if(data->state.httpwant >= CURL_HTTP_VERSION_2
440#ifndef CURL_DISABLE_PROXY
441 && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
442#endif
443 ) {
444 backend->protocols[cur++] = ALPN_H2;
445 infof(data, "ALPN, offering %s", ALPN_H2);
446 }
447#endif
448
449 backend->protocols[cur++] = ALPN_HTTP_1_1;
450 infof(data, "ALPN, offering %s", ALPN_HTTP_1_1);
451
452 br_ssl_engine_set_protocol_names(&backend->ctx.eng,
453 backend->protocols, cur);
454 }
455
456 if((1 == Curl_inet_pton(AF_INET, hostname, &addr))
457#ifdef ENABLE_IPV6
458 || (1 == Curl_inet_pton(AF_INET6, hostname, &addr))
459#endif
460 ) {
461 if(verifyhost) {
462 failf(data, "BearSSL: "
463 "host verification of IP address is not supported");
464 return CURLE_PEER_FAILED_VERIFICATION;
465 }
466 hostname = NULL;
467 }
468
469 if(!br_ssl_client_reset(&backend->ctx, hostname, 0))
470 return CURLE_FAILED_INIT;
471 backend->active = TRUE;
472
473 connssl->connecting_state = ssl_connect_2;
474
475 return CURLE_OK;
476}
477
478static CURLcode bearssl_run_until(struct Curl_easy *data,
479 struct connectdata *conn, int sockindex,
480 unsigned target)
481{
482 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
483 struct ssl_backend_data *backend = connssl->backend;
484 curl_socket_t sockfd = conn->sock[sockindex];
485 unsigned state;
486 unsigned char *buf;
487 size_t len;
488 ssize_t ret;
489 int err;
490
491 for(;;) {
492 state = br_ssl_engine_current_state(&backend->ctx.eng);
493 if(state & BR_SSL_CLOSED) {
494 err = br_ssl_engine_last_error(&backend->ctx.eng);
495 switch(err) {
496 case BR_ERR_OK:
497 /* TLS close notify */
498 if(connssl->state != ssl_connection_complete) {
499 failf(data, "SSL: connection closed during handshake");
500 return CURLE_SSL_CONNECT_ERROR;
501 }
502 return CURLE_OK;
503 case BR_ERR_X509_EXPIRED:
504 failf(data, "SSL: X.509 verification: "
505 "certificate is expired or not yet valid");
506 return CURLE_PEER_FAILED_VERIFICATION;
507 case BR_ERR_X509_BAD_SERVER_NAME:
508 failf(data, "SSL: X.509 verification: "
509 "expected server name was not found in the chain");
510 return CURLE_PEER_FAILED_VERIFICATION;
511 case BR_ERR_X509_NOT_TRUSTED:
512 failf(data, "SSL: X.509 verification: "
513 "chain could not be linked to a trust anchor");
514 return CURLE_PEER_FAILED_VERIFICATION;
515 }
516 /* X.509 errors are documented to have the range 32..63 */
517 if(err >= 32 && err < 64)
518 return CURLE_PEER_FAILED_VERIFICATION;
519 return CURLE_SSL_CONNECT_ERROR;
520 }
521 if(state & target)
522 return CURLE_OK;
523 if(state & BR_SSL_SENDREC) {
524 buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len);
525 ret = swrite(sockfd, buf, len);
526 if(ret == -1) {
527 if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
528 if(connssl->state != ssl_connection_complete)
529 connssl->connecting_state = ssl_connect_2_writing;
530 return CURLE_AGAIN;
531 }
532 return CURLE_WRITE_ERROR;
533 }
534 br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret);
535 }
536 else if(state & BR_SSL_RECVREC) {
537 buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len);
538 ret = sread(sockfd, buf, len);
539 if(ret == 0) {
540 failf(data, "SSL: EOF without close notify");
541 return CURLE_READ_ERROR;
542 }
543 if(ret == -1) {
544 if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
545 if(connssl->state != ssl_connection_complete)
546 connssl->connecting_state = ssl_connect_2_reading;
547 return CURLE_AGAIN;
548 }
549 return CURLE_READ_ERROR;
550 }
551 br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret);
552 }
553 }
554}
555
556static CURLcode bearssl_connect_step2(struct Curl_easy *data,
557 struct connectdata *conn, int sockindex)
558{
559 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
560 struct ssl_backend_data *backend = connssl->backend;
561 CURLcode ret;
562
563 ret = bearssl_run_until(data, conn, sockindex,
564 BR_SSL_SENDAPP | BR_SSL_RECVAPP);
565 if(ret == CURLE_AGAIN)
566 return CURLE_OK;
567 if(ret == CURLE_OK) {
568 if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) {
569 failf(data, "SSL: connection closed during handshake");
570 return CURLE_SSL_CONNECT_ERROR;
571 }
572 connssl->connecting_state = ssl_connect_3;
573 }
574 return ret;
575}
576
577static CURLcode bearssl_connect_step3(struct Curl_easy *data,
578 struct connectdata *conn, int sockindex)
579{
580 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
581 struct ssl_backend_data *backend = connssl->backend;
582 CURLcode ret;
583
584 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
585
586 if(conn->bits.tls_enable_alpn) {
587 const char *protocol;
588
589 protocol = br_ssl_engine_get_selected_protocol(&backend->ctx.eng);
590 if(protocol) {
591 infof(data, "ALPN, server accepted to use %s", protocol);
592
593#ifdef USE_HTTP2
594 if(!strcmp(protocol, ALPN_H2))
595 conn->negnpn = CURL_HTTP_VERSION_2;
596 else
597#endif
598 if(!strcmp(protocol, ALPN_HTTP_1_1))
599 conn->negnpn = CURL_HTTP_VERSION_1_1;
600 else
601 infof(data, "ALPN, unrecognized protocol %s", protocol);
602 Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
603 BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
604 }
605 else
606 infof(data, "ALPN, server did not agree to a protocol");
607 }
608
609 if(SSL_SET_OPTION(primary.sessionid)) {
610 bool incache;
611 void *oldsession;
612 br_ssl_session_parameters *session;
613
614 session = malloc(sizeof(*session));
615 if(!session)
616 return CURLE_OUT_OF_MEMORY;
617 br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
618 Curl_ssl_sessionid_lock(data);
619 incache = !(Curl_ssl_getsessionid(data, conn,
620 SSL_IS_PROXY() ? TRUE : FALSE,
621 &oldsession, NULL, sockindex));
622 if(incache)
623 Curl_ssl_delsessionid(data, oldsession);
624 ret = Curl_ssl_addsessionid(data, conn,
625 SSL_IS_PROXY() ? TRUE : FALSE,
626 session, 0, sockindex);
627 Curl_ssl_sessionid_unlock(data);
628 if(ret) {
629 free(session);
630 return CURLE_OUT_OF_MEMORY;
631 }
632 }
633
634 connssl->connecting_state = ssl_connect_done;
635
636 return CURLE_OK;
637}
638
639static ssize_t bearssl_send(struct Curl_easy *data, int sockindex,
640 const void *buf, size_t len, CURLcode *err)
641{
642 struct connectdata *conn = data->conn;
643 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
644 struct ssl_backend_data *backend = connssl->backend;
645 unsigned char *app;
646 size_t applen;
647
648 for(;;) {
649 *err = bearssl_run_until(data, conn, sockindex, BR_SSL_SENDAPP);
650 if (*err != CURLE_OK)
651 return -1;
652 app = br_ssl_engine_sendapp_buf(&backend->ctx.eng, &applen);
653 if(!app) {
654 failf(data, "SSL: connection closed during write");
655 *err = CURLE_SEND_ERROR;
656 return -1;
657 }
658 if(backend->pending_write) {
659 applen = backend->pending_write;
660 backend->pending_write = 0;
661 return applen;
662 }
663 if(applen > len)
664 applen = len;
665 memcpy(app, buf, applen);
666 br_ssl_engine_sendapp_ack(&backend->ctx.eng, applen);
667 br_ssl_engine_flush(&backend->ctx.eng, 0);
668 backend->pending_write = applen;
669 }
670}
671
672static ssize_t bearssl_recv(struct Curl_easy *data, int sockindex,
673 char *buf, size_t len, CURLcode *err)
674{
675 struct connectdata *conn = data->conn;
676 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
677 struct ssl_backend_data *backend = connssl->backend;
678 unsigned char *app;
679 size_t applen;
680
681 *err = bearssl_run_until(data, conn, sockindex, BR_SSL_RECVAPP);
682 if(*err != CURLE_OK)
683 return -1;
684 app = br_ssl_engine_recvapp_buf(&backend->ctx.eng, &applen);
685 if(!app)
686 return 0;
687 if(applen > len)
688 applen = len;
689 memcpy(buf, app, applen);
690 br_ssl_engine_recvapp_ack(&backend->ctx.eng, applen);
691
692 return applen;
693}
694
695static CURLcode bearssl_connect_common(struct Curl_easy *data,
696 struct connectdata *conn,
697 int sockindex,
698 bool nonblocking,
699 bool *done)
700{
701 CURLcode ret;
702 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
703 curl_socket_t sockfd = conn->sock[sockindex];
704 timediff_t timeout_ms;
705 int what;
706
707 /* check if the connection has already been established */
708 if(ssl_connection_complete == connssl->state) {
709 *done = TRUE;
710 return CURLE_OK;
711 }
712
713 if(ssl_connect_1 == connssl->connecting_state) {
714 ret = bearssl_connect_step1(data, conn, sockindex);
715 if(ret)
716 return ret;
717 }
718
719 while(ssl_connect_2 == connssl->connecting_state ||
720 ssl_connect_2_reading == connssl->connecting_state ||
721 ssl_connect_2_writing == connssl->connecting_state) {
722 /* check allowed time left */
723 timeout_ms = Curl_timeleft(data, NULL, TRUE);
724
725 if(timeout_ms < 0) {
726 /* no need to continue if time already is up */
727 failf(data, "SSL connection timeout");
728 return CURLE_OPERATION_TIMEDOUT;
729 }
730
731 /* if ssl is expecting something, check if it's available. */
732 if(ssl_connect_2_reading == connssl->connecting_state ||
733 ssl_connect_2_writing == connssl->connecting_state) {
734
735 curl_socket_t writefd = ssl_connect_2_writing ==
736 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
737 curl_socket_t readfd = ssl_connect_2_reading ==
738 connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
739
740 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
741 nonblocking?0:timeout_ms);
742 if(what < 0) {
743 /* fatal error */
744 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
745 return CURLE_SSL_CONNECT_ERROR;
746 }
747 else if(0 == what) {
748 if(nonblocking) {
749 *done = FALSE;
750 return CURLE_OK;
751 }
752 else {
753 /* timeout */
754 failf(data, "SSL connection timeout");
755 return CURLE_OPERATION_TIMEDOUT;
756 }
757 }
758 /* socket is readable or writable */
759 }
760
761 /* Run transaction, and return to the caller if it failed or if this
762 * connection is done nonblocking and this loop would execute again. This
763 * permits the owner of a multi handle to abort a connection attempt
764 * before step2 has completed while ensuring that a client using select()
765 * or epoll() will always have a valid fdset to wait on.
766 */
767 ret = bearssl_connect_step2(data, conn, sockindex);
768 if(ret || (nonblocking &&
769 (ssl_connect_2 == connssl->connecting_state ||
770 ssl_connect_2_reading == connssl->connecting_state ||
771 ssl_connect_2_writing == connssl->connecting_state)))
772 return ret;
773 }
774
775 if(ssl_connect_3 == connssl->connecting_state) {
776 ret = bearssl_connect_step3(data, conn, sockindex);
777 if(ret)
778 return ret;
779 }
780
781 if(ssl_connect_done == connssl->connecting_state) {
782 connssl->state = ssl_connection_complete;
783 conn->recv[sockindex] = bearssl_recv;
784 conn->send[sockindex] = bearssl_send;
785 *done = TRUE;
786 }
787 else
788 *done = FALSE;
789
790 /* Reset our connect state machine */
791 connssl->connecting_state = ssl_connect_1;
792
793 return CURLE_OK;
794}
795
796static size_t bearssl_version(char *buffer, size_t size)
797{
798 return msnprintf(buffer, size, "BearSSL");
799}
800
801static bool bearssl_data_pending(const struct connectdata *conn,
802 int connindex)
803{
804 const struct ssl_connect_data *connssl = &conn->ssl[connindex];
805 struct ssl_backend_data *backend = connssl->backend;
806 return br_ssl_engine_current_state(&backend->ctx.eng) & BR_SSL_RECVAPP;
807}
808
809static CURLcode bearssl_random(struct Curl_easy *data UNUSED_PARAM,
810 unsigned char *entropy, size_t length)
811{
812 static br_hmac_drbg_context ctx;
813 static bool seeded = FALSE;
814
815 if(!seeded) {
816 br_prng_seeder seeder;
817
818 br_hmac_drbg_init(&ctx, &br_sha256_vtable, NULL, 0);
819 seeder = br_prng_seeder_system(NULL);
820 if(!seeder || !seeder(&ctx.vtable))
821 return CURLE_FAILED_INIT;
822 seeded = TRUE;
823 }
824 br_hmac_drbg_generate(&ctx, entropy, length);
825
826 return CURLE_OK;
827}
828
829static CURLcode bearssl_connect(struct Curl_easy *data,
830 struct connectdata *conn, int sockindex)
831{
832 CURLcode ret;
833 bool done = FALSE;
834
835 ret = bearssl_connect_common(data, conn, sockindex, FALSE, &done);
836 if(ret)
837 return ret;
838
839 DEBUGASSERT(done);
840
841 return CURLE_OK;
842}
843
844static CURLcode bearssl_connect_nonblocking(struct Curl_easy *data,
845 struct connectdata *conn,
846 int sockindex, bool *done)
847{
848 return bearssl_connect_common(data, conn, sockindex, TRUE, done);
849}
850
851static void *bearssl_get_internals(struct ssl_connect_data *connssl,
852 CURLINFO info UNUSED_PARAM)
853{
854 struct ssl_backend_data *backend = connssl->backend;
855 return &backend->ctx;
856}
857
858static void bearssl_close(struct Curl_easy *data,
859 struct connectdata *conn, int sockindex)
860{
861 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
862 struct ssl_backend_data *backend = connssl->backend;
863 size_t i;
864
865 if(backend->active) {
866 br_ssl_engine_close(&backend->ctx.eng);
867 (void)bearssl_run_until(data, conn, sockindex, BR_SSL_CLOSED);
868 }
869 for(i = 0; i < backend->anchors_len; ++i)
870 free(backend->anchors[i].dn.data);
871 free(backend->anchors);
872}
873
874static void bearssl_session_free(void *ptr)
875{
876 free(ptr);
877}
878
879static CURLcode bearssl_sha256sum(const unsigned char *input,
880 size_t inputlen,
881 unsigned char *sha256sum,
882 size_t sha256len UNUSED_PARAM)
883{
884 br_sha256_context ctx;
885
886 br_sha256_init(&ctx);
887 br_sha256_update(&ctx, input, inputlen);
888 br_sha256_out(&ctx, sha256sum);
889 return CURLE_OK;
890}
891
892const struct Curl_ssl Curl_ssl_bearssl = {
893 { CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */
894 SSLSUPP_CAINFO_BLOB,
895 sizeof(struct ssl_backend_data),
896
897 Curl_none_init, /* init */
898 Curl_none_cleanup, /* cleanup */
899 bearssl_version, /* version */
900 Curl_none_check_cxn, /* check_cxn */
901 Curl_none_shutdown, /* shutdown */
902 bearssl_data_pending, /* data_pending */
903 bearssl_random, /* random */
904 Curl_none_cert_status_request, /* cert_status_request */
905 bearssl_connect, /* connect */
906 bearssl_connect_nonblocking, /* connect_nonblocking */
907 Curl_ssl_getsock, /* getsock */
908 bearssl_get_internals, /* get_internals */
909 bearssl_close, /* close_one */
910 Curl_none_close_all, /* close_all */
911 bearssl_session_free, /* session_free */
912 Curl_none_set_engine, /* set_engine */
913 Curl_none_set_engine_default, /* set_engine_default */
914 Curl_none_engines_list, /* engines_list */
915 Curl_none_false_start, /* false_start */
916 bearssl_sha256sum, /* sha256sum */
917 NULL, /* associate_connection */
918 NULL /* disassociate_connection */
919};
920
921#endif /* USE_BEARSSL */
922