Annotation of embedaddon/curl/lib/vtls/bearssl.c, revision 1.1
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 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>