Annotation of embedaddon/curl/lib/vtls/wolfssl.c, revision 1.1
1.1 ! misho 1: /***************************************************************************
! 2: * _ _ ____ _
! 3: * Project ___| | | | _ \| |
! 4: * / __| | | | |_) | |
! 5: * | (__| |_| | _ <| |___
! 6: * \___|\___/|_| \_\_____|
! 7: *
! 8: * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
! 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:
! 23: /*
! 24: * Source file for all wolfSSL specific code for the TLS/SSL layer. No code
! 25: * but vtls.c should ever call or use these functions.
! 26: *
! 27: */
! 28:
! 29: #include "curl_setup.h"
! 30:
! 31: #ifdef USE_WOLFSSL
! 32:
! 33: #define WOLFSSL_OPTIONS_IGNORE_SYS
! 34: #include <wolfssl/version.h>
! 35: #include <wolfssl/options.h>
! 36:
! 37: /* To determine what functions are available we rely on one or both of:
! 38: - the user's options.h generated by wolfSSL
! 39: - the symbols detected by curl's configure
! 40: Since they are markedly different from one another, and one or the other may
! 41: not be available, we do some checking below to bring things in sync. */
! 42:
! 43: /* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */
! 44: #ifndef HAVE_ALPN
! 45: #ifdef HAVE_WOLFSSL_USEALPN
! 46: #define HAVE_ALPN
! 47: #endif
! 48: #endif
! 49:
! 50: /* WOLFSSL_ALLOW_SSLV3 is wolfSSL's build time symbol for enabling SSLv3 in
! 51: options.h, but is only seen in >= 3.6.6 since that's when they started
! 52: disabling SSLv3 by default. */
! 53: #ifndef WOLFSSL_ALLOW_SSLV3
! 54: #if (LIBWOLFSSL_VERSION_HEX < 0x03006006) || \
! 55: defined(HAVE_WOLFSSLV3_CLIENT_METHOD)
! 56: #define WOLFSSL_ALLOW_SSLV3
! 57: #endif
! 58: #endif
! 59:
! 60: #include <limits.h>
! 61:
! 62: #include "urldata.h"
! 63: #include "sendf.h"
! 64: #include "inet_pton.h"
! 65: #include "vtls.h"
! 66: #include "parsedate.h"
! 67: #include "connect.h" /* for the connect timeout */
! 68: #include "select.h"
! 69: #include "strcase.h"
! 70: #include "x509asn1.h"
! 71: #include "curl_printf.h"
! 72: #include "multiif.h"
! 73:
! 74: #include <wolfssl/openssl/ssl.h>
! 75: #include <wolfssl/ssl.h>
! 76: #include <wolfssl/error-ssl.h>
! 77: #include "wolfssl.h"
! 78:
! 79: /* The last #include files should be: */
! 80: #include "curl_memory.h"
! 81: #include "memdebug.h"
! 82:
! 83: /* KEEP_PEER_CERT is a product of the presence of build time symbol
! 84: OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
! 85: in wolfSSL's settings.h, and the latter two are build time symbols in
! 86: options.h. */
! 87: #ifndef KEEP_PEER_CERT
! 88: #if defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \
! 89: (defined(OPENSSL_EXTRA) && !defined(NO_CERTS))
! 90: #define KEEP_PEER_CERT
! 91: #endif
! 92: #endif
! 93:
! 94: struct ssl_backend_data {
! 95: SSL_CTX* ctx;
! 96: SSL* handle;
! 97: };
! 98:
! 99: static Curl_recv wolfssl_recv;
! 100: static Curl_send wolfssl_send;
! 101:
! 102: static int do_file_type(const char *type)
! 103: {
! 104: if(!type || !type[0])
! 105: return SSL_FILETYPE_PEM;
! 106: if(strcasecompare(type, "PEM"))
! 107: return SSL_FILETYPE_PEM;
! 108: if(strcasecompare(type, "DER"))
! 109: return SSL_FILETYPE_ASN1;
! 110: return -1;
! 111: }
! 112:
! 113: /*
! 114: * This function loads all the client/CA certificates and CRLs. Setup the TLS
! 115: * layer and do all necessary magic.
! 116: */
! 117: static CURLcode
! 118: wolfssl_connect_step1(struct connectdata *conn,
! 119: int sockindex)
! 120: {
! 121: char *ciphers;
! 122: struct Curl_easy *data = conn->data;
! 123: struct ssl_connect_data* connssl = &conn->ssl[sockindex];
! 124: struct ssl_backend_data *backend = connssl->backend;
! 125: SSL_METHOD* req_method = NULL;
! 126: curl_socket_t sockfd = conn->sock[sockindex];
! 127: #ifdef HAVE_SNI
! 128: bool sni = FALSE;
! 129: #define use_sni(x) sni = (x)
! 130: #else
! 131: #define use_sni(x) Curl_nop_stmt
! 132: #endif
! 133:
! 134: if(connssl->state == ssl_connection_complete)
! 135: return CURLE_OK;
! 136:
! 137: if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
! 138: failf(data, "wolfSSL does not support to set maximum SSL/TLS version");
! 139: return CURLE_SSL_CONNECT_ERROR;
! 140: }
! 141:
! 142: /* check to see if we've been told to use an explicit SSL/TLS version */
! 143: switch(SSL_CONN_CONFIG(version)) {
! 144: case CURL_SSLVERSION_DEFAULT:
! 145: case CURL_SSLVERSION_TLSv1:
! 146: #if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
! 147: /* minimum protocol version is set later after the CTX object is created */
! 148: req_method = SSLv23_client_method();
! 149: #else
! 150: infof(data, "wolfSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
! 151: "TLS 1.0 is used exclusively\n");
! 152: req_method = TLSv1_client_method();
! 153: #endif
! 154: use_sni(TRUE);
! 155: break;
! 156: case CURL_SSLVERSION_TLSv1_0:
! 157: #ifdef WOLFSSL_ALLOW_TLSV10
! 158: req_method = TLSv1_client_method();
! 159: use_sni(TRUE);
! 160: #else
! 161: failf(data, "wolfSSL does not support TLS 1.0");
! 162: return CURLE_NOT_BUILT_IN;
! 163: #endif
! 164: break;
! 165: case CURL_SSLVERSION_TLSv1_1:
! 166: req_method = TLSv1_1_client_method();
! 167: use_sni(TRUE);
! 168: break;
! 169: case CURL_SSLVERSION_TLSv1_2:
! 170: req_method = TLSv1_2_client_method();
! 171: use_sni(TRUE);
! 172: break;
! 173: case CURL_SSLVERSION_TLSv1_3:
! 174: #ifdef WOLFSSL_TLS13
! 175: req_method = wolfTLSv1_3_client_method();
! 176: use_sni(TRUE);
! 177: break;
! 178: #else
! 179: failf(data, "wolfSSL: TLS 1.3 is not yet supported");
! 180: return CURLE_SSL_CONNECT_ERROR;
! 181: #endif
! 182: case CURL_SSLVERSION_SSLv3:
! 183: #ifdef WOLFSSL_ALLOW_SSLV3
! 184: req_method = SSLv3_client_method();
! 185: use_sni(FALSE);
! 186: #else
! 187: failf(data, "wolfSSL does not support SSLv3");
! 188: return CURLE_NOT_BUILT_IN;
! 189: #endif
! 190: break;
! 191: case CURL_SSLVERSION_SSLv2:
! 192: failf(data, "wolfSSL does not support SSLv2");
! 193: return CURLE_SSL_CONNECT_ERROR;
! 194: default:
! 195: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
! 196: return CURLE_SSL_CONNECT_ERROR;
! 197: }
! 198:
! 199: if(!req_method) {
! 200: failf(data, "SSL: couldn't create a method!");
! 201: return CURLE_OUT_OF_MEMORY;
! 202: }
! 203:
! 204: if(backend->ctx)
! 205: SSL_CTX_free(backend->ctx);
! 206: backend->ctx = SSL_CTX_new(req_method);
! 207:
! 208: if(!backend->ctx) {
! 209: failf(data, "SSL: couldn't create a context!");
! 210: return CURLE_OUT_OF_MEMORY;
! 211: }
! 212:
! 213: switch(SSL_CONN_CONFIG(version)) {
! 214: case CURL_SSLVERSION_DEFAULT:
! 215: case CURL_SSLVERSION_TLSv1:
! 216: #if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
! 217: /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is
! 218: * whatever minimum version of TLS was built in and at least TLS 1.0. For
! 219: * later library versions that could change (eg TLS 1.0 built in but
! 220: * defaults to TLS 1.1) so we have this short circuit evaluation to find
! 221: * the minimum supported TLS version.
! 222: */
! 223: if((wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1) != 1) &&
! 224: (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_1) != 1) &&
! 225: (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_2) != 1)
! 226: #ifdef WOLFSSL_TLS13
! 227: && (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_3) != 1)
! 228: #endif
! 229: ) {
! 230: failf(data, "SSL: couldn't set the minimum protocol version");
! 231: return CURLE_SSL_CONNECT_ERROR;
! 232: }
! 233: #endif
! 234: break;
! 235: }
! 236:
! 237: ciphers = SSL_CONN_CONFIG(cipher_list);
! 238: if(ciphers) {
! 239: if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
! 240: failf(data, "failed setting cipher list: %s", ciphers);
! 241: return CURLE_SSL_CIPHER;
! 242: }
! 243: infof(data, "Cipher selection: %s\n", ciphers);
! 244: }
! 245:
! 246: #ifndef NO_FILESYSTEM
! 247: /* load trusted cacert */
! 248: if(SSL_CONN_CONFIG(CAfile)) {
! 249: if(1 != SSL_CTX_load_verify_locations(backend->ctx,
! 250: SSL_CONN_CONFIG(CAfile),
! 251: SSL_CONN_CONFIG(CApath))) {
! 252: if(SSL_CONN_CONFIG(verifypeer)) {
! 253: /* Fail if we insist on successfully verifying the server. */
! 254: failf(data, "error setting certificate verify locations:\n"
! 255: " CAfile: %s\n CApath: %s",
! 256: SSL_CONN_CONFIG(CAfile)?
! 257: SSL_CONN_CONFIG(CAfile): "none",
! 258: SSL_CONN_CONFIG(CApath)?
! 259: SSL_CONN_CONFIG(CApath) : "none");
! 260: return CURLE_SSL_CACERT_BADFILE;
! 261: }
! 262: else {
! 263: /* Just continue with a warning if no strict certificate
! 264: verification is required. */
! 265: infof(data, "error setting certificate verify locations,"
! 266: " continuing anyway:\n");
! 267: }
! 268: }
! 269: else {
! 270: /* Everything is fine. */
! 271: infof(data, "successfully set certificate verify locations:\n");
! 272: }
! 273: infof(data,
! 274: " CAfile: %s\n"
! 275: " CApath: %s\n",
! 276: SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
! 277: "none",
! 278: SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath):
! 279: "none");
! 280: }
! 281:
! 282: /* Load the client certificate, and private key */
! 283: if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) {
! 284: int file_type = do_file_type(SSL_SET_OPTION(cert_type));
! 285:
! 286: if(SSL_CTX_use_certificate_file(backend->ctx, SSL_SET_OPTION(cert),
! 287: file_type) != 1) {
! 288: failf(data, "unable to use client certificate (no key or wrong pass"
! 289: " phrase?)");
! 290: return CURLE_SSL_CONNECT_ERROR;
! 291: }
! 292:
! 293: file_type = do_file_type(SSL_SET_OPTION(key_type));
! 294: if(SSL_CTX_use_PrivateKey_file(backend->ctx, SSL_SET_OPTION(key),
! 295: file_type) != 1) {
! 296: failf(data, "unable to set private key");
! 297: return CURLE_SSL_CONNECT_ERROR;
! 298: }
! 299: }
! 300: #endif /* !NO_FILESYSTEM */
! 301:
! 302: /* SSL always tries to verify the peer, this only says whether it should
! 303: * fail to connect if the verification fails, or if it should continue
! 304: * anyway. In the latter case the result of the verification is checked with
! 305: * SSL_get_verify_result() below. */
! 306: SSL_CTX_set_verify(backend->ctx,
! 307: SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER:
! 308: SSL_VERIFY_NONE,
! 309: NULL);
! 310:
! 311: #ifdef HAVE_SNI
! 312: if(sni) {
! 313: struct in_addr addr4;
! 314: #ifdef ENABLE_IPV6
! 315: struct in6_addr addr6;
! 316: #endif
! 317: const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
! 318: conn->host.name;
! 319: size_t hostname_len = strlen(hostname);
! 320: if((hostname_len < USHRT_MAX) &&
! 321: (0 == Curl_inet_pton(AF_INET, hostname, &addr4)) &&
! 322: #ifdef ENABLE_IPV6
! 323: (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) &&
! 324: #endif
! 325: (wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, hostname,
! 326: (unsigned short)hostname_len) != 1)) {
! 327: infof(data, "WARNING: failed to configure server name indication (SNI) "
! 328: "TLS extension\n");
! 329: }
! 330: }
! 331: #endif
! 332:
! 333: /* give application a chance to interfere with SSL set up. */
! 334: if(data->set.ssl.fsslctx) {
! 335: CURLcode result = (*data->set.ssl.fsslctx)(data, backend->ctx,
! 336: data->set.ssl.fsslctxp);
! 337: if(result) {
! 338: failf(data, "error signaled by ssl ctx callback");
! 339: return result;
! 340: }
! 341: }
! 342: #ifdef NO_FILESYSTEM
! 343: else if(SSL_CONN_CONFIG(verifypeer)) {
! 344: failf(data, "SSL: Certificates can't be loaded because wolfSSL was built"
! 345: " with \"no filesystem\". Either disable peer verification"
! 346: " (insecure) or if you are building an application with libcurl you"
! 347: " can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
! 348: return CURLE_SSL_CONNECT_ERROR;
! 349: }
! 350: #endif
! 351:
! 352: /* Let's make an SSL structure */
! 353: if(backend->handle)
! 354: SSL_free(backend->handle);
! 355: backend->handle = SSL_new(backend->ctx);
! 356: if(!backend->handle) {
! 357: failf(data, "SSL: couldn't create a context (handle)!");
! 358: return CURLE_OUT_OF_MEMORY;
! 359: }
! 360:
! 361: #ifdef HAVE_ALPN
! 362: if(conn->bits.tls_enable_alpn) {
! 363: char protocols[128];
! 364: *protocols = '\0';
! 365:
! 366: /* wolfSSL's ALPN protocol name list format is a comma separated string of
! 367: protocols in descending order of preference, eg: "h2,http/1.1" */
! 368:
! 369: #ifdef USE_NGHTTP2
! 370: if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
! 371: strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ",");
! 372: infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
! 373: }
! 374: #endif
! 375:
! 376: strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1);
! 377: infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
! 378:
! 379: if(wolfSSL_UseALPN(backend->handle, protocols,
! 380: (unsigned)strlen(protocols),
! 381: WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
! 382: failf(data, "SSL: failed setting ALPN protocols");
! 383: return CURLE_SSL_CONNECT_ERROR;
! 384: }
! 385: }
! 386: #endif /* HAVE_ALPN */
! 387:
! 388: /* Check if there's a cached ID we can/should use here! */
! 389: if(SSL_SET_OPTION(primary.sessionid)) {
! 390: void *ssl_sessionid = NULL;
! 391:
! 392: Curl_ssl_sessionid_lock(conn);
! 393: if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
! 394: /* we got a session id, use it! */
! 395: if(!SSL_set_session(backend->handle, ssl_sessionid)) {
! 396: char error_buffer[WOLFSSL_MAX_ERROR_SZ];
! 397: Curl_ssl_sessionid_unlock(conn);
! 398: failf(data, "SSL: SSL_set_session failed: %s",
! 399: ERR_error_string(SSL_get_error(backend->handle, 0),
! 400: error_buffer));
! 401: return CURLE_SSL_CONNECT_ERROR;
! 402: }
! 403: /* Informational message */
! 404: infof(data, "SSL re-using session ID\n");
! 405: }
! 406: Curl_ssl_sessionid_unlock(conn);
! 407: }
! 408:
! 409: /* pass the raw socket into the SSL layer */
! 410: if(!SSL_set_fd(backend->handle, (int)sockfd)) {
! 411: failf(data, "SSL: SSL_set_fd failed");
! 412: return CURLE_SSL_CONNECT_ERROR;
! 413: }
! 414:
! 415: connssl->connecting_state = ssl_connect_2;
! 416: return CURLE_OK;
! 417: }
! 418:
! 419:
! 420: static CURLcode
! 421: wolfssl_connect_step2(struct connectdata *conn,
! 422: int sockindex)
! 423: {
! 424: int ret = -1;
! 425: struct Curl_easy *data = conn->data;
! 426: struct ssl_connect_data* connssl = &conn->ssl[sockindex];
! 427: struct ssl_backend_data *backend = connssl->backend;
! 428: const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
! 429: conn->host.name;
! 430: const char * const dispname = SSL_IS_PROXY() ?
! 431: conn->http_proxy.host.dispname : conn->host.dispname;
! 432: const char * const pinnedpubkey = SSL_IS_PROXY() ?
! 433: data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
! 434: data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
! 435:
! 436: conn->recv[sockindex] = wolfssl_recv;
! 437: conn->send[sockindex] = wolfssl_send;
! 438:
! 439: /* Enable RFC2818 checks */
! 440: if(SSL_CONN_CONFIG(verifyhost)) {
! 441: ret = wolfSSL_check_domain_name(backend->handle, hostname);
! 442: if(ret == SSL_FAILURE)
! 443: return CURLE_OUT_OF_MEMORY;
! 444: }
! 445:
! 446: ret = SSL_connect(backend->handle);
! 447: if(ret != 1) {
! 448: char error_buffer[WOLFSSL_MAX_ERROR_SZ];
! 449: int detail = SSL_get_error(backend->handle, ret);
! 450:
! 451: if(SSL_ERROR_WANT_READ == detail) {
! 452: connssl->connecting_state = ssl_connect_2_reading;
! 453: return CURLE_OK;
! 454: }
! 455: else if(SSL_ERROR_WANT_WRITE == detail) {
! 456: connssl->connecting_state = ssl_connect_2_writing;
! 457: return CURLE_OK;
! 458: }
! 459: /* There is no easy way to override only the CN matching.
! 460: * This will enable the override of both mismatching SubjectAltNames
! 461: * as also mismatching CN fields */
! 462: else if(DOMAIN_NAME_MISMATCH == detail) {
! 463: #if 1
! 464: failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n",
! 465: dispname);
! 466: return CURLE_PEER_FAILED_VERIFICATION;
! 467: #else
! 468: /* When the wolfssl_check_domain_name() is used and you desire to
! 469: * continue on a DOMAIN_NAME_MISMATCH, i.e. 'conn->ssl_config.verifyhost
! 470: * == 0', CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA
! 471: * error. The only way to do this is currently to switch the
! 472: * Wolfssl_check_domain_name() in and out based on the
! 473: * 'conn->ssl_config.verifyhost' value. */
! 474: if(SSL_CONN_CONFIG(verifyhost)) {
! 475: failf(data,
! 476: "\tsubject alt name(s) or common name do not match \"%s\"\n",
! 477: dispname);
! 478: return CURLE_PEER_FAILED_VERIFICATION;
! 479: }
! 480: else {
! 481: infof(data,
! 482: "\tsubject alt name(s) and/or common name do not match \"%s\"\n",
! 483: dispname);
! 484: return CURLE_OK;
! 485: }
! 486: #endif
! 487: }
! 488: #if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
! 489: else if(ASN_NO_SIGNER_E == detail) {
! 490: if(SSL_CONN_CONFIG(verifypeer)) {
! 491: failf(data, "\tCA signer not available for verification\n");
! 492: return CURLE_SSL_CACERT_BADFILE;
! 493: }
! 494: else {
! 495: /* Just continue with a warning if no strict certificate
! 496: verification is required. */
! 497: infof(data, "CA signer not available for verification, "
! 498: "continuing anyway\n");
! 499: }
! 500: }
! 501: #endif
! 502: else {
! 503: failf(data, "SSL_connect failed with error %d: %s", detail,
! 504: ERR_error_string(detail, error_buffer));
! 505: return CURLE_SSL_CONNECT_ERROR;
! 506: }
! 507: }
! 508:
! 509: if(pinnedpubkey) {
! 510: #ifdef KEEP_PEER_CERT
! 511: X509 *x509;
! 512: const char *x509_der;
! 513: int x509_der_len;
! 514: curl_X509certificate x509_parsed;
! 515: curl_asn1Element *pubkey;
! 516: CURLcode result;
! 517:
! 518: x509 = SSL_get_peer_certificate(backend->handle);
! 519: if(!x509) {
! 520: failf(data, "SSL: failed retrieving server certificate");
! 521: return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
! 522: }
! 523:
! 524: x509_der = (const char *)wolfSSL_X509_get_der(x509, &x509_der_len);
! 525: if(!x509_der) {
! 526: failf(data, "SSL: failed retrieving ASN.1 server certificate");
! 527: return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
! 528: }
! 529:
! 530: memset(&x509_parsed, 0, sizeof(x509_parsed));
! 531: if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
! 532: return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
! 533:
! 534: pubkey = &x509_parsed.subjectPublicKeyInfo;
! 535: if(!pubkey->header || pubkey->end <= pubkey->header) {
! 536: failf(data, "SSL: failed retrieving public key from server certificate");
! 537: return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
! 538: }
! 539:
! 540: result = Curl_pin_peer_pubkey(data,
! 541: pinnedpubkey,
! 542: (const unsigned char *)pubkey->header,
! 543: (size_t)(pubkey->end - pubkey->header));
! 544: if(result) {
! 545: failf(data, "SSL: public key does not match pinned public key!");
! 546: return result;
! 547: }
! 548: #else
! 549: failf(data, "Library lacks pinning support built-in");
! 550: return CURLE_NOT_BUILT_IN;
! 551: #endif
! 552: }
! 553:
! 554: #ifdef HAVE_ALPN
! 555: if(conn->bits.tls_enable_alpn) {
! 556: int rc;
! 557: char *protocol = NULL;
! 558: unsigned short protocol_len = 0;
! 559:
! 560: rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len);
! 561:
! 562: if(rc == SSL_SUCCESS) {
! 563: infof(data, "ALPN, server accepted to use %.*s\n", protocol_len,
! 564: protocol);
! 565:
! 566: if(protocol_len == ALPN_HTTP_1_1_LENGTH &&
! 567: !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH))
! 568: conn->negnpn = CURL_HTTP_VERSION_1_1;
! 569: #ifdef USE_NGHTTP2
! 570: else if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
! 571: protocol_len == NGHTTP2_PROTO_VERSION_ID_LEN &&
! 572: !memcmp(protocol, NGHTTP2_PROTO_VERSION_ID,
! 573: NGHTTP2_PROTO_VERSION_ID_LEN))
! 574: conn->negnpn = CURL_HTTP_VERSION_2;
! 575: #endif
! 576: else
! 577: infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len,
! 578: protocol);
! 579: Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
! 580: BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
! 581: }
! 582: else if(rc == SSL_ALPN_NOT_FOUND)
! 583: infof(data, "ALPN, server did not agree to a protocol\n");
! 584: else {
! 585: failf(data, "ALPN, failure getting protocol, error %d", rc);
! 586: return CURLE_SSL_CONNECT_ERROR;
! 587: }
! 588: }
! 589: #endif /* HAVE_ALPN */
! 590:
! 591: connssl->connecting_state = ssl_connect_3;
! 592: #if (LIBWOLFSSL_VERSION_HEX >= 0x03009010)
! 593: infof(data, "SSL connection using %s / %s\n",
! 594: wolfSSL_get_version(backend->handle),
! 595: wolfSSL_get_cipher_name(backend->handle));
! 596: #else
! 597: infof(data, "SSL connected\n");
! 598: #endif
! 599:
! 600: return CURLE_OK;
! 601: }
! 602:
! 603:
! 604: static CURLcode
! 605: wolfssl_connect_step3(struct connectdata *conn,
! 606: int sockindex)
! 607: {
! 608: CURLcode result = CURLE_OK;
! 609: struct Curl_easy *data = conn->data;
! 610: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
! 611: struct ssl_backend_data *backend = connssl->backend;
! 612:
! 613: DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
! 614:
! 615: if(SSL_SET_OPTION(primary.sessionid)) {
! 616: bool incache;
! 617: SSL_SESSION *our_ssl_sessionid;
! 618: void *old_ssl_sessionid = NULL;
! 619:
! 620: our_ssl_sessionid = SSL_get_session(backend->handle);
! 621:
! 622: Curl_ssl_sessionid_lock(conn);
! 623: incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL,
! 624: sockindex));
! 625: if(incache) {
! 626: if(old_ssl_sessionid != our_ssl_sessionid) {
! 627: infof(data, "old SSL session ID is stale, removing\n");
! 628: Curl_ssl_delsessionid(conn, old_ssl_sessionid);
! 629: incache = FALSE;
! 630: }
! 631: }
! 632:
! 633: if(!incache) {
! 634: result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
! 635: 0 /* unknown size */, sockindex);
! 636: if(result) {
! 637: Curl_ssl_sessionid_unlock(conn);
! 638: failf(data, "failed to store ssl session");
! 639: return result;
! 640: }
! 641: }
! 642: Curl_ssl_sessionid_unlock(conn);
! 643: }
! 644:
! 645: connssl->connecting_state = ssl_connect_done;
! 646:
! 647: return result;
! 648: }
! 649:
! 650:
! 651: static ssize_t wolfssl_send(struct connectdata *conn,
! 652: int sockindex,
! 653: const void *mem,
! 654: size_t len,
! 655: CURLcode *curlcode)
! 656: {
! 657: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
! 658: struct ssl_backend_data *backend = connssl->backend;
! 659: char error_buffer[WOLFSSL_MAX_ERROR_SZ];
! 660: int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
! 661: int rc = SSL_write(backend->handle, mem, memlen);
! 662:
! 663: if(rc < 0) {
! 664: int err = SSL_get_error(backend->handle, rc);
! 665:
! 666: switch(err) {
! 667: case SSL_ERROR_WANT_READ:
! 668: case SSL_ERROR_WANT_WRITE:
! 669: /* there's data pending, re-invoke SSL_write() */
! 670: *curlcode = CURLE_AGAIN;
! 671: return -1;
! 672: default:
! 673: failf(conn->data, "SSL write: %s, errno %d",
! 674: ERR_error_string(err, error_buffer),
! 675: SOCKERRNO);
! 676: *curlcode = CURLE_SEND_ERROR;
! 677: return -1;
! 678: }
! 679: }
! 680: return rc;
! 681: }
! 682:
! 683: static void Curl_wolfssl_close(struct connectdata *conn, int sockindex)
! 684: {
! 685: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
! 686: struct ssl_backend_data *backend = connssl->backend;
! 687:
! 688: if(backend->handle) {
! 689: (void)SSL_shutdown(backend->handle);
! 690: SSL_free(backend->handle);
! 691: backend->handle = NULL;
! 692: }
! 693: if(backend->ctx) {
! 694: SSL_CTX_free(backend->ctx);
! 695: backend->ctx = NULL;
! 696: }
! 697: }
! 698:
! 699: static ssize_t wolfssl_recv(struct connectdata *conn,
! 700: int num,
! 701: char *buf,
! 702: size_t buffersize,
! 703: CURLcode *curlcode)
! 704: {
! 705: struct ssl_connect_data *connssl = &conn->ssl[num];
! 706: struct ssl_backend_data *backend = connssl->backend;
! 707: char error_buffer[WOLFSSL_MAX_ERROR_SZ];
! 708: int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
! 709: int nread = SSL_read(backend->handle, buf, buffsize);
! 710:
! 711: if(nread < 0) {
! 712: int err = SSL_get_error(backend->handle, nread);
! 713:
! 714: switch(err) {
! 715: case SSL_ERROR_ZERO_RETURN: /* no more data */
! 716: break;
! 717: case SSL_ERROR_WANT_READ:
! 718: case SSL_ERROR_WANT_WRITE:
! 719: /* there's data pending, re-invoke SSL_read() */
! 720: *curlcode = CURLE_AGAIN;
! 721: return -1;
! 722: default:
! 723: failf(conn->data, "SSL read: %s, errno %d",
! 724: ERR_error_string(err, error_buffer),
! 725: SOCKERRNO);
! 726: *curlcode = CURLE_RECV_ERROR;
! 727: return -1;
! 728: }
! 729: }
! 730: return nread;
! 731: }
! 732:
! 733:
! 734: static void Curl_wolfssl_session_free(void *ptr)
! 735: {
! 736: (void)ptr;
! 737: /* wolfSSL reuses sessions on own, no free */
! 738: }
! 739:
! 740:
! 741: static size_t Curl_wolfssl_version(char *buffer, size_t size)
! 742: {
! 743: #if LIBWOLFSSL_VERSION_HEX >= 0x03006000
! 744: return msnprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version());
! 745: #elif defined(WOLFSSL_VERSION)
! 746: return msnprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION);
! 747: #endif
! 748: }
! 749:
! 750:
! 751: static int Curl_wolfssl_init(void)
! 752: {
! 753: return (wolfSSL_Init() == SSL_SUCCESS);
! 754: }
! 755:
! 756:
! 757: static void Curl_wolfssl_cleanup(void)
! 758: {
! 759: wolfSSL_Cleanup();
! 760: }
! 761:
! 762:
! 763: static bool Curl_wolfssl_data_pending(const struct connectdata* conn,
! 764: int connindex)
! 765: {
! 766: const struct ssl_connect_data *connssl = &conn->ssl[connindex];
! 767: struct ssl_backend_data *backend = connssl->backend;
! 768: if(backend->handle) /* SSL is in use */
! 769: return (0 != SSL_pending(backend->handle)) ? TRUE : FALSE;
! 770: else
! 771: return FALSE;
! 772: }
! 773:
! 774:
! 775: /*
! 776: * This function is called to shut down the SSL layer but keep the
! 777: * socket open (CCC - Clear Command Channel)
! 778: */
! 779: static int Curl_wolfssl_shutdown(struct connectdata *conn, int sockindex)
! 780: {
! 781: int retval = 0;
! 782: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
! 783: struct ssl_backend_data *backend = connssl->backend;
! 784:
! 785: if(backend->handle) {
! 786: SSL_free(backend->handle);
! 787: backend->handle = NULL;
! 788: }
! 789: return retval;
! 790: }
! 791:
! 792:
! 793: static CURLcode
! 794: wolfssl_connect_common(struct connectdata *conn,
! 795: int sockindex,
! 796: bool nonblocking,
! 797: bool *done)
! 798: {
! 799: CURLcode result;
! 800: struct Curl_easy *data = conn->data;
! 801: struct ssl_connect_data *connssl = &conn->ssl[sockindex];
! 802: curl_socket_t sockfd = conn->sock[sockindex];
! 803: time_t timeout_ms;
! 804: int what;
! 805:
! 806: /* check if the connection has already been established */
! 807: if(ssl_connection_complete == connssl->state) {
! 808: *done = TRUE;
! 809: return CURLE_OK;
! 810: }
! 811:
! 812: if(ssl_connect_1 == connssl->connecting_state) {
! 813: /* Find out how much more time we're allowed */
! 814: timeout_ms = Curl_timeleft(data, NULL, TRUE);
! 815:
! 816: if(timeout_ms < 0) {
! 817: /* no need to continue if time already is up */
! 818: failf(data, "SSL connection timeout");
! 819: return CURLE_OPERATION_TIMEDOUT;
! 820: }
! 821:
! 822: result = wolfssl_connect_step1(conn, sockindex);
! 823: if(result)
! 824: return result;
! 825: }
! 826:
! 827: while(ssl_connect_2 == connssl->connecting_state ||
! 828: ssl_connect_2_reading == connssl->connecting_state ||
! 829: ssl_connect_2_writing == connssl->connecting_state) {
! 830:
! 831: /* check allowed time left */
! 832: timeout_ms = Curl_timeleft(data, NULL, TRUE);
! 833:
! 834: if(timeout_ms < 0) {
! 835: /* no need to continue if time already is up */
! 836: failf(data, "SSL connection timeout");
! 837: return CURLE_OPERATION_TIMEDOUT;
! 838: }
! 839:
! 840: /* if ssl is expecting something, check if it's available. */
! 841: if(connssl->connecting_state == ssl_connect_2_reading
! 842: || connssl->connecting_state == ssl_connect_2_writing) {
! 843:
! 844: curl_socket_t writefd = ssl_connect_2_writing ==
! 845: connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
! 846: curl_socket_t readfd = ssl_connect_2_reading ==
! 847: connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
! 848:
! 849: what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
! 850: nonblocking?0:timeout_ms);
! 851: if(what < 0) {
! 852: /* fatal error */
! 853: failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
! 854: return CURLE_SSL_CONNECT_ERROR;
! 855: }
! 856: else if(0 == what) {
! 857: if(nonblocking) {
! 858: *done = FALSE;
! 859: return CURLE_OK;
! 860: }
! 861: else {
! 862: /* timeout */
! 863: failf(data, "SSL connection timeout");
! 864: return CURLE_OPERATION_TIMEDOUT;
! 865: }
! 866: }
! 867: /* socket is readable or writable */
! 868: }
! 869:
! 870: /* Run transaction, and return to the caller if it failed or if
! 871: * this connection is part of a multi handle and this loop would
! 872: * execute again. This permits the owner of a multi handle to
! 873: * abort a connection attempt before step2 has completed while
! 874: * ensuring that a client using select() or epoll() will always
! 875: * have a valid fdset to wait on.
! 876: */
! 877: result = wolfssl_connect_step2(conn, sockindex);
! 878: if(result || (nonblocking &&
! 879: (ssl_connect_2 == connssl->connecting_state ||
! 880: ssl_connect_2_reading == connssl->connecting_state ||
! 881: ssl_connect_2_writing == connssl->connecting_state)))
! 882: return result;
! 883: } /* repeat step2 until all transactions are done. */
! 884:
! 885: if(ssl_connect_3 == connssl->connecting_state) {
! 886: result = wolfssl_connect_step3(conn, sockindex);
! 887: if(result)
! 888: return result;
! 889: }
! 890:
! 891: if(ssl_connect_done == connssl->connecting_state) {
! 892: connssl->state = ssl_connection_complete;
! 893: conn->recv[sockindex] = wolfssl_recv;
! 894: conn->send[sockindex] = wolfssl_send;
! 895: *done = TRUE;
! 896: }
! 897: else
! 898: *done = FALSE;
! 899:
! 900: /* Reset our connect state machine */
! 901: connssl->connecting_state = ssl_connect_1;
! 902:
! 903: return CURLE_OK;
! 904: }
! 905:
! 906:
! 907: static CURLcode Curl_wolfssl_connect_nonblocking(struct connectdata *conn,
! 908: int sockindex, bool *done)
! 909: {
! 910: return wolfssl_connect_common(conn, sockindex, TRUE, done);
! 911: }
! 912:
! 913:
! 914: static CURLcode Curl_wolfssl_connect(struct connectdata *conn, int sockindex)
! 915: {
! 916: CURLcode result;
! 917: bool done = FALSE;
! 918:
! 919: result = wolfssl_connect_common(conn, sockindex, FALSE, &done);
! 920: if(result)
! 921: return result;
! 922:
! 923: DEBUGASSERT(done);
! 924:
! 925: return CURLE_OK;
! 926: }
! 927:
! 928: static CURLcode Curl_wolfssl_random(struct Curl_easy *data,
! 929: unsigned char *entropy, size_t length)
! 930: {
! 931: WC_RNG rng;
! 932: (void)data;
! 933: if(wc_InitRng(&rng))
! 934: return CURLE_FAILED_INIT;
! 935: if(length > UINT_MAX)
! 936: return CURLE_FAILED_INIT;
! 937: if(wc_RNG_GenerateBlock(&rng, entropy, (unsigned)length))
! 938: return CURLE_FAILED_INIT;
! 939: if(wc_FreeRng(&rng))
! 940: return CURLE_FAILED_INIT;
! 941: return CURLE_OK;
! 942: }
! 943:
! 944: static CURLcode Curl_wolfssl_sha256sum(const unsigned char *tmp, /* input */
! 945: size_t tmplen,
! 946: unsigned char *sha256sum /* output */,
! 947: size_t unused)
! 948: {
! 949: wc_Sha256 SHA256pw;
! 950: (void)unused;
! 951: wc_InitSha256(&SHA256pw);
! 952: wc_Sha256Update(&SHA256pw, tmp, (word32)tmplen);
! 953: wc_Sha256Final(&SHA256pw, sha256sum);
! 954: return CURLE_OK;
! 955: }
! 956:
! 957: static void *Curl_wolfssl_get_internals(struct ssl_connect_data *connssl,
! 958: CURLINFO info UNUSED_PARAM)
! 959: {
! 960: struct ssl_backend_data *backend = connssl->backend;
! 961: (void)info;
! 962: return backend->handle;
! 963: }
! 964:
! 965: const struct Curl_ssl Curl_ssl_wolfssl = {
! 966: { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */
! 967:
! 968: #ifdef KEEP_PEER_CERT
! 969: SSLSUPP_PINNEDPUBKEY |
! 970: #endif
! 971: SSLSUPP_SSL_CTX,
! 972:
! 973: sizeof(struct ssl_backend_data),
! 974:
! 975: Curl_wolfssl_init, /* init */
! 976: Curl_wolfssl_cleanup, /* cleanup */
! 977: Curl_wolfssl_version, /* version */
! 978: Curl_none_check_cxn, /* check_cxn */
! 979: Curl_wolfssl_shutdown, /* shutdown */
! 980: Curl_wolfssl_data_pending, /* data_pending */
! 981: Curl_wolfssl_random, /* random */
! 982: Curl_none_cert_status_request, /* cert_status_request */
! 983: Curl_wolfssl_connect, /* connect */
! 984: Curl_wolfssl_connect_nonblocking, /* connect_nonblocking */
! 985: Curl_wolfssl_get_internals, /* get_internals */
! 986: Curl_wolfssl_close, /* close_one */
! 987: Curl_none_close_all, /* close_all */
! 988: Curl_wolfssl_session_free, /* session_free */
! 989: Curl_none_set_engine, /* set_engine */
! 990: Curl_none_set_engine_default, /* set_engine_default */
! 991: Curl_none_engines_list, /* engines_list */
! 992: Curl_none_false_start, /* false_start */
! 993: Curl_none_md5sum, /* md5sum */
! 994: Curl_wolfssl_sha256sum /* sha256sum */
! 995: };
! 996:
! 997: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>