Return to wolfssl.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) 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