cyassl.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 /*
00024  * Source file for all CyaSSL-specific code for the TLS/SSL layer. No code
00025  * but vtls.c should ever call or use these functions.
00026  *
00027  */
00028 
00029 #include "curl_setup.h"
00030 
00031 #ifdef USE_CYASSL
00032 
00033 #define WOLFSSL_OPTIONS_IGNORE_SYS
00034 /* CyaSSL's version.h, which should contain only the version, should come
00035 before all other CyaSSL includes and be immediately followed by build config
00036 aka options.h. https://curl.haxx.se/mail/lib-2015-04/0069.html */
00037 #include <cyassl/version.h>
00038 #if defined(HAVE_CYASSL_OPTIONS_H) && (LIBCYASSL_VERSION_HEX > 0x03004008)
00039 #if defined(CYASSL_API) || defined(WOLFSSL_API)
00040 /* Safety measure. If either is defined some API include was already included
00041 and that's a problem since options.h hasn't been included yet. */
00042 #error "CyaSSL API was included before the CyaSSL build options."
00043 #endif
00044 #include <cyassl/options.h>
00045 #endif
00046 
00047 #ifdef HAVE_LIMITS_H
00048 #include <limits.h>
00049 #endif
00050 
00051 #include "urldata.h"
00052 #include "sendf.h"
00053 #include "inet_pton.h"
00054 #include "vtls.h"
00055 #include "parsedate.h"
00056 #include "connect.h" /* for the connect timeout */
00057 #include "select.h"
00058 #include "strcase.h"
00059 #include "x509asn1.h"
00060 #include "curl_printf.h"
00061 
00062 #include <cyassl/ssl.h>
00063 #ifdef HAVE_CYASSL_ERROR_SSL_H
00064 #include <cyassl/error-ssl.h>
00065 #else
00066 #include <cyassl/error.h>
00067 #endif
00068 #include <cyassl/ctaocrypt/random.h>
00069 #include <cyassl/ctaocrypt/sha256.h>
00070 
00071 #include "cyassl.h"
00072 
00073 /* The last #include files should be: */
00074 #include "curl_memory.h"
00075 #include "memdebug.h"
00076 
00077 #if LIBCYASSL_VERSION_HEX < 0x02007002 /* < 2.7.2 */
00078 #define CYASSL_MAX_ERROR_SZ 80
00079 #endif
00080 
00081 /* To determine what functions are available we rely on one or both of:
00082    - the user's options.h generated by CyaSSL/wolfSSL
00083    - the symbols detected by curl's configure
00084    Since they are markedly different from one another, and one or the other may
00085    not be available, we do some checking below to bring things in sync. */
00086 
00087 /* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */
00088 #ifndef HAVE_ALPN
00089 #ifdef HAVE_WOLFSSL_USEALPN
00090 #define HAVE_ALPN
00091 #endif
00092 #endif
00093 
00094 /* WOLFSSL_ALLOW_SSLV3 is wolfSSL's build time symbol for enabling SSLv3 in
00095    options.h, but is only seen in >= 3.6.6 since that's when they started
00096    disabling SSLv3 by default. */
00097 #ifndef WOLFSSL_ALLOW_SSLV3
00098 #if (LIBCYASSL_VERSION_HEX < 0x03006006) || \
00099     defined(HAVE_WOLFSSLV3_CLIENT_METHOD)
00100 #define WOLFSSL_ALLOW_SSLV3
00101 #endif
00102 #endif
00103 
00104 /* HAVE_SUPPORTED_CURVES is wolfSSL's build time symbol for enabling the ECC
00105    supported curve extension in options.h. Note ECC is enabled separately. */
00106 #ifndef HAVE_SUPPORTED_CURVES
00107 #if defined(HAVE_CYASSL_CTX_USESUPPORTEDCURVE) || \
00108     defined(HAVE_WOLFSSL_CTX_USESUPPORTEDCURVE)
00109 #define HAVE_SUPPORTED_CURVES
00110 #endif
00111 #endif
00112 
00113 static Curl_recv cyassl_recv;
00114 static Curl_send cyassl_send;
00115 
00116 
00117 static int do_file_type(const char *type)
00118 {
00119   if(!type || !type[0])
00120     return SSL_FILETYPE_PEM;
00121   if(strcasecompare(type, "PEM"))
00122     return SSL_FILETYPE_PEM;
00123   if(strcasecompare(type, "DER"))
00124     return SSL_FILETYPE_ASN1;
00125   return -1;
00126 }
00127 
00128 /*
00129  * This function loads all the client/CA certificates and CRLs. Setup the TLS
00130  * layer and do all necessary magic.
00131  */
00132 static CURLcode
00133 cyassl_connect_step1(struct connectdata *conn,
00134                      int sockindex)
00135 {
00136   char error_buffer[CYASSL_MAX_ERROR_SZ];
00137   struct Curl_easy *data = conn->data;
00138   struct ssl_connect_data* conssl = &conn->ssl[sockindex];
00139   SSL_METHOD* req_method = NULL;
00140   curl_socket_t sockfd = conn->sock[sockindex];
00141 #ifdef HAVE_SNI
00142   bool sni = FALSE;
00143 #define use_sni(x)  sni = (x)
00144 #else
00145 #define use_sni(x)  Curl_nop_stmt
00146 #endif
00147 
00148   if(conssl->state == ssl_connection_complete)
00149     return CURLE_OK;
00150 
00151   /* check to see if we've been told to use an explicit SSL/TLS version */
00152   switch(SSL_CONN_CONFIG(version)) {
00153   case CURL_SSLVERSION_DEFAULT:
00154   case CURL_SSLVERSION_TLSv1:
00155 #if LIBCYASSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
00156     /* minimum protocol version is set later after the CTX object is created */
00157     req_method = SSLv23_client_method();
00158 #else
00159     infof(data, "CyaSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
00160           "TLS 1.0 is used exclusively\n");
00161     req_method = TLSv1_client_method();
00162 #endif
00163     use_sni(TRUE);
00164     break;
00165   case CURL_SSLVERSION_TLSv1_0:
00166     req_method = TLSv1_client_method();
00167     use_sni(TRUE);
00168     break;
00169   case CURL_SSLVERSION_TLSv1_1:
00170     req_method = TLSv1_1_client_method();
00171     use_sni(TRUE);
00172     break;
00173   case CURL_SSLVERSION_TLSv1_2:
00174     req_method = TLSv1_2_client_method();
00175     use_sni(TRUE);
00176     break;
00177   case CURL_SSLVERSION_TLSv1_3:
00178     failf(data, "CyaSSL: TLS 1.3 is not yet supported");
00179     return CURLE_SSL_CONNECT_ERROR;
00180   case CURL_SSLVERSION_SSLv3:
00181 #ifdef WOLFSSL_ALLOW_SSLV3
00182     req_method = SSLv3_client_method();
00183     use_sni(FALSE);
00184 #else
00185     failf(data, "CyaSSL does not support SSLv3");
00186     return CURLE_NOT_BUILT_IN;
00187 #endif
00188     break;
00189   case CURL_SSLVERSION_SSLv2:
00190     failf(data, "CyaSSL does not support SSLv2");
00191     return CURLE_SSL_CONNECT_ERROR;
00192   default:
00193     failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
00194     return CURLE_SSL_CONNECT_ERROR;
00195   }
00196 
00197   if(!req_method) {
00198     failf(data, "SSL: couldn't create a method!");
00199     return CURLE_OUT_OF_MEMORY;
00200   }
00201 
00202   if(conssl->ctx)
00203     SSL_CTX_free(conssl->ctx);
00204   conssl->ctx = SSL_CTX_new(req_method);
00205 
00206   if(!conssl->ctx) {
00207     failf(data, "SSL: couldn't create a context!");
00208     return CURLE_OUT_OF_MEMORY;
00209   }
00210 
00211   switch(SSL_CONN_CONFIG(version)) {
00212   case CURL_SSLVERSION_DEFAULT:
00213   case CURL_SSLVERSION_TLSv1:
00214 #if LIBCYASSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
00215     /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is whatever
00216     minimum version of TLS was built in and at least TLS 1.0. For later library
00217     versions that could change (eg TLS 1.0 built in but defaults to TLS 1.1) so
00218     we have this short circuit evaluation to find the minimum supported TLS
00219     version. We use wolfSSL_CTX_SetMinVersion and not CyaSSL_SetMinVersion
00220     because only the former will work before the user's CTX callback is called.
00221     */
00222     if((wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1) != 1) &&
00223        (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_1) != 1) &&
00224        (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_2) != 1)) {
00225       failf(data, "SSL: couldn't set the minimum protocol version");
00226       return CURLE_SSL_CONNECT_ERROR;
00227     }
00228 #endif
00229     break;
00230   }
00231 
00232 #ifndef NO_FILESYSTEM
00233   /* load trusted cacert */
00234   if(SSL_CONN_CONFIG(CAfile)) {
00235     if(1 != SSL_CTX_load_verify_locations(conssl->ctx,
00236                                       SSL_CONN_CONFIG(CAfile),
00237                                       SSL_CONN_CONFIG(CApath))) {
00238       if(SSL_CONN_CONFIG(verifypeer)) {
00239         /* Fail if we insist on successfully verifying the server. */
00240         failf(data, "error setting certificate verify locations:\n"
00241               "  CAfile: %s\n  CApath: %s",
00242               SSL_CONN_CONFIG(CAfile)?
00243               SSL_CONN_CONFIG(CAfile): "none",
00244               SSL_CONN_CONFIG(CApath)?
00245               SSL_CONN_CONFIG(CApath) : "none");
00246         return CURLE_SSL_CACERT_BADFILE;
00247       }
00248       else {
00249         /* Just continue with a warning if no strict certificate
00250            verification is required. */
00251         infof(data, "error setting certificate verify locations,"
00252               " continuing anyway:\n");
00253       }
00254     }
00255     else {
00256       /* Everything is fine. */
00257       infof(data, "successfully set certificate verify locations:\n");
00258     }
00259     infof(data,
00260           "  CAfile: %s\n"
00261           "  CApath: %s\n",
00262           SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
00263           "none",
00264           SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath):
00265           "none");
00266   }
00267 
00268   /* Load the client certificate, and private key */
00269   if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) {
00270     int file_type = do_file_type(SSL_SET_OPTION(cert_type));
00271 
00272     if(SSL_CTX_use_certificate_file(conssl->ctx, SSL_SET_OPTION(cert),
00273                                      file_type) != 1) {
00274       failf(data, "unable to use client certificate (no key or wrong pass"
00275             " phrase?)");
00276       return CURLE_SSL_CONNECT_ERROR;
00277     }
00278 
00279     file_type = do_file_type(SSL_SET_OPTION(key_type));
00280     if(SSL_CTX_use_PrivateKey_file(conssl->ctx, SSL_SET_OPTION(key),
00281                                     file_type) != 1) {
00282       failf(data, "unable to set private key");
00283       return CURLE_SSL_CONNECT_ERROR;
00284     }
00285   }
00286 #endif /* !NO_FILESYSTEM */
00287 
00288   /* SSL always tries to verify the peer, this only says whether it should
00289    * fail to connect if the verification fails, or if it should continue
00290    * anyway. In the latter case the result of the verification is checked with
00291    * SSL_get_verify_result() below. */
00292   SSL_CTX_set_verify(conssl->ctx,
00293                      SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER:
00294                                                  SSL_VERIFY_NONE,
00295                      NULL);
00296 
00297 #ifdef HAVE_SNI
00298   if(sni) {
00299     struct in_addr addr4;
00300 #ifdef ENABLE_IPV6
00301     struct in6_addr addr6;
00302 #endif
00303     const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
00304       conn->host.name;
00305     size_t hostname_len = strlen(hostname);
00306     if((hostname_len < USHRT_MAX) &&
00307        (0 == Curl_inet_pton(AF_INET, hostname, &addr4)) &&
00308 #ifdef ENABLE_IPV6
00309        (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) &&
00310 #endif
00311        (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, hostname,
00312                           (unsigned short)hostname_len) != 1)) {
00313       infof(data, "WARNING: failed to configure server name indication (SNI) "
00314             "TLS extension\n");
00315     }
00316   }
00317 #endif
00318 
00319 #ifdef HAVE_SUPPORTED_CURVES
00320   /* CyaSSL/wolfSSL does not send the supported ECC curves ext automatically:
00321      https://github.com/wolfSSL/wolfssl/issues/366
00322      The supported curves below are those also supported by OpenSSL 1.0.2 and
00323      in the same order. */
00324   CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x17); /* secp256r1 */
00325   CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x19); /* secp521r1 */
00326   CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x18); /* secp384r1 */
00327 #endif
00328 
00329   /* give application a chance to interfere with SSL set up. */
00330   if(data->set.ssl.fsslctx) {
00331     CURLcode result = CURLE_OK;
00332     result = (*data->set.ssl.fsslctx)(data, conssl->ctx,
00333                                       data->set.ssl.fsslctxp);
00334     if(result) {
00335       failf(data, "error signaled by ssl ctx callback");
00336       return result;
00337     }
00338   }
00339 #ifdef NO_FILESYSTEM
00340   else if(SSL_CONN_CONFIG(verifypeer)) {
00341     failf(data, "SSL: Certificates couldn't be loaded because CyaSSL was built"
00342           " with \"no filesystem\". Either disable peer verification"
00343           " (insecure) or if you are building an application with libcurl you"
00344           " can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
00345     return CURLE_SSL_CONNECT_ERROR;
00346   }
00347 #endif
00348 
00349   /* Let's make an SSL structure */
00350   if(conssl->handle)
00351     SSL_free(conssl->handle);
00352   conssl->handle = SSL_new(conssl->ctx);
00353   if(!conssl->handle) {
00354     failf(data, "SSL: couldn't create a context (handle)!");
00355     return CURLE_OUT_OF_MEMORY;
00356   }
00357 
00358 #ifdef HAVE_ALPN
00359   if(conn->bits.tls_enable_alpn) {
00360     char protocols[128];
00361     *protocols = '\0';
00362 
00363     /* wolfSSL's ALPN protocol name list format is a comma separated string of
00364        protocols in descending order of preference, eg: "h2,http/1.1" */
00365 
00366 #ifdef USE_NGHTTP2
00367     if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
00368       strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ",");
00369       infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
00370     }
00371 #endif
00372 
00373     strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1);
00374     infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
00375 
00376     if(wolfSSL_UseALPN(conssl->handle, protocols,
00377                        (unsigned)strlen(protocols),
00378                        WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
00379       failf(data, "SSL: failed setting ALPN protocols");
00380       return CURLE_SSL_CONNECT_ERROR;
00381     }
00382   }
00383 #endif /* HAVE_ALPN */
00384 
00385   /* Check if there's a cached ID we can/should use here! */
00386   if(data->set.general_ssl.sessionid) {
00387     void *ssl_sessionid = NULL;
00388 
00389     Curl_ssl_sessionid_lock(conn);
00390     if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
00391       /* we got a session id, use it! */
00392       if(!SSL_set_session(conssl->handle, ssl_sessionid)) {
00393         Curl_ssl_sessionid_unlock(conn);
00394         failf(data, "SSL: SSL_set_session failed: %s",
00395               ERR_error_string(SSL_get_error(conssl->handle, 0),
00396               error_buffer));
00397         return CURLE_SSL_CONNECT_ERROR;
00398       }
00399       /* Informational message */
00400       infof(data, "SSL re-using session ID\n");
00401     }
00402     Curl_ssl_sessionid_unlock(conn);
00403   }
00404 
00405   /* pass the raw socket into the SSL layer */
00406   if(!SSL_set_fd(conssl->handle, (int)sockfd)) {
00407     failf(data, "SSL: SSL_set_fd failed");
00408     return CURLE_SSL_CONNECT_ERROR;
00409   }
00410 
00411   conssl->connecting_state = ssl_connect_2;
00412   return CURLE_OK;
00413 }
00414 
00415 
00416 static CURLcode
00417 cyassl_connect_step2(struct connectdata *conn,
00418                      int sockindex)
00419 {
00420   int ret = -1;
00421   struct Curl_easy *data = conn->data;
00422   struct ssl_connect_data* conssl = &conn->ssl[sockindex];
00423   const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
00424     conn->host.name;
00425   const char * const dispname = SSL_IS_PROXY() ?
00426     conn->http_proxy.host.dispname : conn->host.dispname;
00427   const char * const pinnedpubkey = SSL_IS_PROXY() ?
00428                         data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
00429                         data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
00430 
00431   conn->recv[sockindex] = cyassl_recv;
00432   conn->send[sockindex] = cyassl_send;
00433 
00434   /* Enable RFC2818 checks */
00435   if(SSL_CONN_CONFIG(verifyhost)) {
00436     ret = CyaSSL_check_domain_name(conssl->handle, hostname);
00437     if(ret == SSL_FAILURE)
00438       return CURLE_OUT_OF_MEMORY;
00439   }
00440 
00441   ret = SSL_connect(conssl->handle);
00442   if(ret != 1) {
00443     char error_buffer[CYASSL_MAX_ERROR_SZ];
00444     int  detail = SSL_get_error(conssl->handle, ret);
00445 
00446     if(SSL_ERROR_WANT_READ == detail) {
00447       conssl->connecting_state = ssl_connect_2_reading;
00448       return CURLE_OK;
00449     }
00450     else if(SSL_ERROR_WANT_WRITE == detail) {
00451       conssl->connecting_state = ssl_connect_2_writing;
00452       return CURLE_OK;
00453     }
00454     /* There is no easy way to override only the CN matching.
00455      * This will enable the override of both mismatching SubjectAltNames
00456      * as also mismatching CN fields */
00457     else if(DOMAIN_NAME_MISMATCH == detail) {
00458 #if 1
00459       failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n",
00460             dispname);
00461       return CURLE_PEER_FAILED_VERIFICATION;
00462 #else
00463       /* When the CyaSSL_check_domain_name() is used and you desire to continue
00464        * on a DOMAIN_NAME_MISMATCH, i.e. 'conn->ssl_config.verifyhost == 0',
00465        * CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA error. The only
00466        * way to do this is currently to switch the CyaSSL_check_domain_name()
00467        * in and out based on the 'conn->ssl_config.verifyhost' value. */
00468       if(SSL_CONN_CONFIG(verifyhost)) {
00469         failf(data,
00470               "\tsubject alt name(s) or common name do not match \"%s\"\n",
00471               dispname);
00472         return CURLE_PEER_FAILED_VERIFICATION;
00473       }
00474       else {
00475         infof(data,
00476               "\tsubject alt name(s) and/or common name do not match \"%s\"\n",
00477               dispname);
00478         return CURLE_OK;
00479       }
00480 #endif
00481     }
00482 #if LIBCYASSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
00483     else if(ASN_NO_SIGNER_E == detail) {
00484       if(SSL_CONN_CONFIG(verifypeer)) {
00485         failf(data, "\tCA signer not available for verification\n");
00486         return CURLE_SSL_CACERT_BADFILE;
00487       }
00488       else {
00489         /* Just continue with a warning if no strict certificate
00490            verification is required. */
00491         infof(data, "CA signer not available for verification, "
00492                     "continuing anyway\n");
00493       }
00494     }
00495 #endif
00496     else {
00497       failf(data, "SSL_connect failed with error %d: %s", detail,
00498           ERR_error_string(detail, error_buffer));
00499       return CURLE_SSL_CONNECT_ERROR;
00500     }
00501   }
00502 
00503   if(pinnedpubkey) {
00504 #ifdef KEEP_PEER_CERT
00505     X509 *x509;
00506     const char *x509_der;
00507     int x509_der_len;
00508     curl_X509certificate x509_parsed;
00509     curl_asn1Element *pubkey;
00510     CURLcode result;
00511 
00512     x509 = SSL_get_peer_certificate(conssl->handle);
00513     if(!x509) {
00514       failf(data, "SSL: failed retrieving server certificate");
00515       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
00516     }
00517 
00518     x509_der = (const char *)CyaSSL_X509_get_der(x509, &x509_der_len);
00519     if(!x509_der) {
00520       failf(data, "SSL: failed retrieving ASN.1 server certificate");
00521       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
00522     }
00523 
00524     memset(&x509_parsed, 0, sizeof x509_parsed);
00525     if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
00526       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
00527 
00528     pubkey = &x509_parsed.subjectPublicKeyInfo;
00529     if(!pubkey->header || pubkey->end <= pubkey->header) {
00530       failf(data, "SSL: failed retrieving public key from server certificate");
00531       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
00532     }
00533 
00534     result = Curl_pin_peer_pubkey(data,
00535                                   pinnedpubkey,
00536                                   (const unsigned char *)pubkey->header,
00537                                   (size_t)(pubkey->end - pubkey->header));
00538     if(result) {
00539       failf(data, "SSL: public key does not match pinned public key!");
00540       return result;
00541     }
00542 #else
00543     failf(data, "Library lacks pinning support built-in");
00544     return CURLE_NOT_BUILT_IN;
00545 #endif
00546   }
00547 
00548 #ifdef HAVE_ALPN
00549   if(conn->bits.tls_enable_alpn) {
00550     int rc;
00551     char *protocol = NULL;
00552     unsigned short protocol_len = 0;
00553 
00554     rc = wolfSSL_ALPN_GetProtocol(conssl->handle, &protocol, &protocol_len);
00555 
00556     if(rc == SSL_SUCCESS) {
00557       infof(data, "ALPN, server accepted to use %.*s\n", protocol_len,
00558             protocol);
00559 
00560       if(protocol_len == ALPN_HTTP_1_1_LENGTH &&
00561          !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH))
00562         conn->negnpn = CURL_HTTP_VERSION_1_1;
00563 #ifdef USE_NGHTTP2
00564       else if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
00565               protocol_len == NGHTTP2_PROTO_VERSION_ID_LEN &&
00566               !memcmp(protocol, NGHTTP2_PROTO_VERSION_ID,
00567                       NGHTTP2_PROTO_VERSION_ID_LEN))
00568         conn->negnpn = CURL_HTTP_VERSION_2;
00569 #endif
00570       else
00571         infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len,
00572               protocol);
00573     }
00574     else if(rc == SSL_ALPN_NOT_FOUND)
00575       infof(data, "ALPN, server did not agree to a protocol\n");
00576     else {
00577       failf(data, "ALPN, failure getting protocol, error %d", rc);
00578       return CURLE_SSL_CONNECT_ERROR;
00579     }
00580   }
00581 #endif /* HAVE_ALPN */
00582 
00583   conssl->connecting_state = ssl_connect_3;
00584   infof(data, "SSL connected\n");
00585 
00586   return CURLE_OK;
00587 }
00588 
00589 
00590 static CURLcode
00591 cyassl_connect_step3(struct connectdata *conn,
00592                      int sockindex)
00593 {
00594   CURLcode result = CURLE_OK;
00595   struct Curl_easy *data = conn->data;
00596   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
00597 
00598   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
00599 
00600   if(data->set.general_ssl.sessionid) {
00601     bool incache;
00602     SSL_SESSION *our_ssl_sessionid;
00603     void *old_ssl_sessionid = NULL;
00604 
00605     our_ssl_sessionid = SSL_get_session(connssl->handle);
00606 
00607     Curl_ssl_sessionid_lock(conn);
00608     incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL,
00609                                       sockindex));
00610     if(incache) {
00611       if(old_ssl_sessionid != our_ssl_sessionid) {
00612         infof(data, "old SSL session ID is stale, removing\n");
00613         Curl_ssl_delsessionid(conn, old_ssl_sessionid);
00614         incache = FALSE;
00615       }
00616     }
00617 
00618     if(!incache) {
00619       result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
00620                                      0 /* unknown size */, sockindex);
00621       if(result) {
00622         Curl_ssl_sessionid_unlock(conn);
00623         failf(data, "failed to store ssl session");
00624         return result;
00625       }
00626     }
00627     Curl_ssl_sessionid_unlock(conn);
00628   }
00629 
00630   connssl->connecting_state = ssl_connect_done;
00631 
00632   return result;
00633 }
00634 
00635 
00636 static ssize_t cyassl_send(struct connectdata *conn,
00637                            int sockindex,
00638                            const void *mem,
00639                            size_t len,
00640                            CURLcode *curlcode)
00641 {
00642   char error_buffer[CYASSL_MAX_ERROR_SZ];
00643   int  memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
00644   int  rc     = SSL_write(conn->ssl[sockindex].handle, mem, memlen);
00645 
00646   if(rc < 0) {
00647     int err = SSL_get_error(conn->ssl[sockindex].handle, rc);
00648 
00649     switch(err) {
00650     case SSL_ERROR_WANT_READ:
00651     case SSL_ERROR_WANT_WRITE:
00652       /* there's data pending, re-invoke SSL_write() */
00653       *curlcode = CURLE_AGAIN;
00654       return -1;
00655     default:
00656       failf(conn->data, "SSL write: %s, errno %d",
00657             ERR_error_string(err, error_buffer),
00658             SOCKERRNO);
00659       *curlcode = CURLE_SEND_ERROR;
00660       return -1;
00661     }
00662   }
00663   return rc;
00664 }
00665 
00666 void Curl_cyassl_close(struct connectdata *conn, int sockindex)
00667 {
00668   struct ssl_connect_data *conssl = &conn->ssl[sockindex];
00669 
00670   if(conssl->handle) {
00671     (void)SSL_shutdown(conssl->handle);
00672     SSL_free(conssl->handle);
00673     conssl->handle = NULL;
00674   }
00675   if(conssl->ctx) {
00676     SSL_CTX_free(conssl->ctx);
00677     conssl->ctx = NULL;
00678   }
00679 }
00680 
00681 static ssize_t cyassl_recv(struct connectdata *conn,
00682                            int num,
00683                            char *buf,
00684                            size_t buffersize,
00685                            CURLcode *curlcode)
00686 {
00687   char error_buffer[CYASSL_MAX_ERROR_SZ];
00688   int  buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
00689   int  nread    = SSL_read(conn->ssl[num].handle, buf, buffsize);
00690 
00691   if(nread < 0) {
00692     int err = SSL_get_error(conn->ssl[num].handle, nread);
00693 
00694     switch(err) {
00695     case SSL_ERROR_ZERO_RETURN: /* no more data */
00696       break;
00697     case SSL_ERROR_WANT_READ:
00698     case SSL_ERROR_WANT_WRITE:
00699       /* there's data pending, re-invoke SSL_read() */
00700       *curlcode = CURLE_AGAIN;
00701       return -1;
00702     default:
00703       failf(conn->data, "SSL read: %s, errno %d",
00704             ERR_error_string(err, error_buffer),
00705             SOCKERRNO);
00706       *curlcode = CURLE_RECV_ERROR;
00707       return -1;
00708     }
00709   }
00710   return nread;
00711 }
00712 
00713 
00714 void Curl_cyassl_session_free(void *ptr)
00715 {
00716   (void)ptr;
00717   /* CyaSSL reuses sessions on own, no free */
00718 }
00719 
00720 
00721 size_t Curl_cyassl_version(char *buffer, size_t size)
00722 {
00723 #ifdef WOLFSSL_VERSION
00724   return snprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION);
00725 #elif defined(CYASSL_VERSION)
00726   return snprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION);
00727 #else
00728   return snprintf(buffer, size, "CyaSSL/%s", "<1.8.8");
00729 #endif
00730 }
00731 
00732 
00733 int Curl_cyassl_init(void)
00734 {
00735   return (CyaSSL_Init() == SSL_SUCCESS);
00736 }
00737 
00738 
00739 bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex)
00740 {
00741   if(conn->ssl[connindex].handle)   /* SSL is in use */
00742     return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE;
00743   else
00744     return FALSE;
00745 }
00746 
00747 
00748 /*
00749  * This function is called to shut down the SSL layer but keep the
00750  * socket open (CCC - Clear Command Channel)
00751  */
00752 int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex)
00753 {
00754   int retval = 0;
00755   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
00756 
00757   if(connssl->handle) {
00758     SSL_free(connssl->handle);
00759     connssl->handle = NULL;
00760   }
00761   return retval;
00762 }
00763 
00764 
00765 static CURLcode
00766 cyassl_connect_common(struct connectdata *conn,
00767                       int sockindex,
00768                       bool nonblocking,
00769                       bool *done)
00770 {
00771   CURLcode result;
00772   struct Curl_easy *data = conn->data;
00773   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
00774   curl_socket_t sockfd = conn->sock[sockindex];
00775   long timeout_ms;
00776   int what;
00777 
00778   /* check if the connection has already been established */
00779   if(ssl_connection_complete == connssl->state) {
00780     *done = TRUE;
00781     return CURLE_OK;
00782   }
00783 
00784   if(ssl_connect_1==connssl->connecting_state) {
00785     /* Find out how much more time we're allowed */
00786     timeout_ms = Curl_timeleft(data, NULL, TRUE);
00787 
00788     if(timeout_ms < 0) {
00789       /* no need to continue if time already is up */
00790       failf(data, "SSL connection timeout");
00791       return CURLE_OPERATION_TIMEDOUT;
00792     }
00793 
00794     result = cyassl_connect_step1(conn, sockindex);
00795     if(result)
00796       return result;
00797   }
00798 
00799   while(ssl_connect_2 == connssl->connecting_state ||
00800         ssl_connect_2_reading == connssl->connecting_state ||
00801         ssl_connect_2_writing == connssl->connecting_state) {
00802 
00803     /* check allowed time left */
00804     timeout_ms = Curl_timeleft(data, NULL, TRUE);
00805 
00806     if(timeout_ms < 0) {
00807       /* no need to continue if time already is up */
00808       failf(data, "SSL connection timeout");
00809       return CURLE_OPERATION_TIMEDOUT;
00810     }
00811 
00812     /* if ssl is expecting something, check if it's available. */
00813     if(connssl->connecting_state == ssl_connect_2_reading
00814        || connssl->connecting_state == ssl_connect_2_writing) {
00815 
00816       curl_socket_t writefd = ssl_connect_2_writing==
00817         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
00818       curl_socket_t readfd = ssl_connect_2_reading==
00819         connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
00820 
00821       what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
00822                                nonblocking?0:timeout_ms);
00823       if(what < 0) {
00824         /* fatal error */
00825         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
00826         return CURLE_SSL_CONNECT_ERROR;
00827       }
00828       else if(0 == what) {
00829         if(nonblocking) {
00830           *done = FALSE;
00831           return CURLE_OK;
00832         }
00833         else {
00834           /* timeout */
00835           failf(data, "SSL connection timeout");
00836           return CURLE_OPERATION_TIMEDOUT;
00837         }
00838       }
00839       /* socket is readable or writable */
00840     }
00841 
00842     /* Run transaction, and return to the caller if it failed or if
00843      * this connection is part of a multi handle and this loop would
00844      * execute again. This permits the owner of a multi handle to
00845      * abort a connection attempt before step2 has completed while
00846      * ensuring that a client using select() or epoll() will always
00847      * have a valid fdset to wait on.
00848      */
00849     result = cyassl_connect_step2(conn, sockindex);
00850     if(result || (nonblocking &&
00851                   (ssl_connect_2 == connssl->connecting_state ||
00852                    ssl_connect_2_reading == connssl->connecting_state ||
00853                    ssl_connect_2_writing == connssl->connecting_state)))
00854       return result;
00855   } /* repeat step2 until all transactions are done. */
00856 
00857   if(ssl_connect_3 == connssl->connecting_state) {
00858     result = cyassl_connect_step3(conn, sockindex);
00859     if(result)
00860       return result;
00861   }
00862 
00863   if(ssl_connect_done == connssl->connecting_state) {
00864     connssl->state = ssl_connection_complete;
00865     conn->recv[sockindex] = cyassl_recv;
00866     conn->send[sockindex] = cyassl_send;
00867     *done = TRUE;
00868   }
00869   else
00870     *done = FALSE;
00871 
00872   /* Reset our connect state machine */
00873   connssl->connecting_state = ssl_connect_1;
00874 
00875   return CURLE_OK;
00876 }
00877 
00878 
00879 CURLcode
00880 Curl_cyassl_connect_nonblocking(struct connectdata *conn,
00881                                 int sockindex,
00882                                 bool *done)
00883 {
00884   return cyassl_connect_common(conn, sockindex, TRUE, done);
00885 }
00886 
00887 
00888 CURLcode
00889 Curl_cyassl_connect(struct connectdata *conn,
00890                     int sockindex)
00891 {
00892   CURLcode result;
00893   bool done = FALSE;
00894 
00895   result = cyassl_connect_common(conn, sockindex, FALSE, &done);
00896   if(result)
00897     return result;
00898 
00899   DEBUGASSERT(done);
00900 
00901   return CURLE_OK;
00902 }
00903 
00904 int Curl_cyassl_random(struct Curl_easy *data,
00905                        unsigned char *entropy,
00906                        size_t length)
00907 {
00908   RNG rng;
00909   (void)data;
00910   if(InitRng(&rng))
00911     return 1;
00912   if(length > UINT_MAX)
00913     return 1;
00914   if(RNG_GenerateBlock(&rng, entropy, (unsigned)length))
00915     return 1;
00916   return 0;
00917 }
00918 
00919 void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
00920                       size_t tmplen,
00921                       unsigned char *sha256sum /* output */,
00922                       size_t unused)
00923 {
00924   Sha256 SHA256pw;
00925   (void)unused;
00926   InitSha256(&SHA256pw);
00927   Sha256Update(&SHA256pw, tmp, (word32)tmplen);
00928   Sha256Final(&SHA256pw, sha256sum);
00929 }
00930 
00931 #endif


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:02