Newer
Older
/***************************************************************************
Daniel Stenberg
committed
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
* 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
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.
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
***************************************************************************/
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.
Daniel Stenberg
committed
*/
/*
* The original SSLeay-using code for curl was written by Linas Vepstas and
* Sampo Kellomaki 1998.
#include "curl_setup.h"
#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 "slist.h"
#include "strequal.h"
#include "select.h"
#include "rawstr.h"
#include "hostcheck.h"
Daniel Stenberg
committed
#include <openssl/rand.h>
#include <openssl/x509v3.h>
Daniel Stenberg
committed
#include <openssl/dsa.h>
#include <openssl/dh.h>
#include <openssl/err.h>
#include <openssl/md5.h>
#include <openssl/conf.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#ifdef HAVE_OPENSSL_PKCS12_H
#include <openssl/pkcs12.h>
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
#include <openssl/ocsp.h>
#include "warnless.h"
#include "non-ascii.h" /* for Curl_convert_from_utf8 prototype */
/* The last #include files should be: */
#include "curl_memory.h"
#ifndef OPENSSL_VERSION_NUMBER
#error "OPENSSL_VERSION_NUMBER not defined"
#endif
#if defined(HAVE_OPENSSL_ENGINE_H)
Daniel Stenberg
committed
#include <openssl/ui.h>
#endif
#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)
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
committed
}
Daniel Stenberg
committed
/*
* 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.
*/
Daniel Stenberg
committed
#ifdef HAVE_RAND_STATUS
#define seed_enough(x) rand_enough()
static bool rand_enough(void)
{
return (0 != RAND_status()) ? TRUE : FALSE;
Daniel Stenberg
committed
}
Daniel Stenberg
committed
#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
committed
#endif
static int ossl_seed(struct Curl_easy *data)
Daniel Stenberg
committed
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! */
Daniel Stenberg
committed
if(data->set.ssl.random_file)
#define RANDOM_FILE "" /* doesn't matter won't be used */
{
/* let the option override the define */
Daniel Stenberg
committed
nread += RAND_load_file((data->set.str[STRING_SSL_RANDOM_FILE]?
data->set.str[STRING_SSL_RANDOM_FILE]:
RANDOM_FILE),
RAND_LOAD_LENGTH);
Daniel Stenberg
committed
if(seed_enough(nread))
#if defined(HAVE_RAND_EGD)
/* 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 */
Daniel Stenberg
committed
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 */
Daniel Stenberg
committed
int ret = RAND_egd(data->set.str[STRING_SSL_EGDSOCKET]?
data->set.str[STRING_SSL_EGDSOCKET]:EGD_SOCKET);
if(-1 != ret) {
nread += ret;
Daniel Stenberg
committed
if(seed_enough(nread))
return nread;
}
}
#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);
if(buf[0]) {
/* we got a file name to try */
nread += RAND_load_file(buf, RAND_LOAD_LENGTH);
Daniel Stenberg
committed
if(seed_enough(nread))
return nread;
}
Daniel Stenberg
committed
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;
Daniel Stenberg
committed
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)
{
if(!type || !type[0])
Daniel Stenberg
committed
if(Curl_raw_equal(type, "PEM"))
Daniel Stenberg
committed
if(Curl_raw_equal(type, "DER"))
Daniel Stenberg
committed
if(Curl_raw_equal(type, "ENG"))
Daniel Stenberg
committed
if(Curl_raw_equal(type, "P12"))
return SSL_FILETYPE_PKCS12;
#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,
Daniel Stenberg
committed
SSL_CTX* ctx,
char *cert_file,
const char *cert_type,
char *key_file,
const char *key_type)
struct Curl_easy *data = conn->data;
Daniel Stenberg
committed
int file_type = do_file_type(cert_type);
if(cert_file || (file_type == SSL_FILETYPE_ENGINE)) {
int cert_done = 0;
Daniel Stenberg
committed
if(data->set.str[STRING_KEY_PASSWD]) {
/* set the password in the callback userdata */
Daniel Stenberg
committed
SSL_CTX_set_default_passwd_cb_userdata(ctx,
Daniel Stenberg
committed
data->set.str[STRING_KEY_PASSWD]);
Daniel Stenberg
committed
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 */
Daniel Stenberg
committed
if(SSL_CTX_use_certificate_chain_file(ctx,
cert_file) != 1) {
failf(data,
"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. */
Daniel Stenberg
committed
if(SSL_CTX_use_certificate_file(ctx,
cert_file,
file_type) != 1) {
failf(data,
"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) );
return 0;
}
break;
Daniel Stenberg
committed
{
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)) {
Daniel Stenberg
committed
failf(data, "ssl engine does not support loading certificates");
return 0;
}
Daniel Stenberg
committed
/* Load the certificate from the engine */
if(!ENGINE_ctrl_cmd(data->state.engine, cmd_name,
0, ¶ms, NULL, 1)) {
Daniel Stenberg
committed
failf(data, "ssl engine cannot load client cert with id"
" '%s' [%s]", cert_file,
ERR_error_string(ERR_get_error(), NULL));
return 0;
}
if(!params.cert) {
Daniel Stenberg
committed
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;
Daniel Stenberg
committed
#endif
case SSL_FILETYPE_PKCS12:
{
FILE *f;
PKCS12 *p12;
EVP_PKEY *pri;
STACK_OF(X509) *ca = NULL;
Daniel Stenberg
committed
if(!f) {
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;
}
PKCS12_PBE_add();
Daniel Stenberg
committed
if(!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509,
failf(data,
"could not parse PKCS12 file, check password, " OSSL_PACKAGE
" error %s",
ERR_error_string(ERR_get_error(), NULL) );
PKCS12_free(p12);
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)) {
X509_free(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)) {
}
}
}
cert_done = 1;
fail:
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:
if(cert_done)
break;
/* cert & key can only be in PEM case in the same file */
key_file=cert_file;
case SSL_FILETYPE_ASN1:
Daniel Stenberg
committed
if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
Daniel Stenberg
committed
failf(data, "unable to set private key file: '%s' type %s",
key_file, key_type?key_type:"PEM");
return 0;
}
break;
case SSL_FILETYPE_ENGINE:
#ifdef HAVE_OPENSSL_ENGINE_H
{ /* XXXX still needs some work */
Daniel Stenberg
committed
if(data->state.engine) {
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,
Daniel Stenberg
committed
data->set.str[STRING_KEY_PASSWD]);
UI_destroy_method(ui_method);
if(!priv_key) {
Daniel Stenberg
committed
failf(data, "failed to load private key from crypto engine");
Daniel Stenberg
committed
if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
Daniel Stenberg
committed
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... */
Daniel Stenberg
committed
failf(data, "crypto engine not set, can't load private key");
Daniel Stenberg
committed
failf(data, "file type ENG for private key not supported");
case SSL_FILETYPE_PKCS12:
if(!cert_done) {
Daniel Stenberg
committed
failf(data, "file type P12 for private key not supported");
Daniel Stenberg
committed
return 0;
}
break;
Daniel Stenberg
committed
failf(data, "not supported file type for private key");
Daniel Stenberg
committed
ssl=SSL_new(ctx);
failf(data, "unable to create an SSL structure");
/* 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);
}
SSL_free(ssl);
/* If we are using DSA, we can copy the parameters from
* the private key */
Daniel Stenberg
committed
/* Now we know that a key and cert have been set against
* the SSL context */
Daniel Stenberg
committed
if(!SSL_CTX_check_private_key(ctx)) {
failf(data, "Private key does not match the certificate public key");
Daniel Stenberg
committed
/* returns non-zero on failure */
static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
Daniel Stenberg
committed
{
#if 0
return X509_NAME_oneline(a, buf, size);
#else
BIO *bio_out = BIO_new(BIO_s_mem());
BUF_MEM *biomem;
int rc;
Daniel Stenberg
committed
if(!bio_out)
return 1; /* alloc failed! */
Daniel Stenberg
committed
rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC);
Daniel Stenberg
committed
BIO_get_mem_ptr(bio_out, &biomem);
if((size_t)biomem->length < size)
Daniel Stenberg
committed
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
ERR_error_string_n() that takes the size of the buffer as a
third argument */
ERR_error_string_n(error, buf, size);
/**
* Global SSL init
*
* @retval 0 error initializing SSL
* @retval 1 SSL initialized successfully
*/
Daniel Stenberg
committed
int Curl_ossl_init(void)
{
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
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();
}
Daniel Stenberg
committed
/* Global cleanup */
void Curl_ossl_cleanup(void)
{
/* Free ciphers and digests lists */
Daniel Stenberg
committed
EVP_cleanup();
Daniel Stenberg
committed
Daniel Stenberg
committed
#ifdef HAVE_ENGINE_CLEANUP
/* Free engine list */
Daniel Stenberg
committed
ENGINE_cleanup();
#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
/* Free OpenSSL ex_data table */
Daniel Stenberg
committed
CRYPTO_cleanup_all_ex_data();
/* 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 */
char buf;
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 */
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)
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
Daniel Stenberg
committed
if(!e) {
failf(data, "SSL Engine '%s' not found", engine);
Daniel Stenberg
committed
if(data->state.engine) {
Daniel Stenberg
committed
ENGINE_finish(data->state.engine);
ENGINE_free(data->state.engine);
data->state.engine = NULL;
Daniel Stenberg
committed
if(!ENGINE_init(e)) {
failf(data, "Failed to initialise SSL Engine '%s':\n%s",
engine, ossl_strerror(ERR_get_error(), buf, sizeof(buf)));
Daniel Stenberg
committed
data->state.engine = e;
(void)engine;
failf(data, "SSL Engine not supported");
Daniel Stenberg
committed
/* Sets engine as default for all SSL operations
CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data)
Daniel Stenberg
committed
#ifdef HAVE_OPENSSL_ENGINE_H
Daniel Stenberg
committed
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
Daniel Stenberg
committed
return CURLE_OK;
/* Return list of OpenSSL crypto engine names.
struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data)
#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
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);
/*
* This function is called when an SSL connection is closed.
*/
Daniel Stenberg
committed
void Curl_ossl_close(struct connectdata *conn, int sockindex)
{
Daniel Stenberg
committed
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
Daniel Stenberg
committed
if(connssl->handle) {
(void)SSL_shutdown(connssl->handle);
SSL_set_connect_state(connssl->handle);
Daniel Stenberg
committed
SSL_free (connssl->handle);
connssl->handle = NULL;
}
if(connssl->ctx) {
SSL_CTX_free (connssl->ctx);
connssl->ctx = NULL;
}
}
Daniel Stenberg
committed
/*
* 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. */
Daniel Stenberg
committed
unsigned long sslerror;
ssize_t nread;
Yang Tse
committed
int buffsize;
Daniel Stenberg
committed
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... */
Linus Nielsen
committed
if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
(void)SSL_shutdown(connssl->handle);
Daniel Stenberg
committed
if(connssl->handle) {
Yang Tse
committed
buffsize = (int)sizeof(buf);
Daniel Stenberg
committed
while(!done) {
int what = Curl_socket_ready(conn->sock[sockindex],
CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
Daniel Stenberg
committed
if(what > 0) {
ERR_clear_error();
Daniel Stenberg
committed
/* 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,
Yang Tse
committed
buffsize);
Daniel Stenberg
committed
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)),
SOCKERRNO);
Daniel Stenberg
committed
done = 1;
break;
}
}
else if(0 == what) {
/* timeout */
failf(data, "SSL shutdown timeout");
done = 1;
}
else {
/* anything that gets here is fatally bad */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
Daniel Stenberg
committed
retval = -1;
done = 1;
}
} /* while()-loop for the select() */