Skip to content
Snippets Groups Projects
openssl.c 93.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • /***************************************************************************
    
     *                                  _   _ ____  _
     *  Project                     ___| | | |  _ \| |
     *                             / __| | | | |_) | |
     *                            | (__| |_| |  _ <| |___
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *                             \___|\___/|_| \_\_____|
     *
    
     * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *
    
     * This software is licensed as described in the file COPYING, which
     * you should have received as part of this distribution. The terms
    
     * are also available at https://curl.haxx.se/docs/copyright.html.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     * copies of the Software, and permit persons to whom the Software is
    
     * furnished to do so, under the terms of the COPYING file.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     * KIND, either express or implied.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *
    
     ***************************************************************************/
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
     * Source file for all OpenSSL-specific code for the TLS/SSL layer. No code
    
     * but vtls.c should ever call or use these functions.
    
     */
    
    /*
     * The original SSLeay-using code for curl was written by Linas Vepstas and
     * Sampo Kellomaki 1998.
    
    #include "curl_setup.h"
    
    #ifdef USE_OPENSSL
    
    
    #ifdef HAVE_LIMITS_H
    
    #include <limits.h>
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    #include "urldata.h"
    #include "sendf.h"
    #include "formdata.h" /* for the boundary function */
    #include "url.h" /* for the ssl config check function */
    #include "inet_pton.h"
    
    #include "openssl.h"
    
    #include "connect.h"
    
    #include "strequal.h"
    #include "select.h"
    
    #include "vtls.h"
    
    #include "rawstr.h"
    #include "hostcheck.h"
    
    #include "curl_printf.h"
    
    #include <openssl/ssl.h>
    
    #include <openssl/rand.h>
    
    #include <openssl/dsa.h>
    #include <openssl/dh.h>
    
    #include <openssl/err.h>
    
    #include <openssl/conf.h>
    
    #include <openssl/rsa.h>
    
    #ifdef HAVE_OPENSSL_PKCS12_H
    #include <openssl/pkcs12.h>
    #endif
    
    
    #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    #include "warnless.h"
    #include "non-ascii.h" /* for Curl_convert_from_utf8 prototype */
    
    /* The last #include files should be: */
    #include "curl_memory.h"
    
    #include "memdebug.h"
    
    #ifndef OPENSSL_VERSION_NUMBER
    #error "OPENSSL_VERSION_NUMBER not defined"
    #endif
    
    
    #if defined(HAVE_OPENSSL_ENGINE_H)
    
    #if OPENSSL_VERSION_NUMBER >= 0x00909000L
    #define SSL_METHOD_QUAL const
    #else
    #define SSL_METHOD_QUAL
    #endif
    
    
    #if (OPENSSL_VERSION_NUMBER >= 0x10000000L)
    
    #define HAVE_ERR_REMOVE_THREAD_STATE 1
    
    #if (OPENSSL_VERSION_NUMBER >= 0x10100004L) && \
    
      !defined(LIBRESSL_VERSION_NUMBER)
    
    /* OpenSSL 1.1.0 deprecates the function */
    #define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1
    
    #if !defined(HAVE_SSLV2_CLIENT_METHOD) || \
      OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0+ has no SSLv2 */
    
    #undef OPENSSL_NO_SSL2 /* undef first to avoid compiler warnings */
    #define OPENSSL_NO_SSL2
    #endif
    
    
    #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \
      !defined(LIBRESSL_VERSION_NUMBER)
    
    #define SSLeay_add_ssl_algorithms() SSL_library_init()
    #define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER
    
    #define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */
    
    #define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */
    
    #define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */
    
    #if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \
      !defined(LIBRESSL_VERSION_NUMBER)
    
    #define HAVE_X509_GET0_SIGNATURE 1
    
    #if OPENSSL_VERSION_NUMBER >= 0x10002003L && \
      OPENSSL_VERSION_NUMBER <= 0x10002FFFL && \
      !defined(OPENSSL_NO_COMP)
    #define HAVE_SSL_COMP_FREE_COMPRESSION_METHODS 1
    #endif
    
    
    #if (OPENSSL_VERSION_NUMBER < 0x0090808fL)
    /* not present in older OpenSSL */
    
    #define OPENSSL_load_builtin_modules(x)
    #endif
    
    
    #if defined(LIBRESSL_VERSION_NUMBER)
    #define OSSL_PACKAGE "LibreSSL"
    #elif defined(OPENSSL_IS_BORINGSSL)
    #define OSSL_PACKAGE "BoringSSL"
    #else
    #define OSSL_PACKAGE "OpenSSL"
    #endif
    
    
    /*
     * Number of bytes to read from the random number seed file. This must be
     * a finite value (because some entropy "files" like /dev/urandom have
     * an infinite length), but must be large enough to provide enough
     * entopy to properly seed OpenSSL's PRNG.
     */
    #define RAND_LOAD_LENGTH 1024
    
    static int passwd_callback(char *buf, int num, int encrypting,
                               void *global_passwd)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
    
    Yang Tse's avatar
    Yang Tse committed
      DEBUGASSERT(0 == encrypting);
    
      if(!encrypting) {
        int klen = curlx_uztosi(strlen((char *)global_passwd));
        if(num > klen) {
          memcpy(buf, global_passwd, klen+1);
          return klen;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      return 0;
    }
    
    
    /*
     * rand_enough() is a function that returns TRUE if we have seeded the random
     * engine properly. We use some preprocessor magic to provide a seed_enough()
     * macro to use, just to prevent a compiler warning on this function if we
     * pass in an argument that is never used.
     */
    
    #ifdef HAVE_RAND_STATUS
    #define seed_enough(x) rand_enough()
    static bool rand_enough(void)
    {
    
      return (0 != RAND_status()) ? TRUE : FALSE;
    
    #define seed_enough(x) rand_enough(x)
    static bool rand_enough(int nread)
    {
      /* this is a very silly decision to make */
    
      return (nread > 500) ? TRUE : FALSE;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    static int ossl_seed(struct Curl_easy *data)
    
      char *buf = data->state.buffer; /* point to the big buffer */
    
      int nread=0;
    
      /* Q: should we add support for a random file name as a libcurl option?
    
         A: Yes, it is here */
    
    #ifndef RANDOM_FILE
      /* if RANDOM_FILE isn't defined, we only perform this if an option tells
         us to! */
    
    #define RANDOM_FILE "" /* doesn't matter won't be used */
    
      {
        /* let the option override the define */
    
        nread += RAND_load_file((data->set.str[STRING_SSL_RANDOM_FILE]?
                                 data->set.str[STRING_SSL_RANDOM_FILE]:
                                 RANDOM_FILE),
    
      /* only available in OpenSSL 0.9.5 and later */
    
      /* EGD_SOCKET is set at configure time or not at all */
    #ifndef EGD_SOCKET
      /* If we don't have the define set, we only do this if the egd-option
         is set */
    
      if(data->set.str[STRING_SSL_EGDSOCKET])
    
    #define EGD_SOCKET "" /* doesn't matter won't be used */
    #endif
    
        /* If there's an option and a define, the option overrides the
           define */
    
        int ret = RAND_egd(data->set.str[STRING_SSL_EGDSOCKET]?
                           data->set.str[STRING_SSL_EGDSOCKET]:EGD_SOCKET);
    
        if(-1 != ret) {
          nread += ret;
    
      }
    #endif
    
      /* If we get here, it means we need to seed the PRNG using a "silly"
         approach! */
    
      do {
        unsigned char randb[64];
    
        int len = sizeof(randb);
        RAND_bytes(randb, len);
    
        RAND_add(randb, len, (len >> 1));
      } while(!RAND_status());
    
      /* generates a default path for the random seed file */
      buf[0]=0; /* blank it first */
      RAND_file_name(buf, BUFSIZE);
    
        nread += RAND_load_file(buf, RAND_LOAD_LENGTH);
    
      infof(data, "libcurl is now using a weak random seed!\n");
    
    static void Curl_ossl_seed(struct Curl_easy *data)
    
    {
      /* we have the "SSL is seeded" boolean static to prevent multiple
         time-consuming seedings in vain */
      static bool ssl_seeded = FALSE;
    
    
      if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
         data->set.str[STRING_SSL_EGDSOCKET]) {
    
        ossl_seed(data);
        ssl_seeded = TRUE;
      }
    }
    
    
    #ifndef SSL_FILETYPE_ENGINE
    #define SSL_FILETYPE_ENGINE 42
    #endif
    
    #ifndef SSL_FILETYPE_PKCS12
    #define SSL_FILETYPE_PKCS12 43
    #endif
    
    static int do_file_type(const char *type)
    {
    
        return SSL_FILETYPE_PEM;
    
        return SSL_FILETYPE_PEM;
    
        return SSL_FILETYPE_ASN1;
    
        return SSL_FILETYPE_ENGINE;
    
    #if defined(HAVE_OPENSSL_ENGINE_H)
    
    /*
     * Supply default password to the engine user interface conversation.
     * The password is passed by OpenSSL engine from ENGINE_load_private_key()
     * last argument to the ui and can be obtained by UI_get0_user_data(ui) here.
     */
    static int ssl_ui_reader(UI *ui, UI_STRING *uis)
    {
      const char *password;
      switch(UI_get_string_type(uis)) {
      case UIT_PROMPT:
      case UIT_VERIFY:
        password = (const char*)UI_get0_user_data(ui);
    
        if(password && (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) {
    
          UI_set_result(ui, uis, password);
          return 1;
        }
      default:
        break;
      }
      return (UI_method_get_reader(UI_OpenSSL()))(ui, uis);
    }
    
    /*
     * Suppress interactive request for a default password if available.
     */
    static int ssl_ui_writer(UI *ui, UI_STRING *uis)
    {
      switch(UI_get_string_type(uis)) {
      case UIT_PROMPT:
      case UIT_VERIFY:
    
        if(UI_get0_user_data(ui) &&
           (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) {
    
          return 1;
        }
      default:
        break;
      }
      return (UI_method_get_writer(UI_OpenSSL()))(ui, uis);
    }
    #endif
    
    
    static
    int cert_stuff(struct connectdata *conn,
    
                   const char *cert_type,
                   char *key_file,
                   const char *key_type)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
    
      struct Curl_easy *data = conn->data;
    
      if(cert_file || (file_type == SSL_FILETYPE_ENGINE)) {
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        SSL *ssl;
        X509 *x509;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
        if(data->set.str[STRING_KEY_PASSWD]) {
    
          /* set the password in the callback userdata */
    
          SSL_CTX_set_default_passwd_cb_userdata(ctx,
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
          /* Set passwd callback: */
    
          SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
    
    
        switch(file_type) {
        case SSL_FILETYPE_PEM:
    
          /* SSL_CTX_use_certificate_chain_file() only works on PEM files */
    
          if(SSL_CTX_use_certificate_chain_file(ctx,
                                                cert_file) != 1) {
    
                  "could not load PEM client certificate, " OSSL_PACKAGE
                  " error %s, "
    
                  "(no key found, wrong pass phrase, or wrong file format?)",
                  ERR_error_string(ERR_get_error(), NULL) );
    
    
        case SSL_FILETYPE_ASN1:
          /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but
             we use the case above for PEM so this can only be performed with
             ASN1 files. */
    
          if(SSL_CTX_use_certificate_file(ctx,
                                          cert_file,
                                          file_type) != 1) {
    
                  "could not load ASN1 client certificate, " OSSL_PACKAGE
                  " error %s, "
    
                  "(no key found, wrong pass phrase, or wrong file format?)",
                  ERR_error_string(ERR_get_error(), NULL) );
    
        case SSL_FILETYPE_ENGINE:
    
    Yang Tse's avatar
     
    Yang Tse committed
    #if defined(HAVE_OPENSSL_ENGINE_H) && defined(ENGINE_CTRL_GET_CMD_FROM_NAME)
    
          {
            if(data->state.engine) {
              const char *cmd_name = "LOAD_CERT_CTRL";
              struct {
                const char *cert_id;
                X509 *cert;
              } params;
    
              params.cert_id = cert_file;
              params.cert = NULL;
    
              /* Does the engine supports LOAD_CERT_CTRL ? */
    
              if(!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
                              0, (void *)cmd_name, NULL)) {
    
                failf(data, "ssl engine does not support loading certificates");
                return 0;
              }
    
    Yang Tse's avatar
     
    Yang Tse committed
    
    
              /* Load the certificate from the engine */
    
              if(!ENGINE_ctrl_cmd(data->state.engine, cmd_name,
                                  0, &params, NULL, 1)) {
    
                failf(data, "ssl engine cannot load client cert with id"
                      " '%s' [%s]", cert_file,
                      ERR_error_string(ERR_get_error(), NULL));
                return 0;
              }
    
    
                failf(data, "ssl engine didn't initialized the certificate "
                      "properly.");
                return 0;
              }
    
              if(SSL_CTX_use_certificate(ctx, params.cert) != 1) {
                failf(data, "unable to set client certificate");
                X509_free(params.cert);
                return 0;
              }
              X509_free(params.cert); /* we don't need the handle any more... */
            }
            else {
              failf(data, "crypto engine not set, can't load certificate");
              return 0;
            }
          }
          break;
    #else
    
          failf(data, "file type ENG for certificate not implemented");
          return 0;
    
    #ifdef HAVE_OPENSSL_PKCS12_H
    
          f = fopen(cert_file, "rb");
    
            failf(data, "could not open PKCS12 file '%s'", cert_file);
            return 0;
          }
          p12 = d2i_PKCS12_fp(f, NULL);
          fclose(f);
    
    
            failf(data, "error reading PKCS12 file '%s'", cert_file);
    
          if(!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509,
    
                  "could not parse PKCS12 file, check password, " OSSL_PACKAGE
                  " error %s",
    
                  ERR_error_string(ERR_get_error(), NULL) );
    
            return 0;
          }
    
          PKCS12_free(p12);
    
          if(SSL_CTX_use_certificate(ctx, x509) != 1) {
    
                  "could not load PKCS12 client certificate, " OSSL_PACKAGE
                  " error %s",
    
                  ERR_error_string(ERR_get_error(), NULL) );
    
          }
    
          if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) {
            failf(data, "unable to use private key from PKCS12 file '%s'",
                  cert_file);
    
          if(!SSL_CTX_check_private_key (ctx)) {
    
            failf(data, "private key from PKCS12 file '%s' "
                  "does not match certificate in same file", cert_file);
    
          }
          /* Set Certificate Verification chain */
    
          if(ca) {
            while(sk_X509_num(ca)) {
    
              /*
               * Note that sk_X509_pop() is used below to make sure the cert is
               * removed from the stack properly before getting passed to
               * SSL_CTX_add_extra_chain_cert(). Previously we used
               * sk_X509_value() instead, but then we'd clean it in the subsequent
               * sk_X509_pop_free() call.
               */
              X509 *x = sk_X509_pop(ca);
              if(!SSL_CTX_add_extra_chain_cert(ctx, x)) {
    
                failf(data, "cannot add certificate to certificate chain");
    
              /* SSL_CTX_add_client_CA() seems to work with either sk_* function,
               * presumably because it duplicates what we pass to it.
               */
              if(!SSL_CTX_add_client_CA(ctx, x)) {
    
    Yang Tse's avatar
     
    Yang Tse committed
                failf(data, "cannot add certificate to client CA list");
    
          EVP_PKEY_free(pri);
          X509_free(x509);
    
          sk_X509_pop_free(ca, X509_free);
    
    
          if(!cert_done)
            return 0; /* failure! */
    
    #else
          failf(data, "file type P12 for certificate not supported");
          return 0;
    #endif
        }
    
        default:
          failf(data, "not supported file type '%s' for certificate", cert_type);
          return 0;
        }
    
        file_type = do_file_type(key_type);
    
        switch(file_type) {
        case SSL_FILETYPE_PEM:
    
            /* cert & key can only be in PEM case in the same file */
            key_file=cert_file;
        case SSL_FILETYPE_ASN1:
    
          if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
    
            failf(data, "unable to set private key file: '%s' type %s",
    
            return 0;
          }
          break;
        case SSL_FILETYPE_ENGINE:
    #ifdef HAVE_OPENSSL_ENGINE_H
    
          {                         /* XXXX still needs some work */
    
            EVP_PKEY *priv_key = NULL;
    
              UI_METHOD *ui_method =
                UI_create_method((char *)"cURL user interface");
    
                failf(data, "unable do create " OSSL_PACKAGE
                      " user-interface method");
    
                return 0;
              }
              UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL()));
              UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL()));
              UI_method_set_reader(ui_method, ssl_ui_reader);
              UI_method_set_writer(ui_method, ssl_ui_writer);
    
              /* the typecast below was added to please mingw32 */
              priv_key = (EVP_PKEY *)
    
                ENGINE_load_private_key(data->state.engine, key_file,
    
              UI_destroy_method(ui_method);
    
                failf(data, "failed to load private key from crypto engine");
    
              if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
    
                failf(data, "unable to set private key");
    
                EVP_PKEY_free(priv_key);
                return 0;
              }
    
              EVP_PKEY_free(priv_key);  /* we don't need the handle any more... */
    
              failf(data, "crypto engine not set, can't load private key");
    
          failf(data, "file type ENG for private key not supported");
    
        case SSL_FILETYPE_PKCS12:
          if(!cert_done) {
    
            failf(data, "file type P12 for private key not supported");
    
          failf(data, "not supported file type for private key");
    
          failf(data, "unable to create an SSL structure");
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        x509=SSL_get_certificate(ssl);
    
    
        /* This version was provided by Evan Jordan and is supposed to not
           leak memory as the previous version: */
    
          EVP_PKEY *pktmp = X509_get_pubkey(x509);
    
          EVP_PKEY_copy_parameters(pktmp, SSL_get_privatekey(ssl));
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        SSL_free(ssl);
    
        /* If we are using DSA, we can copy the parameters from
         * the private key */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        /* Now we know that a key and cert have been set against
         * the SSL context */
    
          failf(data, "Private key does not match the certificate public key");
    
    Yang Tse's avatar
     
    Yang Tse committed
          return 0;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        }
      }
    
    Yang Tse's avatar
     
    Yang Tse committed
      return 1;
    
    static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
    
    {
    #if 0
      return X509_NAME_oneline(a, buf, size);
    #else
      BIO *bio_out = BIO_new(BIO_s_mem());
      BUF_MEM *biomem;
      int rc;
    
    
      rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC);
    
      if((size_t)biomem->length < size)
    
        size = biomem->length;
      else
        size--; /* don't overwrite the buffer end */
    
      memcpy(buf, biomem->data, size);
      buf[size]=0;
    
      BIO_free(bio_out);
    
      return !rc;
    #endif
    }
    
    
    /* Return error string for last OpenSSL error
     */
    
    static char *ossl_strerror(unsigned long error, char *buf, size_t size)
    
    {
      /* OpenSSL 0.9.6 and later has a function named
    
    Daniel Melani's avatar
    Daniel Melani committed
         ERR_error_string_n() that takes the size of the buffer as a
    
         third argument */
      ERR_error_string_n(error, buf, size);
    
    Yang Tse's avatar
     
    Yang Tse committed
      return buf;
    
    /**
     * Global SSL init
     *
     * @retval 0 error initializing SSL
     * @retval 1 SSL initialized successfully
     */
    
      OPENSSL_load_builtin_modules();
    
    
    #ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES
      ENGINE_load_builtin_engines();
    #endif
    
    
      /* OPENSSL_config(NULL); is "strongly recommended" to use but unfortunately
         that function makes an exit() call on wrongly formatted config files
         which makes it hard to use in some situations. OPENSSL_config() itself
         calls CONF_modules_load_file() and we use that instead and we ignore
         its return code! */
    
    
      /* CONF_MFLAGS_DEFAULT_SECTION introduced some time between 0.9.8b and
         0.9.8e */
    #ifndef CONF_MFLAGS_DEFAULT_SECTION
    #define CONF_MFLAGS_DEFAULT_SECTION 0x0
    #endif
    
    
    Leith Bade's avatar
    Leith Bade committed
      CONF_modules_load_file(NULL, NULL,
                             CONF_MFLAGS_DEFAULT_SECTION|
                             CONF_MFLAGS_IGNORE_MISSING_FILE);
    
      /* Lets get nice error messages */
      SSL_load_error_strings();
    
      /* Init the global ciphers and digests */
      if(!SSLeay_add_ssl_algorithms())
        return 0;
    
      OpenSSL_add_all_algorithms();
    
    
    /* Global cleanup */
    void Curl_ossl_cleanup(void)
    {
    
      /* Free ciphers and digests lists */
    
      /* Free engine list */
    
    #ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
    
      /* Free OpenSSL ex_data table */
    
    
      /* Free OpenSSL error strings */
      ERR_free_strings();
    
      /* Free thread local error state, destroying hash upon zero refcount */
    
    #ifdef HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED
    
    
    #elif defined(HAVE_ERR_REMOVE_THREAD_STATE)
    
      ERR_remove_thread_state(NULL);
    #else
      ERR_remove_state(0);
    #endif
    
    
      /* Free all memory allocated by all configuration modules */
      CONF_modules_free();
    
    #ifdef HAVE_SSL_COMP_FREE_COMPRESSION_METHODS
    
      SSL_COMP_free_compression_methods();
    #endif
    
     * This function is used to determine connection status.
    
     *
     * Return codes:
     *     1 means the connection is still in place
     *     0 means the connection has been closed
     *    -1 means the connection status is unknown
     */
    int Curl_ossl_check_cxn(struct connectdata *conn)
    {
    
      /* SSL_peek takes data out of the raw recv buffer without peeking so we use
         recv MSG_PEEK instead. Bug #795 */
    
    #ifdef MSG_PEEK
    
      nread = recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
                   (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK);
      if(nread == 0)
    
        return 0; /* connection has been closed */
    
      else if(nread == 1)
    
        return 1; /* connection still in place */
    
      else if(nread == -1) {
          int err = SOCKERRNO;
          if(err == EINPROGRESS ||
    #if defined(EAGAIN) && (EAGAIN != EWOULDBLOCK)
             err == EAGAIN ||
    #endif
             err == EWOULDBLOCK)
            return 1; /* connection still in place */
          if(err == ECONNRESET ||
    #ifdef ECONNABORTED
             err == ECONNABORTED ||
    #endif
    #ifdef ENETDOWN
             err == ENETDOWN ||
    
    #ifdef ENETRESET
             err == ENETRESET ||
    #endif
    #ifdef ESHUTDOWN
             err == ESHUTDOWN ||
    #endif
    #ifdef ETIMEDOUT
             err == ETIMEDOUT ||
    #endif
             err == ENOTCONN)
            return 0; /* connection has been closed */
      }
    #endif
      return -1; /* connection status unknown */
    
    /* Selects an OpenSSL crypto engine
     */
    
    CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine)
    
    #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
    
    Yang Tse's avatar
     
    Yang Tse committed
      ENGINE *e;
    
    #if OPENSSL_VERSION_NUMBER >= 0x00909000L
      e = ENGINE_by_id(engine);
    #else
      /* avoid memory leak */
      for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) {
        const char *e_id = ENGINE_get_id(e);
        if(!strcmp(engine, e_id))
          break;
      }
    #endif
    
        failf(data, "SSL Engine '%s' not found", engine);
    
    Yang Tse's avatar
     
    Yang Tse committed
        return CURLE_SSL_ENGINE_NOTFOUND;
    
        ENGINE_finish(data->state.engine);
        ENGINE_free(data->state.engine);
    
        data->state.engine = NULL;
    
        char buf[256];
    
    
        ENGINE_free(e);
    
        failf(data, "Failed to initialise SSL Engine '%s':\n%s",
    
              engine, ossl_strerror(ERR_get_error(), buf, sizeof(buf)));
    
    Yang Tse's avatar
     
    Yang Tse committed
        return CURLE_SSL_ENGINE_INITFAILED;
    
    Yang Tse's avatar
     
    Yang Tse committed
      return CURLE_OK;
    
      failf(data, "SSL Engine not supported");
    
    Yang Tse's avatar
     
    Yang Tse committed
      return CURLE_SSL_ENGINE_NOTFOUND;
    
    /* Sets engine as default for all SSL operations
    
    CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data)
    
      if(data->state.engine) {
        if(ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) {
    
          infof(data, "set default crypto engine '%s'\n",
    
                ENGINE_get_id(data->state.engine));
    
          failf(data, "set default crypto engine '%s' failed",
                ENGINE_get_id(data->state.engine));
    
          return CURLE_SSL_ENGINE_SETFAILED;
        }
      }
    #else
      (void) data;
    #endif
    
    /* Return list of OpenSSL crypto engine names.
    
    struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data)
    
      struct curl_slist *list = NULL;
    
    #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
    
      struct curl_slist *beg;
    
      for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) {
    
        beg = curl_slist_append(list, ENGINE_get_id(e));
        if(!beg) {
          curl_slist_free_all(list);
    
          return NULL;
        }
    
        list = beg;
    
      (void) data;
    
    Yang Tse's avatar
     
    Yang Tse committed
      return list;
    
    /*
     * This function is called when an SSL connection is closed.
     */
    
    void Curl_ossl_close(struct connectdata *conn, int sockindex)
    
      struct ssl_connect_data *connssl = &conn->ssl[sockindex];
    
      if(connssl->handle) {
        (void)SSL_shutdown(connssl->handle);
        SSL_set_connect_state(connssl->handle);
    
        SSL_free (connssl->handle);
        connssl->handle = NULL;
      }
      if(connssl->ctx) {
        SSL_CTX_free (connssl->ctx);
        connssl->ctx = NULL;
    
    /*
     * This function is called to shut down the SSL layer but keep the
     * socket open (CCC - Clear Command Channel)
     */
    int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
    {
      int retval = 0;
      struct ssl_connect_data *connssl = &conn->ssl[sockindex];
    
      struct Curl_easy *data = conn->data;
    
      char buf[256]; /* We will use this for the OpenSSL error buffer, so it has
                        to be at least 256 bytes long. */
    
      int err;
      int done = 0;
    
      /* This has only been tested on the proftpd server, and the mod_tls code
         sends a close notify alert without waiting for a close notify alert in
         response. Thus we wait for a close notify alert from the server, but
         we do not send one. Let's hope other servers do the same... */
    
    
      if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
          (void)SSL_shutdown(connssl->handle);
    
    
          int what = Curl_socket_ready(conn->sock[sockindex],
    
                                       CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
    
            /* Something to read, let's do it and hope that it is the close
               notify alert from the server */
            nread = (ssize_t)SSL_read(conn->ssl[sockindex].handle, buf,
    
            err = SSL_get_error(conn->ssl[sockindex].handle, (int)nread);
    
            switch(err) {
            case SSL_ERROR_NONE: /* this is not an error */
            case SSL_ERROR_ZERO_RETURN: /* no more data */
              /* This is the expected response. There was no data but only
                 the close notify alert */
              done = 1;
              break;
            case SSL_ERROR_WANT_READ:
              /* there's data pending, re-invoke SSL_read() */
              infof(data, "SSL_ERROR_WANT_READ\n");
              break;
            case SSL_ERROR_WANT_WRITE:
              /* SSL wants a write. Really odd. Let's bail out. */
              infof(data, "SSL_ERROR_WANT_WRITE\n");
              done = 1;
              break;
            default:
              /* openssl/ssl.h says "look at error stack/return value/errno" */
              sslerror = ERR_get_error();
    
              failf(conn->data, OSSL_PACKAGE " SSL read: %s, errno %d",
    
                    ossl_strerror(sslerror, buf, sizeof(buf)),
    
              done = 1;
              break;
            }
          }
          else if(0 == what) {
            /* timeout */
            failf(data, "SSL shutdown timeout");
            done = 1;
          }
          else {
            /* anything that gets here is fatally bad */
    
    Yang Tse's avatar
    Yang Tse committed
            failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
    
            retval = -1;
            done = 1;
          }
        } /* while()-loop for the select() */