Return to bearssl.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / vtls |
1.1 ! misho 1: /*************************************************************************** ! 2: * _ _ ____ _ ! 3: * Project ___| | | | _ \| | ! 4: * / __| | | | |_) | | ! 5: * | (__| |_| | _ <| |___ ! 6: * \___|\___/|_| \_\_____| ! 7: * ! 8: * Copyright (C) 2019 - 2020, 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: /* size of pending write, yet to be flushed */ ! 56: size_t pending_write; ! 57: }; ! 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: struct ssl_backend_data *backend = connssl->backend; ! 302: const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); ! 303: const char *hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : ! 304: conn->host.name; ! 305: const bool verifypeer = SSL_CONN_CONFIG(verifypeer); ! 306: const bool verifyhost = SSL_CONN_CONFIG(verifyhost); ! 307: CURLcode ret; ! 308: unsigned version_min, version_max; ! 309: #ifdef ENABLE_IPV6 ! 310: struct in6_addr addr; ! 311: #else ! 312: struct in_addr addr; ! 313: #endif ! 314: ! 315: switch(SSL_CONN_CONFIG(version)) { ! 316: case CURL_SSLVERSION_SSLv2: ! 317: failf(data, "BearSSL does not support SSLv2"); ! 318: return CURLE_SSL_CONNECT_ERROR; ! 319: case CURL_SSLVERSION_SSLv3: ! 320: failf(data, "BearSSL does not support SSLv3"); ! 321: return CURLE_SSL_CONNECT_ERROR; ! 322: case CURL_SSLVERSION_TLSv1_0: ! 323: version_min = BR_TLS10; ! 324: version_max = BR_TLS10; ! 325: break; ! 326: case CURL_SSLVERSION_TLSv1_1: ! 327: version_min = BR_TLS11; ! 328: version_max = BR_TLS11; ! 329: break; ! 330: case CURL_SSLVERSION_TLSv1_2: ! 331: version_min = BR_TLS12; ! 332: version_max = BR_TLS12; ! 333: break; ! 334: case CURL_SSLVERSION_DEFAULT: ! 335: case CURL_SSLVERSION_TLSv1: ! 336: version_min = BR_TLS10; ! 337: version_max = BR_TLS12; ! 338: break; ! 339: default: ! 340: failf(data, "BearSSL: unknown CURLOPT_SSLVERSION"); ! 341: return CURLE_SSL_CONNECT_ERROR; ! 342: } ! 343: ! 344: if(ssl_cafile) { ! 345: ret = load_cafile(ssl_cafile, &backend->anchors, &backend->anchors_len); ! 346: if(ret != CURLE_OK) { ! 347: if(verifypeer) { ! 348: failf(data, "error setting certificate verify locations:\n" ! 349: " CAfile: %s\n", ssl_cafile); ! 350: return ret; ! 351: } ! 352: infof(data, "error setting certificate verify locations," ! 353: " continuing anyway:\n"); ! 354: } ! 355: } ! 356: ! 357: /* initialize SSL context */ ! 358: br_ssl_client_init_full(&backend->ctx, &backend->x509.minimal, ! 359: backend->anchors, backend->anchors_len); ! 360: br_ssl_engine_set_versions(&backend->ctx.eng, version_min, version_max); ! 361: br_ssl_engine_set_buffer(&backend->ctx.eng, backend->buf, ! 362: sizeof(backend->buf), 1); ! 363: ! 364: /* initialize X.509 context */ ! 365: backend->x509.vtable = &x509_vtable; ! 366: backend->x509.verifypeer = verifypeer; ! 367: backend->x509.verifyhost = verifyhost; ! 368: br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable); ! 369: ! 370: if(SSL_SET_OPTION(primary.sessionid)) { ! 371: void *session; ! 372: ! 373: Curl_ssl_sessionid_lock(conn); ! 374: if(!Curl_ssl_getsessionid(conn, &session, NULL, sockindex)) { ! 375: br_ssl_engine_set_session_parameters(&backend->ctx.eng, session); ! 376: infof(data, "BearSSL: re-using session ID\n"); ! 377: } ! 378: Curl_ssl_sessionid_unlock(conn); ! 379: } ! 380: ! 381: if(conn->bits.tls_enable_alpn) { ! 382: int cur = 0; ! 383: ! 384: /* NOTE: when adding more protocols here, increase the size of the ! 385: * protocols array in `struct ssl_backend_data`. ! 386: */ ! 387: ! 388: #ifdef USE_NGHTTP2 ! 389: if(data->set.httpversion >= CURL_HTTP_VERSION_2 && ! 390: (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) { ! 391: backend->protocols[cur++] = NGHTTP2_PROTO_VERSION_ID; ! 392: infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); ! 393: } ! 394: #endif ! 395: ! 396: backend->protocols[cur++] = ALPN_HTTP_1_1; ! 397: infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); ! 398: ! 399: br_ssl_engine_set_protocol_names(&backend->ctx.eng, ! 400: backend->protocols, cur); ! 401: } ! 402: ! 403: if((1 == Curl_inet_pton(AF_INET, hostname, &addr)) ! 404: #ifdef ENABLE_IPV6 ! 405: || (1 == Curl_inet_pton(AF_INET6, hostname, &addr)) ! 406: #endif ! 407: ) { ! 408: if(verifyhost) { ! 409: failf(data, "BearSSL: " ! 410: "host verification of IP address is not supported"); ! 411: return CURLE_PEER_FAILED_VERIFICATION; ! 412: } ! 413: hostname = NULL; ! 414: } ! 415: ! 416: if(!br_ssl_client_reset(&backend->ctx, hostname, 0)) ! 417: return CURLE_FAILED_INIT; ! 418: backend->active = TRUE; ! 419: ! 420: connssl->connecting_state = ssl_connect_2; ! 421: ! 422: return CURLE_OK; ! 423: } ! 424: ! 425: static CURLcode bearssl_run_until(struct connectdata *conn, int sockindex, ! 426: unsigned target) ! 427: { ! 428: struct Curl_easy *data = conn->data; ! 429: struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ! 430: struct ssl_backend_data *backend = connssl->backend; ! 431: curl_socket_t sockfd = conn->sock[sockindex]; ! 432: unsigned state; ! 433: unsigned char *buf; ! 434: size_t len; ! 435: ssize_t ret; ! 436: int err; ! 437: ! 438: for(;;) { ! 439: state = br_ssl_engine_current_state(&backend->ctx.eng); ! 440: if(state & BR_SSL_CLOSED) { ! 441: err = br_ssl_engine_last_error(&backend->ctx.eng); ! 442: switch(err) { ! 443: case BR_ERR_OK: ! 444: /* TLS close notify */ ! 445: if(connssl->state != ssl_connection_complete) { ! 446: failf(data, "SSL: connection closed during handshake"); ! 447: return CURLE_SSL_CONNECT_ERROR; ! 448: } ! 449: return CURLE_OK; ! 450: case BR_ERR_X509_EXPIRED: ! 451: failf(data, "SSL: X.509 verification: " ! 452: "certificate is expired or not yet valid"); ! 453: return CURLE_PEER_FAILED_VERIFICATION; ! 454: case BR_ERR_X509_BAD_SERVER_NAME: ! 455: failf(data, "SSL: X.509 verification: " ! 456: "expected server name was not found in the chain"); ! 457: return CURLE_PEER_FAILED_VERIFICATION; ! 458: case BR_ERR_X509_NOT_TRUSTED: ! 459: failf(data, "SSL: X.509 verification: " ! 460: "chain could not be linked to a trust anchor"); ! 461: return CURLE_PEER_FAILED_VERIFICATION; ! 462: } ! 463: /* X.509 errors are documented to have the range 32..63 */ ! 464: if(err >= 32 && err < 64) ! 465: return CURLE_PEER_FAILED_VERIFICATION; ! 466: return CURLE_SSL_CONNECT_ERROR; ! 467: } ! 468: if(state & target) ! 469: return CURLE_OK; ! 470: if(state & BR_SSL_SENDREC) { ! 471: buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len); ! 472: ret = swrite(sockfd, buf, len); ! 473: if(ret == -1) { ! 474: if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { ! 475: if(connssl->state != ssl_connection_complete) ! 476: connssl->connecting_state = ssl_connect_2_writing; ! 477: return CURLE_AGAIN; ! 478: } ! 479: return CURLE_WRITE_ERROR; ! 480: } ! 481: br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret); ! 482: } ! 483: else if(state & BR_SSL_RECVREC) { ! 484: buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len); ! 485: ret = sread(sockfd, buf, len); ! 486: if(ret == 0) { ! 487: failf(data, "SSL: EOF without close notify"); ! 488: return CURLE_READ_ERROR; ! 489: } ! 490: if(ret == -1) { ! 491: if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { ! 492: if(connssl->state != ssl_connection_complete) ! 493: connssl->connecting_state = ssl_connect_2_reading; ! 494: return CURLE_AGAIN; ! 495: } ! 496: return CURLE_READ_ERROR; ! 497: } ! 498: br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret); ! 499: } ! 500: } ! 501: } ! 502: ! 503: static CURLcode bearssl_connect_step2(struct connectdata *conn, int sockindex) ! 504: { ! 505: struct Curl_easy *data = conn->data; ! 506: struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ! 507: struct ssl_backend_data *backend = connssl->backend; ! 508: CURLcode ret; ! 509: ! 510: ret = bearssl_run_until(conn, sockindex, BR_SSL_SENDAPP | BR_SSL_RECVAPP); ! 511: if(ret == CURLE_AGAIN) ! 512: return CURLE_OK; ! 513: if(ret == CURLE_OK) { ! 514: if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) { ! 515: failf(data, "SSL: connection closed during handshake"); ! 516: return CURLE_SSL_CONNECT_ERROR; ! 517: } ! 518: connssl->connecting_state = ssl_connect_3; ! 519: } ! 520: return ret; ! 521: } ! 522: ! 523: static CURLcode bearssl_connect_step3(struct connectdata *conn, int sockindex) ! 524: { ! 525: struct Curl_easy *data = conn->data; ! 526: struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ! 527: struct ssl_backend_data *backend = connssl->backend; ! 528: CURLcode ret; ! 529: ! 530: DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); ! 531: ! 532: if(conn->bits.tls_enable_alpn) { ! 533: const char *protocol; ! 534: ! 535: protocol = br_ssl_engine_get_selected_protocol(&backend->ctx.eng); ! 536: if(protocol) { ! 537: infof(data, "ALPN, server accepted to use %s\n", protocol); ! 538: ! 539: #ifdef USE_NGHTTP2 ! 540: if(!strcmp(protocol, NGHTTP2_PROTO_VERSION_ID)) ! 541: conn->negnpn = CURL_HTTP_VERSION_2; ! 542: else ! 543: #endif ! 544: if(!strcmp(protocol, ALPN_HTTP_1_1)) ! 545: conn->negnpn = CURL_HTTP_VERSION_1_1; ! 546: else ! 547: infof(data, "ALPN, unrecognized protocol %s\n", protocol); ! 548: Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ? ! 549: BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); ! 550: } ! 551: else ! 552: infof(data, "ALPN, server did not agree to a protocol\n"); ! 553: } ! 554: ! 555: if(SSL_SET_OPTION(primary.sessionid)) { ! 556: bool incache; ! 557: void *oldsession; ! 558: br_ssl_session_parameters *session; ! 559: ! 560: session = malloc(sizeof(*session)); ! 561: if(!session) ! 562: return CURLE_OUT_OF_MEMORY; ! 563: br_ssl_engine_get_session_parameters(&backend->ctx.eng, session); ! 564: Curl_ssl_sessionid_lock(conn); ! 565: incache = !(Curl_ssl_getsessionid(conn, &oldsession, NULL, sockindex)); ! 566: if(incache) ! 567: Curl_ssl_delsessionid(conn, oldsession); ! 568: ret = Curl_ssl_addsessionid(conn, session, 0, sockindex); ! 569: Curl_ssl_sessionid_unlock(conn); ! 570: if(ret) { ! 571: free(session); ! 572: return CURLE_OUT_OF_MEMORY; ! 573: } ! 574: } ! 575: ! 576: connssl->connecting_state = ssl_connect_done; ! 577: ! 578: return CURLE_OK; ! 579: } ! 580: ! 581: static ssize_t bearssl_send(struct connectdata *conn, int sockindex, ! 582: const void *buf, size_t len, CURLcode *err) ! 583: { ! 584: struct Curl_easy *data = conn->data; ! 585: struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ! 586: struct ssl_backend_data *backend = connssl->backend; ! 587: unsigned char *app; ! 588: size_t applen; ! 589: ! 590: for(;;) { ! 591: *err = bearssl_run_until(conn, sockindex, BR_SSL_SENDAPP); ! 592: if (*err != CURLE_OK) ! 593: return -1; ! 594: app = br_ssl_engine_sendapp_buf(&backend->ctx.eng, &applen); ! 595: if(!app) { ! 596: failf(data, "SSL: connection closed during write"); ! 597: *err = CURLE_SEND_ERROR; ! 598: return -1; ! 599: } ! 600: if(backend->pending_write) { ! 601: applen = backend->pending_write; ! 602: backend->pending_write = 0; ! 603: return applen; ! 604: } ! 605: if(applen > len) ! 606: applen = len; ! 607: memcpy(app, buf, applen); ! 608: br_ssl_engine_sendapp_ack(&backend->ctx.eng, applen); ! 609: br_ssl_engine_flush(&backend->ctx.eng, 0); ! 610: backend->pending_write = applen; ! 611: } ! 612: } ! 613: ! 614: static ssize_t bearssl_recv(struct connectdata *conn, int sockindex, ! 615: char *buf, size_t len, CURLcode *err) ! 616: { ! 617: struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ! 618: struct ssl_backend_data *backend = connssl->backend; ! 619: unsigned char *app; ! 620: size_t applen; ! 621: ! 622: *err = bearssl_run_until(conn, sockindex, BR_SSL_RECVAPP); ! 623: if(*err != CURLE_OK) ! 624: return -1; ! 625: app = br_ssl_engine_recvapp_buf(&backend->ctx.eng, &applen); ! 626: if(!app) ! 627: return 0; ! 628: if(applen > len) ! 629: applen = len; ! 630: memcpy(buf, app, applen); ! 631: br_ssl_engine_recvapp_ack(&backend->ctx.eng, applen); ! 632: ! 633: return applen; ! 634: } ! 635: ! 636: static CURLcode bearssl_connect_common(struct connectdata *conn, ! 637: int sockindex, ! 638: bool nonblocking, ! 639: bool *done) ! 640: { ! 641: CURLcode ret; ! 642: struct Curl_easy *data = conn->data; ! 643: struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ! 644: curl_socket_t sockfd = conn->sock[sockindex]; ! 645: time_t timeout_ms; ! 646: int what; ! 647: ! 648: /* check if the connection has already been established */ ! 649: if(ssl_connection_complete == connssl->state) { ! 650: *done = TRUE; ! 651: return CURLE_OK; ! 652: } ! 653: ! 654: if(ssl_connect_1 == connssl->connecting_state) { ! 655: ret = bearssl_connect_step1(conn, sockindex); ! 656: if(ret) ! 657: return ret; ! 658: } ! 659: ! 660: while(ssl_connect_2 == connssl->connecting_state || ! 661: ssl_connect_2_reading == connssl->connecting_state || ! 662: ssl_connect_2_writing == connssl->connecting_state) { ! 663: /* check allowed time left */ ! 664: timeout_ms = Curl_timeleft(data, NULL, TRUE); ! 665: ! 666: if(timeout_ms < 0) { ! 667: /* no need to continue if time already is up */ ! 668: failf(data, "SSL connection timeout"); ! 669: return CURLE_OPERATION_TIMEDOUT; ! 670: } ! 671: ! 672: /* if ssl is expecting something, check if it's available. */ ! 673: if(ssl_connect_2_reading == connssl->connecting_state || ! 674: ssl_connect_2_writing == connssl->connecting_state) { ! 675: ! 676: curl_socket_t writefd = ssl_connect_2_writing == ! 677: connssl->connecting_state?sockfd:CURL_SOCKET_BAD; ! 678: curl_socket_t readfd = ssl_connect_2_reading == ! 679: connssl->connecting_state?sockfd:CURL_SOCKET_BAD; ! 680: ! 681: what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, ! 682: nonblocking?0:timeout_ms); ! 683: if(what < 0) { ! 684: /* fatal error */ ! 685: failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); ! 686: return CURLE_SSL_CONNECT_ERROR; ! 687: } ! 688: else if(0 == what) { ! 689: if(nonblocking) { ! 690: *done = FALSE; ! 691: return CURLE_OK; ! 692: } ! 693: else { ! 694: /* timeout */ ! 695: failf(data, "SSL connection timeout"); ! 696: return CURLE_OPERATION_TIMEDOUT; ! 697: } ! 698: } ! 699: /* socket is readable or writable */ ! 700: } ! 701: ! 702: /* Run transaction, and return to the caller if it failed or if this ! 703: * connection is done nonblocking and this loop would execute again. This ! 704: * permits the owner of a multi handle to abort a connection attempt ! 705: * before step2 has completed while ensuring that a client using select() ! 706: * or epoll() will always have a valid fdset to wait on. ! 707: */ ! 708: ret = bearssl_connect_step2(conn, sockindex); ! 709: if(ret || (nonblocking && ! 710: (ssl_connect_2 == connssl->connecting_state || ! 711: ssl_connect_2_reading == connssl->connecting_state || ! 712: ssl_connect_2_writing == connssl->connecting_state))) ! 713: return ret; ! 714: } ! 715: ! 716: if(ssl_connect_3 == connssl->connecting_state) { ! 717: ret = bearssl_connect_step3(conn, sockindex); ! 718: if(ret) ! 719: return ret; ! 720: } ! 721: ! 722: if(ssl_connect_done == connssl->connecting_state) { ! 723: connssl->state = ssl_connection_complete; ! 724: conn->recv[sockindex] = bearssl_recv; ! 725: conn->send[sockindex] = bearssl_send; ! 726: *done = TRUE; ! 727: } ! 728: else ! 729: *done = FALSE; ! 730: ! 731: /* Reset our connect state machine */ ! 732: connssl->connecting_state = ssl_connect_1; ! 733: ! 734: return CURLE_OK; ! 735: } ! 736: ! 737: static size_t Curl_bearssl_version(char *buffer, size_t size) ! 738: { ! 739: return msnprintf(buffer, size, "BearSSL"); ! 740: } ! 741: ! 742: static bool Curl_bearssl_data_pending(const struct connectdata *conn, ! 743: int connindex) ! 744: { ! 745: const struct ssl_connect_data *connssl = &conn->ssl[connindex]; ! 746: struct ssl_backend_data *backend = connssl->backend; ! 747: return br_ssl_engine_current_state(&backend->ctx.eng) & BR_SSL_RECVAPP; ! 748: } ! 749: ! 750: static CURLcode Curl_bearssl_random(struct Curl_easy *data UNUSED_PARAM, ! 751: unsigned char *entropy, size_t length) ! 752: { ! 753: static br_hmac_drbg_context ctx; ! 754: static bool seeded = FALSE; ! 755: ! 756: if(!seeded) { ! 757: br_prng_seeder seeder; ! 758: ! 759: br_hmac_drbg_init(&ctx, &br_sha256_vtable, NULL, 0); ! 760: seeder = br_prng_seeder_system(NULL); ! 761: if(!seeder || !seeder(&ctx.vtable)) ! 762: return CURLE_FAILED_INIT; ! 763: seeded = TRUE; ! 764: } ! 765: br_hmac_drbg_generate(&ctx, entropy, length); ! 766: ! 767: return CURLE_OK; ! 768: } ! 769: ! 770: static CURLcode Curl_bearssl_connect(struct connectdata *conn, int sockindex) ! 771: { ! 772: CURLcode ret; ! 773: bool done = FALSE; ! 774: ! 775: ret = bearssl_connect_common(conn, sockindex, FALSE, &done); ! 776: if(ret) ! 777: return ret; ! 778: ! 779: DEBUGASSERT(done); ! 780: ! 781: return CURLE_OK; ! 782: } ! 783: ! 784: static CURLcode Curl_bearssl_connect_nonblocking(struct connectdata *conn, ! 785: int sockindex, bool *done) ! 786: { ! 787: return bearssl_connect_common(conn, sockindex, TRUE, done); ! 788: } ! 789: ! 790: static void *Curl_bearssl_get_internals(struct ssl_connect_data *connssl, ! 791: CURLINFO info UNUSED_PARAM) ! 792: { ! 793: struct ssl_backend_data *backend = connssl->backend; ! 794: return &backend->ctx; ! 795: } ! 796: ! 797: static void Curl_bearssl_close(struct connectdata *conn, int sockindex) ! 798: { ! 799: struct ssl_connect_data *connssl = &conn->ssl[sockindex]; ! 800: struct ssl_backend_data *backend = connssl->backend; ! 801: size_t i; ! 802: ! 803: if(backend->active) { ! 804: br_ssl_engine_close(&backend->ctx.eng); ! 805: (void)bearssl_run_until(conn, sockindex, BR_SSL_CLOSED); ! 806: } ! 807: for(i = 0; i < backend->anchors_len; ++i) ! 808: free(backend->anchors[i].dn.data); ! 809: free(backend->anchors); ! 810: } ! 811: ! 812: static void Curl_bearssl_session_free(void *ptr) ! 813: { ! 814: free(ptr); ! 815: } ! 816: ! 817: static CURLcode Curl_bearssl_md5sum(unsigned char *input, ! 818: size_t inputlen, ! 819: unsigned char *md5sum, ! 820: size_t md5len UNUSED_PARAM) ! 821: { ! 822: br_md5_context ctx; ! 823: ! 824: br_md5_init(&ctx); ! 825: br_md5_update(&ctx, input, inputlen); ! 826: br_md5_out(&ctx, md5sum); ! 827: return CURLE_OK; ! 828: } ! 829: ! 830: static CURLcode Curl_bearssl_sha256sum(const unsigned char *input, ! 831: size_t inputlen, ! 832: unsigned char *sha256sum, ! 833: size_t sha256len UNUSED_PARAM) ! 834: { ! 835: br_sha256_context ctx; ! 836: ! 837: br_sha256_init(&ctx); ! 838: br_sha256_update(&ctx, input, inputlen); ! 839: br_sha256_out(&ctx, sha256sum); ! 840: return CURLE_OK; ! 841: } ! 842: ! 843: const struct Curl_ssl Curl_ssl_bearssl = { ! 844: { CURLSSLBACKEND_BEARSSL, "bearssl" }, ! 845: 0, ! 846: sizeof(struct ssl_backend_data), ! 847: ! 848: Curl_none_init, ! 849: Curl_none_cleanup, ! 850: Curl_bearssl_version, ! 851: Curl_none_check_cxn, ! 852: Curl_none_shutdown, ! 853: Curl_bearssl_data_pending, ! 854: Curl_bearssl_random, ! 855: Curl_none_cert_status_request, ! 856: Curl_bearssl_connect, ! 857: Curl_bearssl_connect_nonblocking, ! 858: Curl_bearssl_get_internals, ! 859: Curl_bearssl_close, ! 860: Curl_none_close_all, ! 861: Curl_bearssl_session_free, ! 862: Curl_none_set_engine, ! 863: Curl_none_set_engine_default, ! 864: Curl_none_engines_list, ! 865: Curl_none_false_start, ! 866: Curl_bearssl_md5sum, ! 867: Curl_bearssl_sha256sum ! 868: }; ! 869: ! 870: #endif /* USE_BEARSSL */