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