Skip to content
openssl.c 81.9 KiB
Newer Older
/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
Daniel Stenberg's avatar
Daniel Stenberg committed
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2014, 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 http://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 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"
Daniel Stenberg's avatar
Daniel Stenberg committed

#define _MPRINTF_REPLACE /* use the internal *printf() functions */
#include <curl/mprintf.h>

Daniel Stenberg's avatar
Daniel Stenberg committed
#ifdef USE_SSLEAY
#include <openssl/rand.h>
#include <openssl/dsa.h>
#include <openssl/dh.h>
#include <openssl/err.h>
#else
#include <rand.h>
#include <x509v3.h>
Daniel Stenberg's avatar
Daniel Stenberg committed

#include "warnless.h"
#include "curl_memory.h"
#include "non-ascii.h" /* for Curl_convert_from_utf8 prototype */
/* The last #include file should be: */
#include "memdebug.h"
#ifndef OPENSSL_VERSION_NUMBER
#error "OPENSSL_VERSION_NUMBER not defined"
#endif

#if OPENSSL_VERSION_NUMBER >= 0x0090581fL
#define HAVE_SSL_GET1_SESSION 1
#else
#undef HAVE_SSL_GET1_SESSION
#endif

#if OPENSSL_VERSION_NUMBER >= 0x00904100L
#define HAVE_USERDATA_IN_PWD_CALLBACK 1
#else
#undef HAVE_USERDATA_IN_PWD_CALLBACK
#endif

#if OPENSSL_VERSION_NUMBER >= 0x00907001L
/* ENGINE_load_private_key() takes four arguments */
#define HAVE_ENGINE_LOAD_FOUR_ARGS
#else
/* ENGINE_load_private_key() takes three arguments */
#undef HAVE_ENGINE_LOAD_FOUR_ARGS
#endif

#if (OPENSSL_VERSION_NUMBER >= 0x00903001L) && defined(HAVE_OPENSSL_PKCS12_H)
/* OpenSSL has PKCS 12 support */
#define HAVE_PKCS12_SUPPORT
#else
/* OpenSSL/SSLEay does not have PKCS12 support */
#undef HAVE_PKCS12_SUPPORT
#endif

#if OPENSSL_VERSION_NUMBER >= 0x00906001L
#define HAVE_ERR_ERROR_STRING_N 1
#endif

#if OPENSSL_VERSION_NUMBER >= 0x00909000L
#define SSL_METHOD_QUAL const
#else
#define SSL_METHOD_QUAL
#endif

#if OPENSSL_VERSION_NUMBER >= 0x00907000L
/* 0.9.6 didn't have X509_STORE_set_flags() */
#define HAVE_X509_STORE_SET_FLAGS 1
#else
#define X509_STORE_set_flags(x,y) Curl_nop_stmt
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
#define HAVE_ERR_REMOVE_THREAD_STATE 1
#endif

#ifndef HAVE_SSLV2_CLIENT_METHOD
#undef OPENSSL_NO_SSL2 /* undef first to avoid compiler warnings */
#define OPENSSL_NO_SSL2
#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
#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
Daniel Stenberg's avatar
Daniel Stenberg committed
static char global_passwd[64];
Daniel Stenberg's avatar
Daniel Stenberg committed

Yang Tse's avatar
Yang Tse committed
static int passwd_callback(char *buf, int num, int encrypting
Patrick Monnerat's avatar
Patrick Monnerat committed
#ifdef HAVE_USERDATA_IN_PWD_CALLBACK
Daniel Stenberg's avatar
Daniel Stenberg committed
                           /* This was introduced in 0.9.4, we can set this
                              using SSL_CTX_set_default_passwd_cb_userdata()
                              */
Daniel Stenberg's avatar
Daniel Stenberg committed
#endif
                           )
{
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 SessionHandle *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");
int Curl_ossl_seed(struct SessionHandle *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;
  }
  return 0;
}


#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) && defined(HAVE_ENGINE_LOAD_FOUR_ARGS)
/*
 * 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(NULL != 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(NULL != 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 SessionHandle *data = conn->data;
  int file_type = do_file_type(cert_type);

  if(cert_file != NULL || 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]) {
#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
Daniel Stenberg's avatar
Daniel Stenberg committed
      /*
       * If password has been given, we store that in the global
       * area (*shudder*) for a while:
       */
      size_t len = strlen(data->set.str[STRING_KEY_PASSWD]);
        memcpy(global_passwd, data->set.str[STRING_KEY_PASSWD], len+1);
Yang Tse's avatar
Yang Tse committed
      else
        global_passwd[0] = '\0';
#else
      /*
       * We 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);
#define SSL_CLIENT_CERT_ERR \
    "unable to use client certificate (no key found or wrong pass phrase?)"

    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) {
        failf(data, SSL_CLIENT_CERT_ERR);

    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) {
        failf(data, SSL_CLIENT_CERT_ERR);
    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;
    case SSL_FILETYPE_PKCS12:
    {
#ifdef HAVE_PKCS12_SUPPORT
      FILE *f;
      PKCS12 *p12;
      EVP_PKEY *pri;
      STACK_OF(X509) *ca = NULL;
      int i;
        failf(data, "could not open PKCS12 file '%s'", cert_file);
        return 0;
      }
      p12 = d2i_PKCS12_fp(f, NULL);
      fclose(f);

      if(!p12) {
        failf(data, "error reading PKCS12 file '%s'", cert_file );
        return 0;
      }

      if(!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509,
        failf(data,
              "could not parse PKCS12 file, check password, OpenSSL error %s",
              ERR_error_string(ERR_get_error(), NULL) );
        return 0;
      }

      PKCS12_free(p12);

      if(SSL_CTX_use_certificate(ctx, x509) != 1) {
        failf(data, SSL_CLIENT_CERT_ERR);
      }

      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 && sk_X509_num(ca)) {
        for(i = 0; i < sk_X509_num(ca); i++) {
          /*
           * 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");
          if(NULL == ui_method) {
            failf(data, "unable do create OpenSSL 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,
#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
          UI_destroy_method(ui_method);
#endif
            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... */
        }
        else {
          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));
      EVP_PKEY_free(pktmp);
    }

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
    }
Daniel Stenberg's avatar
Daniel Stenberg committed
    /* erase it now */
    memset(global_passwd, 0, sizeof(global_passwd));
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
}

Daniel Stenberg's avatar
Daniel Stenberg committed
int cert_verify_callback(int ok, X509_STORE_CTX *ctx)
{
  X509 *err_cert;
  char buf[256];

  err_cert=X509_STORE_CTX_get_current_cert(ctx);
  (void)x509_name_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
/* Return error string for last OpenSSL error
 */
static char *SSL_strerror(unsigned long error, char *buf, size_t size)
{
#ifdef HAVE_ERR_ERROR_STRING_N
  /* OpenSSL 0.9.6 and later has a function named
     ERRO_error_string_n() that takes the size of the buffer as a
     third argument */
  ERR_error_string_n(error, buf, size);
#else
  (void) size;
  ERR_error_string(error, buf);
#endif
Yang Tse's avatar
 
Yang Tse committed
  return buf;
#endif /* USE_SSLEAY */
/**
 * Global SSL init
 *
 * @retval 0 error initializing SSL
 * @retval 1 SSL initialized successfully
 */
#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES
  ENGINE_load_builtin_engines();
#endif

  /* Lets get nice error messages */
  SSL_load_error_strings();

  /* Init the global ciphers and digests */
Daniel Stenberg's avatar
Daniel Stenberg committed
  if(!SSLeay_add_ssl_algorithms())
    return 0;

/* 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
  ERR_remove_thread_state(NULL);
#else
  ERR_remove_state(0);
#endif
/*
 * This function uses SSL_peek 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)
{
  int rc;
  char buf;

  rc = SSL_peek(conn->ssl[FIRSTSOCKET].handle, (void*)&buf, 1);
    return 1; /* connection still in place */

    return 0; /* connection has been closed */

  return -1; /* connection status unknown */
}

/* Selects an OpenSSL crypto engine
 */
CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine)
{
#if defined(USE_SSLEAY) && 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, SSL_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 SessionHandle *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 SessionHandle *data)
  struct curl_slist *list = NULL;
#if defined(USE_SSLEAY) && 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 SessionHandle *data = conn->data;
  char buf[120]; /* We will use this for the OpenSSL error buffer, so it has
                    to be at least 120 bytes long. */
  unsigned long sslerror;
  ssize_t nread;
  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, "SSL read: %s, errno %d",
                ERR_error_string(sslerror, 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() */

    if(data->set.verbose) {
      switch(SSL_get_shutdown(connssl->handle)) {
      case SSL_SENT_SHUTDOWN:
        infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n");
        break;
      case SSL_RECEIVED_SHUTDOWN:
        infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n");
        break;
      case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN:
        infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|"
              "SSL_RECEIVED__SHUTDOWN\n");
        break;