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