summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib/vtls/openssl.c
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2015-08-12 19:43:52 (GMT)
committerBrad King <brad.king@kitware.com>2015-08-12 19:43:52 (GMT)
commit91e8d35ab8ec2d62478a42eff10af88713497fad (patch)
treeff8cd1bd1ce3c42ef56c76b5ab471831a80c4665 /Utilities/cmcurl/lib/vtls/openssl.c
parent602cdc06a01b7c5c0eb444111382b09040f677ee (diff)
parent706542615828488a5ad197d0ef3dd5e42eb739c4 (diff)
downloadCMake-91e8d35ab8ec2d62478a42eff10af88713497fad.zip
CMake-91e8d35ab8ec2d62478a42eff10af88713497fad.tar.gz
CMake-91e8d35ab8ec2d62478a42eff10af88713497fad.tar.bz2
Merge branch 'curl-upstream' into update-curl
Resolve conflicts by taking upstream side when possible and otherwise integrating the changes from both sides. Be carful in CMakeLists.txt where the OPENSSL code block that we modified previously has moved, and preserve our previous modifications in the new location.
Diffstat (limited to 'Utilities/cmcurl/lib/vtls/openssl.c')
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.c1091
1 files changed, 691 insertions, 400 deletions
diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c
index da92854..90e4c2b 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.c
+++ b/Utilities/cmcurl/lib/vtls/openssl.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2015, 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
@@ -32,6 +32,8 @@
#include "curl_setup.h"
+#ifdef USE_OPENSSL
+
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
@@ -49,13 +51,9 @@
#include "vtls.h"
#include "rawstr.h"
#include "hostcheck.h"
+#include "curl_printf.h"
-#define _MPRINTF_REPLACE /* use the internal *printf() functions */
-#include <curl/mprintf.h>
-
-#ifdef USE_SSLEAY
-
-#ifdef USE_OPENSSL
+#include <openssl/ssl.h>
#include <openssl/rand.h>
#include <openssl/x509v3.h>
#include <openssl/dsa.h>
@@ -63,36 +61,29 @@
#include <openssl/err.h>
#include <openssl/md5.h>
#include <openssl/conf.h>
-#else
-#include <rand.h>
-#include <x509v3.h>
-#include <md5.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_IS_BORINGSSL)
+#include <openssl/ocsp.h>
#endif
#include "warnless.h"
-#include "curl_memory.h"
#include "non-ascii.h" /* for Curl_convert_from_utf8 prototype */
-/* The last #include file should be: */
+/* 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 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
+#if OPENSSL_VERSION_NUMBER >= 0x00907001L && !defined(OPENSSL_IS_BORINGSSL)
/* ENGINE_load_private_key() takes four arguments */
#define HAVE_ENGINE_LOAD_FOUR_ARGS
#include <openssl/ui.h>
@@ -101,18 +92,16 @@
#undef HAVE_ENGINE_LOAD_FOUR_ARGS
#endif
-#if (OPENSSL_VERSION_NUMBER >= 0x00903001L) && defined(HAVE_OPENSSL_PKCS12_H)
-/* OpenSSL has PKCS 12 support */
+#if (OPENSSL_VERSION_NUMBER >= 0x00903001L) && \
+ defined(HAVE_OPENSSL_PKCS12_H) && \
+ !defined(OPENSSL_IS_BORINGSSL)
+/* OpenSSL has PKCS 12 support, BoringSSL does not */
#define HAVE_PKCS12_SUPPORT
#else
-/* OpenSSL/SSLEay does not have PKCS12 support */
+/* OpenSSL 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
@@ -126,15 +115,32 @@
#define X509_STORE_set_flags(x,y) Curl_nop_stmt
#endif
-#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+#ifdef OPENSSL_IS_BORINGSSL
+/* BoringSSL has no ERR_remove_state() */
+#define ERR_remove_state(x)
+#elif (OPENSSL_VERSION_NUMBER >= 0x10000000L)
#define HAVE_ERR_REMOVE_THREAD_STATE 1
#endif
-#ifndef HAVE_SSLV2_CLIENT_METHOD
+#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 defined(OPENSSL_IS_BORINGSSL)
+#define NO_RAND_SEED 1
+/* In BoringSSL OpenSSL_add_all_algorithms does nothing */
+#define OpenSSL_add_all_algorithms()
+/* BoringSSL does not have CONF_modules_load_file */
+#define CONF_modules_load_file(a,b,c)
+#endif
+
+#if (OPENSSL_VERSION_NUMBER < 0x0090808fL) || defined(OPENSSL_IS_BORINGSSL)
+/* not present in BoringSSL or older OpenSSL */
+#define OPENSSL_load_builtin_modules(x)
+#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
@@ -143,18 +149,8 @@
*/
#define RAND_LOAD_LENGTH 1024
-#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
-static char global_passwd[64];
-#endif
-
-static int passwd_callback(char *buf, int num, int encrypting
-#ifdef HAVE_USERDATA_IN_PWD_CALLBACK
- /* This was introduced in 0.9.4, we can set this
- using SSL_CTX_set_default_passwd_cb_userdata()
- */
- , void *global_passwd
-#endif
- )
+static int passwd_callback(char *buf, int num, int encrypting,
+ void *global_passwd)
{
DEBUGASSERT(0 == encrypting);
@@ -175,6 +171,7 @@ static int passwd_callback(char *buf, int num, int encrypting
* pass in an argument that is never used.
*/
+#ifndef NO_RAND_SEED
#ifdef HAVE_RAND_STATUS
#define seed_enough(x) rand_enough()
static bool rand_enough(void)
@@ -259,7 +256,7 @@ static int ossl_seed(struct SessionHandle *data)
return nread;
}
-static int Curl_ossl_seed(struct SessionHandle *data)
+static void Curl_ossl_seed(struct SessionHandle *data)
{
/* we have the "SSL is seeded" boolean static to prevent multiple
time-consuming seedings in vain */
@@ -270,8 +267,11 @@ static int Curl_ossl_seed(struct SessionHandle *data)
ossl_seed(data);
ssl_seeded = TRUE;
}
- return 0;
}
+#else
+/* BoringSSL needs no seeding */
+#define Curl_ossl_seed(x)
+#endif
#ifndef SSL_FILETYPE_ENGINE
@@ -308,8 +308,7 @@ static int ssl_ui_reader(UI *ui, UI_STRING *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) {
+ if(password && (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) {
UI_set_result(ui, uis, password);
return 1;
}
@@ -327,8 +326,8 @@ 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) {
+ if(UI_get0_user_data(ui) &&
+ (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) {
return 1;
}
default:
@@ -350,43 +349,29 @@ int cert_stuff(struct connectdata *conn,
int file_type = do_file_type(cert_type);
- if(cert_file != NULL || file_type == SSL_FILETYPE_ENGINE) {
+ if(cert_file || (file_type == SSL_FILETYPE_ENGINE)) {
SSL *ssl;
X509 *x509;
int cert_done = 0;
if(data->set.str[STRING_KEY_PASSWD]) {
-#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
- /*
- * 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]);
- if(len < sizeof(global_passwd))
- memcpy(global_passwd, data->set.str[STRING_KEY_PASSWD], len+1);
- else
- global_passwd[0] = '\0';
-#else
- /*
- * We set the password in the callback userdata
- */
+ /* set the password in the callback userdata */
SSL_CTX_set_default_passwd_cb_userdata(ctx,
data->set.str[STRING_KEY_PASSWD]);
-#endif
/* 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);
+ failf(data,
+ "could not load PEM client certificate, OpenSSL error %s, "
+ "(no key found, wrong pass phrase, or wrong file format?)",
+ ERR_error_string(ERR_get_error(), NULL) );
return 0;
}
break;
@@ -398,7 +383,10 @@ int cert_stuff(struct connectdata *conn,
if(SSL_CTX_use_certificate_file(ctx,
cert_file,
file_type) != 1) {
- failf(data, SSL_CLIENT_CERT_ERR);
+ failf(data,
+ "could not load ASN1 client certificate, OpenSSL error %s, "
+ "(no key found, wrong pass phrase, or wrong file format?)",
+ ERR_error_string(ERR_get_error(), NULL) );
return 0;
}
break;
@@ -464,7 +452,7 @@ int cert_stuff(struct connectdata *conn,
STACK_OF(X509) *ca = NULL;
int i;
- f = fopen(cert_file,"rb");
+ f = fopen(cert_file, "rb");
if(!f) {
failf(data, "could not open PKCS12 file '%s'", cert_file);
return 0;
@@ -473,7 +461,7 @@ int cert_stuff(struct connectdata *conn,
fclose(f);
if(!p12) {
- failf(data, "error reading PKCS12 file '%s'", cert_file );
+ failf(data, "error reading PKCS12 file '%s'", cert_file);
return 0;
}
@@ -491,7 +479,9 @@ int cert_stuff(struct connectdata *conn,
PKCS12_free(p12);
if(SSL_CTX_use_certificate(ctx, x509) != 1) {
- failf(data, SSL_CLIENT_CERT_ERR);
+ failf(data,
+ "could not load PKCS12 client certificate, OpenSSL error %s",
+ ERR_error_string(ERR_get_error(), NULL) );
goto fail;
}
@@ -556,7 +546,7 @@ int cert_stuff(struct connectdata *conn,
case SSL_FILETYPE_PEM:
if(cert_done)
break;
- if(key_file == NULL)
+ if(!key_file)
/* cert & key can only be in PEM case in the same file */
key_file=cert_file;
case SSL_FILETYPE_ASN1:
@@ -574,7 +564,7 @@ int cert_stuff(struct connectdata *conn,
#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
UI_METHOD *ui_method =
UI_create_method((char *)"cURL user interface");
- if(NULL == ui_method) {
+ if(!ui_method) {
failf(data, "unable do create OpenSSL user-interface method");
return 0;
}
@@ -585,7 +575,7 @@ int cert_stuff(struct connectdata *conn,
#endif
/* the typecast below was added to please mingw32 */
priv_key = (EVP_PKEY *)
- ENGINE_load_private_key(data->state.engine,key_file,
+ ENGINE_load_private_key(data->state.engine, key_file,
#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
ui_method,
#endif
@@ -626,8 +616,8 @@ int cert_stuff(struct connectdata *conn,
}
ssl=SSL_new(ctx);
- if(NULL == ssl) {
- failf(data,"unable to create an SSL structure");
+ if(!ssl) {
+ failf(data, "unable to create an SSL structure");
return 0;
}
@@ -635,9 +625,9 @@ int cert_stuff(struct connectdata *conn,
/* This version was provided by Evan Jordan and is supposed to not
leak memory as the previous version: */
- if(x509 != NULL) {
+ if(x509) {
EVP_PKEY *pktmp = X509_get_pubkey(x509);
- EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(ssl));
+ EVP_PKEY_copy_parameters(pktmp, SSL_get_privatekey(ssl));
EVP_PKEY_free(pktmp);
}
@@ -653,10 +643,6 @@ int cert_stuff(struct connectdata *conn,
failf(data, "Private key does not match the certificate public key");
return 0;
}
-#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
- /* erase it now */
- memset(global_passwd, 0, sizeof(global_passwd));
-#endif
}
return 1;
}
@@ -691,36 +677,17 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
#endif
}
-static
-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 ok;
-}
-
/* 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
+ ERR_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
return buf;
}
-#endif /* USE_SSLEAY */
-
-#ifdef USE_SSLEAY
/**
* Global SSL init
*
@@ -729,6 +696,8 @@ static char *SSL_strerror(unsigned long error, char *buf, size_t size)
*/
int Curl_ossl_init(void)
{
+ OPENSSL_load_builtin_modules();
+
#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES
ENGINE_load_builtin_engines();
#endif
@@ -749,17 +718,19 @@ int Curl_ossl_init(void)
calls CONF_modules_load_file() and we use that instead and we ignore
its return code! */
- (void)CONF_modules_load_file(NULL, NULL,
- CONF_MFLAGS_DEFAULT_SECTION|
- CONF_MFLAGS_IGNORE_MISSING_FILE);
+ /* 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);
return 1;
}
-#endif /* USE_SSLEAY */
-
-#ifdef USE_SSLEAY
-
/* Global cleanup */
void Curl_ossl_cleanup(void)
{
@@ -814,7 +785,7 @@ int Curl_ossl_check_cxn(struct connectdata *conn)
*/
CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine)
{
-#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
+#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
ENGINE *e;
#if OPENSSL_VERSION_NUMBER >= 0x00909000L
@@ -862,7 +833,7 @@ CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data)
#ifdef HAVE_OPENSSL_ENGINE_H
if(data->state.engine) {
if(ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) {
- infof(data,"set default crypto engine '%s'\n",
+ infof(data, "set default crypto engine '%s'\n",
ENGINE_get_id(data->state.engine));
}
else {
@@ -882,7 +853,7 @@ CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data)
struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data)
{
struct curl_slist *list = NULL;
-#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
+#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
struct curl_slist *beg;
ENGINE *e;
@@ -1031,7 +1002,7 @@ void Curl_ossl_session_free(void *ptr)
* This function is called when the 'data' struct is going away. Close
* down everything and free all resources!
*/
-int Curl_ossl_close_all(struct SessionHandle *data)
+void Curl_ossl_close_all(struct SessionHandle *data)
{
#ifdef HAVE_OPENSSL_ENGINE_H
if(data->state.engine) {
@@ -1042,7 +1013,6 @@ int Curl_ossl_close_all(struct SessionHandle *data)
#else
(void)data;
#endif
- return 0;
}
static int asn1_output(const ASN1_UTCTIME *tm,
@@ -1052,7 +1022,7 @@ static int asn1_output(const ASN1_UTCTIME *tm,
const char *asn1_string;
int gmt=FALSE;
int i;
- int year=0,month=0,day=0,hour=0,minute=0,second=0;
+ int year=0, month=0, day=0, hour=0, minute=0, second=0;
i=tm->length;
asn1_string=(const char *)tm->data;
@@ -1112,8 +1082,7 @@ static int asn1_output(const ASN1_UTCTIME *tm,
in the certificate and must exactly match the IP in the URI.
*/
-static CURLcode verifyhost(struct connectdata *conn,
- X509 *server_cert)
+static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
{
int matched = -1; /* -1 is no alternative match yet, 1 means match and 0
means mismatch */
@@ -1126,7 +1095,7 @@ static CURLcode verifyhost(struct connectdata *conn,
#else
struct in_addr addr;
#endif
- CURLcode res = CURLE_OK;
+ CURLcode result = CURLE_OK;
#ifdef ENABLE_IPV6
if(conn->bits.ipv6_ip &&
@@ -1207,19 +1176,19 @@ static CURLcode verifyhost(struct connectdata *conn,
infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname);
failf(data, "SSL: no alternative certificate subject name matches "
"target host name '%s'", conn->host.dispname);
- res = CURLE_PEER_FAILED_VERIFICATION;
+ result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
/* we have to look to the last occurrence of a commonName in the
distinguished one to get the most significant one. */
- int j,i=-1 ;
+ int j, i=-1;
/* The following is done because of a bug in 0.9.6b */
unsigned char *nulstr = (unsigned char *)"";
unsigned char *peer_CN = nulstr;
- X509_NAME *name = X509_get_subject_name(server_cert) ;
+ X509_NAME *name = X509_get_subject_name(server_cert);
if(name)
while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i))>=0)
i=j;
@@ -1229,7 +1198,8 @@ static CURLcode verifyhost(struct connectdata *conn,
UTF8 etc. */
if(i>=0) {
- ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i));
+ ASN1_STRING *tmp =
+ X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i));
/* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input
is already UTF-8 encoded. We check for this case and copy the raw
@@ -1254,7 +1224,7 @@ static CURLcode verifyhost(struct connectdata *conn,
/* there was a terminating zero before the end of string, this
cannot match and we return failure! */
failf(data, "SSL: illegal cert name field");
- res = CURLE_PEER_FAILED_VERIFICATION;
+ result = CURLE_PEER_FAILED_VERIFICATION;
}
}
}
@@ -1271,18 +1241,18 @@ static CURLcode verifyhost(struct connectdata *conn,
}
}
- if(res)
+ if(result)
/* error already detected, pass through */
;
else if(!peer_CN) {
failf(data,
"SSL: unable to obtain common name from peer certificate");
- res = CURLE_PEER_FAILED_VERIFICATION;
+ result = CURLE_PEER_FAILED_VERIFICATION;
}
else if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) {
failf(data, "SSL: certificate subject name '%s' does not match "
"target host name '%s'", peer_CN, conn->host.dispname);
- res = CURLE_PEER_FAILED_VERIFICATION;
+ result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
infof(data, "\t common name: %s (matched)\n", peer_CN);
@@ -1290,9 +1260,138 @@ static CURLcode verifyhost(struct connectdata *conn,
if(peer_CN)
OPENSSL_free(peer_CN);
}
- return res;
+
+ return result;
+}
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+ !defined(OPENSSL_IS_BORINGSSL)
+static CURLcode verifystatus(struct connectdata *conn,
+ struct ssl_connect_data *connssl)
+{
+ int i, ocsp_status;
+ const unsigned char *p;
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ OCSP_RESPONSE *rsp = NULL;
+ OCSP_BASICRESP *br = NULL;
+ X509_STORE *st = NULL;
+ STACK_OF(X509) *ch = NULL;
+
+ long len = SSL_get_tlsext_status_ocsp_resp(connssl->handle, &p);
+
+ if(!p) {
+ failf(data, "No OCSP response received");
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+
+ rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
+ if(!rsp) {
+ failf(data, "Invalid OCSP response");
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+
+ ocsp_status = OCSP_response_status(rsp);
+ if(ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+ failf(data, "Invalid OCSP response status: %s (%d)",
+ OCSP_response_status_str(ocsp_status), ocsp_status);
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+
+ br = OCSP_response_get1_basic(rsp);
+ if(!br) {
+ failf(data, "Invalid OCSP response");
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+
+ ch = SSL_get_peer_cert_chain(connssl->handle);
+ st = SSL_CTX_get_cert_store(connssl->ctx);
+
+#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \
+ defined(LIBRESSL_VERSION_NUMBER))
+ /* The authorized responder cert in the OCSP response MUST be signed by the
+ peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert,
+ no problem, but if it's an intermediate cert OpenSSL has a bug where it
+ expects this issuer to be present in the chain embedded in the OCSP
+ response. So we add it if necessary. */
+
+ /* First make sure the peer cert chain includes both a peer and an issuer,
+ and the OCSP response contains a responder cert. */
+ if(sk_X509_num(ch) >= 2 && sk_X509_num(br->certs) >= 1) {
+ X509 *responder = sk_X509_value(br->certs, sk_X509_num(br->certs) - 1);
+
+ /* Find issuer of responder cert and add it to the OCSP response chain */
+ for(i = 0; i < sk_X509_num(ch); i++) {
+ X509 *issuer = sk_X509_value(ch, i);
+ if(X509_check_issued(issuer, responder) == X509_V_OK) {
+ if(!OCSP_basic_add1_cert(br, issuer)) {
+ failf(data, "Could not add issuer cert to OCSP response");
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+ }
+ }
+ }
+#endif
+
+ if(OCSP_basic_verify(br, ch, st, 0) <= 0) {
+ failf(data, "OCSP response verification failed");
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+
+ for(i = 0; i < OCSP_resp_count(br); i++) {
+ int cert_status, crl_reason;
+ OCSP_SINGLERESP *single = NULL;
+
+ ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
+
+ if(!(single = OCSP_resp_get0(br, i)))
+ continue;
+
+ cert_status = OCSP_single_get0_status(single, &crl_reason, &rev,
+ &thisupd, &nextupd);
+
+ if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
+ failf(data, "OCSP response has expired");
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+
+ infof(data, "SSL certificate status: %s (%d)\n",
+ OCSP_cert_status_str(cert_status), cert_status);
+
+ switch(cert_status) {
+ case V_OCSP_CERTSTATUS_GOOD:
+ break;
+
+ case V_OCSP_CERTSTATUS_REVOKED:
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+
+ failf(data, "SSL certificate revocation reason: %s (%d)",
+ OCSP_crl_reason_str(crl_reason), crl_reason);
+ goto end;
+
+ case V_OCSP_CERTSTATUS_UNKNOWN:
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+ }
+
+end:
+ if(br) OCSP_BASICRESP_free(br);
+ OCSP_RESPONSE_free(rsp);
+
+ return result;
}
-#endif /* USE_SSLEAY */
+#endif
+
+#endif /* USE_OPENSSL */
/* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions
and thus this cannot be done there. */
@@ -1300,6 +1399,7 @@ static CURLcode verifyhost(struct connectdata *conn,
static const char *ssl_msg_type(int ssl_ver, int msg)
{
+#ifdef SSL2_VERSION_MAJOR
if(ssl_ver == SSL2_VERSION_MAJOR) {
switch (msg) {
case SSL2_MT_ERROR:
@@ -1322,7 +1422,9 @@ static const char *ssl_msg_type(int ssl_ver, int msg)
return "Client CERT";
}
}
- else if(ssl_ver == SSL3_VERSION_MAJOR) {
+ else
+#endif
+ if(ssl_ver == SSL3_VERSION_MAJOR) {
switch (msg) {
case SSL3_MT_HELLO_REQUEST:
return "Hello request";
@@ -1330,8 +1432,12 @@ static const char *ssl_msg_type(int ssl_ver, int msg)
return "Client hello";
case SSL3_MT_SERVER_HELLO:
return "Server hello";
+#ifdef SSL3_MT_NEWSESSION_TICKET
+ case SSL3_MT_NEWSESSION_TICKET:
+ return "Newsession Ticket";
+#endif
case SSL3_MT_CERTIFICATE:
- return "CERT";
+ return "Certificate";
case SSL3_MT_SERVER_KEY_EXCHANGE:
return "Server key exchange";
case SSL3_MT_CLIENT_KEY_EXCHANGE:
@@ -1344,6 +1450,10 @@ static const char *ssl_msg_type(int ssl_ver, int msg)
return "CERT verify";
case SSL3_MT_FINISHED:
return "Finished";
+#ifdef SSL3_MT_CERTIFICATE_STATUS
+ case SSL3_MT_CERTIFICATE_STATUS:
+ return "Certificate Status";
+#endif
}
}
return "Unknown";
@@ -1351,12 +1461,22 @@ static const char *ssl_msg_type(int ssl_ver, int msg)
static const char *tls_rt_type(int type)
{
- return (
- type == SSL3_RT_CHANGE_CIPHER_SPEC ? "TLS change cipher, " :
- type == SSL3_RT_ALERT ? "TLS alert, " :
- type == SSL3_RT_HANDSHAKE ? "TLS handshake, " :
- type == SSL3_RT_APPLICATION_DATA ? "TLS app data, " :
- "TLS Unknown, ");
+ switch(type) {
+#ifdef SSL3_RT_HEADER
+ case SSL3_RT_HEADER:
+ return "TLS header";
+#endif
+ case SSL3_RT_CHANGE_CIPHER_SPEC:
+ return "TLS change cipher";
+ case SSL3_RT_ALERT:
+ return "TLS alert";
+ case SSL3_RT_HANDSHAKE:
+ return "TLS handshake";
+ case SSL3_RT_APPLICATION_DATA:
+ return "TLS app data";
+ default:
+ return "TLS Unknown";
+ }
}
@@ -1364,38 +1484,77 @@ static const char *tls_rt_type(int type)
* Our callback from the SSL/TLS layers.
*/
static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
- const void *buf, size_t len, const SSL *ssl,
- struct connectdata *conn)
+ const void *buf, size_t len, SSL *ssl,
+ void *userp)
{
struct SessionHandle *data;
const char *msg_name, *tls_rt_name;
char ssl_buf[1024];
- int ver, msg_type, txt_len;
+ char unknown[32];
+ int msg_type, txt_len;
+ const char *verstr = NULL;
+ struct connectdata *conn = userp;
if(!conn || !conn->data || !conn->data->set.fdebug ||
(direction != 0 && direction != 1))
return;
data = conn->data;
- ssl_ver >>= 8;
- ver = (ssl_ver == SSL2_VERSION_MAJOR ? '2' :
- ssl_ver == SSL3_VERSION_MAJOR ? '3' : '?');
- /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL
- * always pass-up content-type as 0. But the interesting message-type
- * is at 'buf[0]'.
- */
- if(ssl_ver == SSL3_VERSION_MAJOR && content_type != 0)
- tls_rt_name = tls_rt_type(content_type);
- else
- tls_rt_name = "";
+ switch(ssl_ver) {
+#ifdef SSL2_VERSION /* removed in recent versions */
+ case SSL2_VERSION:
+ verstr = "SSLv2";
+ break;
+#endif
+#ifdef SSL3_VERSION
+ case SSL3_VERSION:
+ verstr = "SSLv3";
+ break;
+#endif
+ case TLS1_VERSION:
+ verstr = "TLSv1.0";
+ break;
+#ifdef TLS1_1_VERSION
+ case TLS1_1_VERSION:
+ verstr = "TLSv1.1";
+ break;
+#endif
+#ifdef TLS1_2_VERSION
+ case TLS1_2_VERSION:
+ verstr = "TLSv1.2";
+ break;
+#endif
+ case 0:
+ break;
+ default:
+ snprintf(unknown, sizeof(unknown), "(%x)", ssl_ver);
+ verstr = unknown;
+ break;
+ }
+
+ if(ssl_ver) {
+ /* the info given when the version is zero is not that useful for us */
+
+ ssl_ver >>= 8; /* check the upper 8 bits only below */
- msg_type = *(char*)buf;
- msg_name = ssl_msg_type(ssl_ver, msg_type);
+ /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL
+ * always pass-up content-type as 0. But the interesting message-type
+ * is at 'buf[0]'.
+ */
+ if(ssl_ver == SSL3_VERSION_MAJOR && content_type)
+ tls_rt_name = tls_rt_type(content_type);
+ else
+ tls_rt_name = "";
- txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "SSLv%c, %s%s (%d):\n",
- ver, tls_rt_name, msg_name, msg_type);
- Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL);
+ msg_type = *(char*)buf;
+ msg_name = ssl_msg_type(ssl_ver, msg_type);
+
+ txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n",
+ verstr, direction?"OUT":"IN",
+ tls_rt_name, msg_name, msg_type);
+ Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL);
+ }
Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
CURLINFO_SSL_DATA_IN, (char *)buf, len, NULL);
@@ -1403,7 +1562,7 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
}
#endif
-#ifdef USE_SSLEAY
+#ifdef USE_OPENSSL
/* ====================================================== */
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
@@ -1412,26 +1571,44 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
# define use_sni(x) Curl_nop_stmt
#endif
-#ifdef USE_NGHTTP2
-
+/* Check for OpenSSL 1.0.2 which has ALPN support. */
#undef HAS_ALPN
-#if defined(HAVE_SSL_CTX_SET_ALPN_PROTOS) && \
- defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB)
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L \
+ && !defined(OPENSSL_NO_TLSEXT)
# define HAS_ALPN 1
#endif
-#if !defined(HAVE_SSL_CTX_SET_NEXT_PROTO_SELECT_CB) || \
- defined(OPENSSL_NO_NEXTPROTONEG)
-# if !defined(HAS_ALPN)
-# error http2 builds require OpenSSL with NPN or ALPN support
-# endif
+/* Check for OpenSSL 1.0.1 which has NPN support. */
+#undef HAS_NPN
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L \
+ && !defined(OPENSSL_NO_TLSEXT) \
+ && !defined(OPENSSL_NO_NEXTPROTONEG)
+# define HAS_NPN 1
#endif
+#ifdef HAS_NPN
/*
* in is a list of lenght prefixed strings. this function has to select
* the protocol we want to use from the list and write its string into out.
*/
+
+static int
+select_next_protocol(unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen,
+ const char *key, unsigned int keylen)
+{
+ unsigned int i;
+ for(i = 0; i + keylen <= inlen; i += in[i] + 1) {
+ if(memcmp(&in[i + 1], key, keylen) == 0) {
+ *out = (unsigned char *) &in[i + 1];
+ *outlen = in[i];
+ return 0;
+ }
+ }
+ return -1;
+}
+
static int
select_next_proto_cb(SSL *ssl,
unsigned char **out, unsigned char *outlen,
@@ -1439,37 +1616,43 @@ select_next_proto_cb(SSL *ssl,
void *arg)
{
struct connectdata *conn = (struct connectdata*) arg;
- int retval = nghttp2_select_next_protocol(out, outlen, in, inlen);
+
(void)ssl;
- if(retval == 1) {
+#ifdef USE_NGHTTP2
+ if(conn->data->set.httpversion == CURL_HTTP_VERSION_2_0 &&
+ !select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_VERSION_ID,
+ NGHTTP2_PROTO_VERSION_ID_LEN)) {
infof(conn->data, "NPN, negotiated HTTP2 (%s)\n",
NGHTTP2_PROTO_VERSION_ID);
- conn->negnpn = NPN_HTTP2;
+ conn->negnpn = CURL_HTTP_VERSION_2_0;
+ return SSL_TLSEXT_ERR_OK;
}
- else if(retval == 0) {
+#endif
+
+ if(!select_next_protocol(out, outlen, in, inlen, ALPN_HTTP_1_1,
+ ALPN_HTTP_1_1_LENGTH)) {
infof(conn->data, "NPN, negotiated HTTP1.1\n");
- conn->negnpn = NPN_HTTP1_1;
- }
- else {
- infof(conn->data, "NPN, no overlap, use HTTP1.1\n",
- NGHTTP2_PROTO_VERSION_ID);
- *out = (unsigned char*)"http/1.1";
- *outlen = sizeof("http/1.1") - 1;
- conn->negnpn = NPN_HTTP1_1;
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
+ return SSL_TLSEXT_ERR_OK;
}
+ infof(conn->data, "NPN, no overlap, use HTTP1.1\n");
+ *out = (unsigned char *)ALPN_HTTP_1_1;
+ *outlen = ALPN_HTTP_1_1_LENGTH;
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
+
return SSL_TLSEXT_ERR_OK;
}
-#endif
+#endif /* HAS_NPN */
static const char *
-get_ssl_version_txt(SSL_SESSION *session)
+get_ssl_version_txt(SSL *ssl)
{
- if(NULL == session)
+ if(!ssl)
return "";
- switch(session->ssl_version) {
+ switch(SSL_version(ssl)) {
#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
case TLS1_2_VERSION:
return "TLSv1.2";
@@ -1486,17 +1669,14 @@ get_ssl_version_txt(SSL_SESSION *session)
return "unknown";
}
-
-static CURLcode
-ossl_connect_step1(struct connectdata *conn,
- int sockindex)
+static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
{
- CURLcode retcode = CURLE_OK;
+ CURLcode result = CURLE_OK;
char *ciphers;
struct SessionHandle *data = conn->data;
- SSL_METHOD_QUAL SSL_METHOD *req_method=NULL;
- void *ssl_sessionid=NULL;
- X509_LOOKUP *lookup=NULL;
+ SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
+ void *ssl_sessionid = NULL;
+ X509_LOOKUP *lookup = NULL;
curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
long ctx_options;
@@ -1508,9 +1688,6 @@ ossl_connect_step1(struct connectdata *conn,
struct in_addr addr;
#endif
#endif
-#ifdef HAS_ALPN
- unsigned char protocols[128];
-#endif
DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
@@ -1529,7 +1706,12 @@ ossl_connect_step1(struct connectdata *conn,
case CURL_SSLVERSION_TLSv1_1:
case CURL_SSLVERSION_TLSv1_2:
/* it will be handled later with the context options */
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
+ !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
+ req_method = TLS_client_method();
+#else
req_method = SSLv23_client_method();
+#endif
use_sni(TRUE);
break;
case CURL_SSLVERSION_SSLv2:
@@ -1546,6 +1728,10 @@ ossl_connect_step1(struct connectdata *conn,
break;
#endif
case CURL_SSLVERSION_SSLv3:
+#ifdef OPENSSL_NO_SSL3_METHOD
+ failf(data, "OpenSSL was built without SSLv3 support");
+ return CURLE_NOT_BUILT_IN;
+#else
#ifdef USE_TLS_SRP
if(data->set.ssl.authtype == CURL_TLSAUTH_SRP)
return CURLE_SSL_CONNECT_ERROR;
@@ -1553,6 +1739,7 @@ ossl_connect_step1(struct connectdata *conn,
req_method = SSLv3_client_method();
use_sni(FALSE);
break;
+#endif
}
if(connssl->ctx)
@@ -1571,16 +1758,9 @@ ossl_connect_step1(struct connectdata *conn,
#ifdef SSL_CTRL_SET_MSG_CALLBACK
if(data->set.fdebug && data->set.verbose) {
- /* the SSL trace callback is only used for verbose logging so we only
- inform about failures of setting it */
- if(!SSL_CTX_callback_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK,
- (void (*)(void))ssl_tls_trace)) {
- infof(data, "SSL: couldn't set callback!\n");
- }
- else if(!SSL_CTX_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK_ARG, 0,
- conn)) {
- infof(data, "SSL: couldn't set callback argument!\n");
- }
+ /* the SSL trace callback is only used for verbose logging */
+ SSL_CTX_set_msg_callback(connssl->ctx, ssl_tls_trace);
+ SSL_CTX_set_msg_callback_arg(connssl->ctx, conn);
}
#endif
@@ -1593,7 +1773,7 @@ ossl_connect_step1(struct connectdata *conn,
The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to
disable "rfc4507bis session ticket support". rfc4507bis was later turned
- into the proper RFC5077 it seems: http://tools.ietf.org/html/rfc5077
+ into the proper RFC5077 it seems: https://tools.ietf.org/html/rfc5077
The enabled extension concerns the session management. I wonder how often
libcurl stops a connection and then resumes a TLS session. also, sending
@@ -1613,7 +1793,7 @@ ossl_connect_step1(struct connectdata *conn,
this option regardless of OpenSSL version and SSL_OP_ALL definition.
OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability
- (http://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to
+ (https://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to
SSL_OP_ALL that _disables_ that work-around despite the fact that
SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to
keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit
@@ -1643,17 +1823,12 @@ ossl_connect_step1(struct connectdata *conn,
#endif
switch(data->set.ssl.version) {
- case CURL_SSLVERSION_DEFAULT:
- ctx_options |= SSL_OP_NO_SSLv2;
+ case CURL_SSLVERSION_SSLv3:
#ifdef USE_TLS_SRP
if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
infof(data, "Set version TLSv1.x for SRP authorisation\n");
- ctx_options |= SSL_OP_NO_SSLv3;
}
#endif
- break;
-
- case CURL_SSLVERSION_SSLv3:
ctx_options |= SSL_OP_NO_SSLv2;
ctx_options |= SSL_OP_NO_TLSv1;
#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
@@ -1662,6 +1837,7 @@ ossl_connect_step1(struct connectdata *conn,
#endif
break;
+ case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
ctx_options |= SSL_OP_NO_SSLv2;
ctx_options |= SSL_OP_NO_SSLv3;
@@ -1710,33 +1886,36 @@ ossl_connect_step1(struct connectdata *conn,
SSL_CTX_set_options(connssl->ctx, ctx_options);
-#ifdef USE_NGHTTP2
- if(data->set.httpversion == CURL_HTTP_VERSION_2_0) {
- if(data->set.ssl_enable_npn) {
- SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb,
- conn);
- }
+#ifdef HAS_NPN
+ if(data->set.ssl_enable_npn)
+ SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb, conn);
+#endif
#ifdef HAS_ALPN
- if(data->set.ssl_enable_alpn) {
- protocols[0] = NGHTTP2_PROTO_VERSION_ID_LEN;
- memcpy(&protocols[1], NGHTTP2_PROTO_VERSION_ID,
- NGHTTP2_PROTO_VERSION_ID_LEN);
+ if(data->set.ssl_enable_alpn) {
+ int cur = 0;
+ unsigned char protocols[128];
- protocols[NGHTTP2_PROTO_VERSION_ID_LEN+1] = ALPN_HTTP_1_1_LENGTH;
- memcpy(&protocols[NGHTTP2_PROTO_VERSION_ID_LEN+2], ALPN_HTTP_1_1,
- ALPN_HTTP_1_1_LENGTH);
-
- /* expects length prefixed preference ordered list of protocols in wire
- * format
- */
- SSL_CTX_set_alpn_protos(connssl->ctx, protocols,
- NGHTTP2_PROTO_VERSION_ID_LEN + ALPN_HTTP_1_1_LENGTH + 2);
+#ifdef USE_NGHTTP2
+ if(data->set.httpversion == CURL_HTTP_VERSION_2_0) {
+ protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN;
- infof(data, "ALPN, offering %s, %s\n", NGHTTP2_PROTO_VERSION_ID,
- ALPN_HTTP_1_1);
+ memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID,
+ NGHTTP2_PROTO_VERSION_ID_LEN);
+ cur += NGHTTP2_PROTO_VERSION_ID_LEN;
+ infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
}
#endif
+
+ protocols[cur++] = ALPN_HTTP_1_1_LENGTH;
+ memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
+ cur += ALPN_HTTP_1_1_LENGTH;
+ infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+
+ /* expects length prefixed preference ordered list of protocols in wire
+ * format
+ */
+ SSL_CTX_set_alpn_protos(connssl->ctx, protocols, cur);
}
#endif
@@ -1759,6 +1938,7 @@ ossl_connect_step1(struct connectdata *conn,
failf(data, "failed setting cipher list: %s", ciphers);
return CURLE_SSL_CIPHER;
}
+ infof(data, "Cipher selection: %s\n", ciphers);
#ifdef USE_TLS_SRP
if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
@@ -1768,7 +1948,7 @@ ossl_connect_step1(struct connectdata *conn,
failf(data, "Unable to set SRP user name");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- if(!SSL_CTX_set_srp_password(connssl->ctx,data->set.ssl.password)) {
+ if(!SSL_CTX_set_srp_password(connssl->ctx, data->set.ssl.password)) {
failf(data, "failed setting SRP password");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
@@ -1790,7 +1970,7 @@ ossl_connect_step1(struct connectdata *conn,
data->set.str[STRING_SSL_CAPATH])) {
if(data->set.ssl.verifypeer) {
/* Fail if we insist on successfully verifying the server. */
- failf(data,"error setting certificate verify locations:\n"
+ failf(data, "error setting certificate verify locations:\n"
" CAfile: %s\n CApath: %s",
data->set.str[STRING_SSL_CAFILE]?
data->set.str[STRING_SSL_CAFILE]: "none",
@@ -1824,9 +2004,9 @@ ossl_connect_step1(struct connectdata *conn,
lookup=X509_STORE_add_lookup(SSL_CTX_get_cert_store(connssl->ctx),
X509_LOOKUP_file());
if(!lookup ||
- (!X509_load_crl_file(lookup,data->set.str[STRING_SSL_CRLFILE],
+ (!X509_load_crl_file(lookup, data->set.str[STRING_SSL_CRLFILE],
X509_FILETYPE_PEM)) ) {
- failf(data,"error loading CRL file: %s",
+ failf(data, "error loading CRL file: %s",
data->set.str[STRING_SSL_CRLFILE]);
return CURLE_SSL_CRL_BADFILE;
}
@@ -1841,21 +2021,35 @@ ossl_connect_step1(struct connectdata *conn,
data->set.str[STRING_SSL_CRLFILE]: "none");
}
+ /* Try building a chain using issuers in the trusted store first to avoid
+ problems with server-sent legacy intermediates.
+ Newer versions of OpenSSL do alternate chain checking by default which
+ gives us the same fix without as much of a performance hit (slight), so we
+ prefer that if available.
+ https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest
+ */
+#if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS)
+ if(data->set.ssl.verifypeer) {
+ X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx),
+ X509_V_FLAG_TRUSTED_FIRST);
+ }
+#endif
+
/* SSL always tries to verify the peer, this only says whether it should
* fail to connect if the verification fails, or if it should continue
* anyway. In the latter case the result of the verification is checked with
* SSL_get_verify_result() below. */
SSL_CTX_set_verify(connssl->ctx,
data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
- cert_verify_callback);
+ NULL);
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
- retcode = (*data->set.ssl.fsslctx)(data, connssl->ctx,
- data->set.ssl.fsslctxp);
- if(retcode) {
- failf(data,"error signaled by ssl ctx callback");
- return retcode;
+ result = (*data->set.ssl.fsslctx)(data, connssl->ctx,
+ data->set.ssl.fsslctxp);
+ if(result) {
+ failf(data, "error signaled by ssl ctx callback");
+ return result;
}
}
@@ -1867,6 +2061,13 @@ ossl_connect_step1(struct connectdata *conn,
failf(data, "SSL: couldn't create a context (handle)!");
return CURLE_OUT_OF_MEMORY;
}
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+ !defined(OPENSSL_IS_BORINGSSL)
+ if(data->set.ssl.verifystatus)
+ SSL_set_tlsext_status_type(connssl->handle, TLSEXT_STATUSTYPE_ocsp);
+#endif
+
SSL_set_connect_state(connssl->handle);
connssl->server_cert = 0x0;
@@ -1887,7 +2088,7 @@ ossl_connect_step1(struct connectdata *conn,
/* we got a session id, use it! */
if(!SSL_set_session(connssl->handle, ssl_sessionid)) {
failf(data, "SSL: SSL_set_session failed: %s",
- ERR_error_string(ERR_get_error(),NULL));
+ ERR_error_string(ERR_get_error(), NULL));
return CURLE_SSL_CONNECT_ERROR;
}
/* Informational message */
@@ -1897,16 +2098,16 @@ ossl_connect_step1(struct connectdata *conn,
/* pass the raw socket into the SSL layers */
if(!SSL_set_fd(connssl->handle, (int)sockfd)) {
failf(data, "SSL: SSL_set_fd failed: %s",
- ERR_error_string(ERR_get_error(),NULL));
+ ERR_error_string(ERR_get_error(), NULL));
return CURLE_SSL_CONNECT_ERROR;
}
connssl->connecting_state = ssl_connect_2;
+
return CURLE_OK;
}
-static CURLcode
-ossl_connect_step2(struct connectdata *conn, int sockindex)
+static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
{
struct SessionHandle *data = conn->data;
int err;
@@ -1936,10 +2137,9 @@ ossl_connect_step2(struct connectdata *conn, int sockindex)
else {
/* untreated error */
unsigned long errdetail;
- char error_buffer[256]; /* OpenSSL documents that this must be at least
- 256 bytes long. */
- CURLcode rc;
- const char *cert_problem = NULL;
+ char error_buffer[256]=""; /* OpenSSL documents that this must be at
+ least 256 bytes long. */
+ CURLcode result;
long lerr;
connssl->connecting_state = ssl_connect_2; /* the connection failed,
@@ -1962,7 +2162,7 @@ ossl_connect_step2(struct connectdata *conn, int sockindex)
SSL routines:
SSL3_GET_SERVER_CERTIFICATE:
certificate verify failed */
- rc = CURLE_SSL_CACERT;
+ result = CURLE_SSL_CACERT;
lerr = SSL_get_verify_result(connssl->handle);
if(lerr != X509_V_OK) {
@@ -1971,12 +2171,13 @@ ossl_connect_step2(struct connectdata *conn, int sockindex)
X509_verify_cert_error_string(lerr));
}
else
- cert_problem = "SSL certificate problem, verify that the CA cert is"
- " OK.";
-
+ /* strcpy() is fine here as long as the string fits within
+ error_buffer */
+ strcpy(error_buffer,
+ "SSL certificate problem, check your CA cert");
break;
default:
- rc = CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
SSL_strerror(errdetail, error_buffer, sizeof(error_buffer));
break;
}
@@ -1987,15 +2188,16 @@ ossl_connect_step2(struct connectdata *conn, int sockindex)
* (RST connection etc.), OpenSSL gives no explanation whatsoever and
* the SO_ERROR is also lost.
*/
- if(CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) {
+ if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
failf(data, "Unknown SSL protocol error in connection to %s:%ld ",
conn->host.name, conn->remote_port);
- return rc;
+ return result;
}
+
/* Could be a CERT problem */
+ failf(data, "%s", error_buffer);
- failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer);
- return rc;
+ return result;
}
}
else {
@@ -2003,9 +2205,9 @@ ossl_connect_step2(struct connectdata *conn, int sockindex)
connssl->connecting_state = ssl_connect_3;
/* Informational message */
- infof (data, "SSL connection using %s / %s\n",
- get_ssl_version_txt(SSL_get_session(connssl->handle)),
- SSL_get_cipher(connssl->handle));
+ infof(data, "SSL connection using %s / %s\n",
+ get_ssl_version_txt(connssl->handle),
+ SSL_get_cipher(connssl->handle));
#ifdef HAS_ALPN
/* Sets data and len to negotiated protocol, len is 0 if no protocol was
@@ -2018,18 +2220,20 @@ ossl_connect_step2(struct connectdata *conn, int sockindex)
if(len != 0) {
infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol);
+#ifdef USE_NGHTTP2
if(len == NGHTTP2_PROTO_VERSION_ID_LEN &&
- memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len) == 0) {
- conn->negnpn = NPN_HTTP2;
+ !memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len)) {
+ conn->negnpn = CURL_HTTP_VERSION_2_0;
}
- else if(len == ALPN_HTTP_1_1_LENGTH && memcmp(ALPN_HTTP_1_1,
- neg_protocol, ALPN_HTTP_1_1_LENGTH) == 0) {
- conn->negnpn = NPN_HTTP1_1;
+ else
+#endif
+ if(len == ALPN_HTTP_1_1_LENGTH &&
+ !memcmp(ALPN_HTTP_1_1, neg_protocol, ALPN_HTTP_1_1_LENGTH)) {
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
}
}
- else {
+ else
infof(data, "ALPN, server did not agree to a protocol\n");
- }
}
#endif
@@ -2082,7 +2286,7 @@ static void pubkey_show(struct SessionHandle *data,
#define print_pubkey_BN(_type, _name, _num) \
do { \
- if(pubkey->pkey._type->_name != NULL) { \
+ if(pubkey->pkey._type->_name) { \
int len = BN_num_bytes(pubkey->pkey._type->_name); \
if(len < CERTBUFFERSIZE) { \
BN_bn2bin(pubkey->pkey._type->_name, (unsigned char*)bufp); \
@@ -2123,7 +2327,7 @@ static int X509V3_ext(struct SessionHandle *data,
X509_EXTENSION_get_critical(ext)?"(critical)":"");
if(!X509V3_EXT_print(bio_out, ext, 0, 0))
- M_ASN1_OCTET_STRING_print(bio_out, ext->value);
+ ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext));
BIO_get_mem_ptr(bio_out, &biomem);
@@ -2160,6 +2364,7 @@ static void X509_signature(struct SessionHandle *data,
char buf[1024];
char *ptr = buf;
int i;
+
for(i=0; i<sig->length; i++)
ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%02x:", sig->data[i]);
@@ -2182,7 +2387,6 @@ static void dumpcert(struct SessionHandle *data, X509 *x, int numcert)
"Cert", biomem->data, biomem->length);
BIO_free(bio_out);
-
}
/*
@@ -2196,6 +2400,7 @@ static CURLcode get_cert_chain(struct connectdata *conn,
struct ssl_connect_data *connssl)
{
+ CURLcode result;
STACK_OF(X509) *sk;
int i;
char *bufp;
@@ -2213,9 +2418,11 @@ static CURLcode get_cert_chain(struct connectdata *conn,
}
numcerts = sk_X509_num(sk);
- if(Curl_ssl_init_certinfo(data, numcerts)) {
+
+ result = Curl_ssl_init_certinfo(data, numcerts);
+ if(result) {
free(bufp);
- return CURLE_OUT_OF_MEMORY;
+ return result;
}
infof(data, "--- Certificate chain\n");
@@ -2250,28 +2457,22 @@ static CURLcode get_cert_chain(struct connectdata *conn,
Curl_ssl_push_certinfo(data, i, "Version", bufp); /* hex */
num=X509_get_serialNumber(x);
- if(num->length <= 4) {
- value = ASN1_INTEGER_get(num);
- infof(data," Serial Number: %ld (0x%lx)\n", value, value);
- snprintf(bufp, CERTBUFFERSIZE, "%lx", value);
- }
- else {
+ {
int left = CERTBUFFERSIZE;
ptr = bufp;
- *ptr++ = 0;
- if(num->type == V_ASN1_NEG_INTEGER)
+ if(num->type == V_ASN1_NEG_INTEGER) {
*ptr++='-';
+ left--;
+ }
- for(j=0; (j<num->length) && (left>=4); j++) {
- /* TODO: length restrictions */
- snprintf(ptr, 3, "%02x%c",num->data[j],
- ((j+1 == num->length)?'\n':':'));
- ptr += 3;
- left-=4;
+ for(j=0; (j<num->length) && (left>=3); j++) {
+ snprintf(ptr, left, "%02x", num->data[j]);
+ ptr += 2;
+ left -= 2;
}
if(num->length)
- infof(data," Serial Number: %s\n", bufp);
+ infof(data, " Serial Number: %s\n", bufp);
else
bufp[0]=0;
}
@@ -2357,6 +2558,65 @@ static CURLcode get_cert_chain(struct connectdata *conn,
}
/*
+ * Heavily modified from:
+ * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL
+ */
+static CURLcode pkp_pin_peer_pubkey(X509* cert, const char *pinnedpubkey)
+{
+ /* Scratch */
+ int len1 = 0, len2 = 0;
+ unsigned char *buff1 = NULL, *temp = NULL;
+
+ /* Result is returned to caller */
+ CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+
+ /* if a path wasn't specified, don't pin */
+ if(!pinnedpubkey)
+ return CURLE_OK;
+
+ if(!cert)
+ return result;
+
+ do {
+ /* Begin Gyrations to get the subjectPublicKeyInfo */
+ /* Thanks to Viktor Dukhovni on the OpenSSL mailing list */
+
+ /* https://groups.google.com/group/mailing.openssl.users/browse_thread
+ /thread/d61858dae102c6c7 */
+ len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL);
+ if(len1 < 1)
+ break; /* failed */
+
+ /* https://www.openssl.org/docs/crypto/buffer.html */
+ buff1 = temp = OPENSSL_malloc(len1);
+ if(!buff1)
+ break; /* failed */
+
+ /* https://www.openssl.org/docs/crypto/d2i_X509.html */
+ len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp);
+
+ /*
+ * These checks are verifying we got back the same values as when we
+ * sized the buffer. It's pretty weak since they should always be the
+ * same. But it gives us something to test.
+ */
+ if((len1 != len2) || !temp || ((temp - buff1) != len1))
+ break; /* failed */
+
+ /* End Gyrations */
+
+ /* The one good exit point */
+ result = Curl_pin_peer_pubkey(pinnedpubkey, buff1, len1);
+ } while(0);
+
+ /* https://www.openssl.org/docs/crypto/buffer.html */
+ if(buff1)
+ OPENSSL_free(buff1);
+
+ return result;
+}
+
+/*
* Get the server cert, verify it and show it etc, only call failf() if the
* 'strict' argument is TRUE as otherwise all this is for informational
* purposes only!
@@ -2368,7 +2628,7 @@ static CURLcode servercert(struct connectdata *conn,
struct ssl_connect_data *connssl,
bool strict)
{
- CURLcode retcode = CURLE_OK;
+ CURLcode result = CURLE_OK;
int rc;
long lerr;
ASN1_TIME *certdate;
@@ -2376,6 +2636,7 @@ static CURLcode servercert(struct connectdata *conn,
X509 *issuer;
FILE *fp;
char *buffer = data->state.buffer;
+ const char *ptr;
if(data->set.ssl.certinfo)
/* we've been asked to gather certificate info! */
@@ -2387,7 +2648,8 @@ static CURLcode servercert(struct connectdata *conn,
failf(data, "SSL: couldn't get peer certificate!");
return CURLE_PEER_FAILED_VERIFICATION;
}
- infof (data, "Server certificate:\n");
+
+ infof(data, "Server certificate:\n");
rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert),
buffer, BUFSIZE);
@@ -2402,11 +2664,11 @@ static CURLcode servercert(struct connectdata *conn,
infof(data, "\t expire date: %s\n", buffer);
if(data->set.ssl.verifyhost) {
- retcode = verifyhost(conn, connssl->server_cert);
- if(retcode) {
+ result = verifyhost(conn, connssl->server_cert);
+ if(result) {
X509_free(connssl->server_cert);
connssl->server_cert = NULL;
- return retcode;
+ return result;
}
}
@@ -2415,7 +2677,7 @@ static CURLcode servercert(struct connectdata *conn,
if(rc) {
if(strict)
failf(data, "SSL: couldn't get X509-issuer name!");
- retcode = CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
}
else {
infof(data, "\t issuer: %s\n", buffer);
@@ -2425,7 +2687,7 @@ static CURLcode servercert(struct connectdata *conn,
/* e.g. match issuer name with provided issuer certificate */
if(data->set.str[STRING_SSL_ISSUERCERT]) {
- fp=fopen(data->set.str[STRING_SSL_ISSUERCERT],"r");
+ fp = fopen(data->set.str[STRING_SSL_ISSUERCERT], FOPEN_READTEXT);
if(!fp) {
if(strict)
failf(data, "SSL: Unable to open issuer cert (%s)",
@@ -2434,7 +2696,8 @@ static CURLcode servercert(struct connectdata *conn,
connssl->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
- issuer = PEM_read_X509(fp,NULL,ZERO_NULL,NULL);
+
+ issuer = PEM_read_X509(fp, NULL, ZERO_NULL, NULL);
if(!issuer) {
if(strict)
failf(data, "SSL: Unable to read issuer cert (%s)",
@@ -2444,8 +2707,10 @@ static CURLcode servercert(struct connectdata *conn,
fclose(fp);
return CURLE_SSL_ISSUER_ERROR;
}
+
fclose(fp);
- if(X509_check_issued(issuer,connssl->server_cert) != X509_V_OK) {
+
+ if(X509_check_issued(issuer, connssl->server_cert) != X509_V_OK) {
if(strict)
failf(data, "SSL: Certificate issuer check failed (%s)",
data->set.str[STRING_SSL_ISSUERCERT]);
@@ -2454,13 +2719,15 @@ static CURLcode servercert(struct connectdata *conn,
connssl->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
+
infof(data, "\t SSL certificate issuer check ok (%s)\n",
data->set.str[STRING_SSL_ISSUERCERT]);
X509_free(issuer);
}
- lerr = data->set.ssl.certverifyresult=
+ lerr = data->set.ssl.certverifyresult =
SSL_get_verify_result(connssl->handle);
+
if(data->set.ssl.certverifyresult != X509_V_OK) {
if(data->set.ssl.verifypeer) {
/* We probably never reach this, because SSL_connect() will fail
@@ -2468,7 +2735,7 @@ static CURLcode servercert(struct connectdata *conn,
if(strict)
failf(data, "SSL certificate verify result: %s (%ld)",
X509_verify_cert_error_string(lerr), lerr);
- retcode = CURLE_PEER_FAILED_VERIFICATION;
+ result = CURLE_PEER_FAILED_VERIFICATION;
}
else
infof(data, "\t SSL certificate verify result: %s (%ld),"
@@ -2479,46 +2746,52 @@ static CURLcode servercert(struct connectdata *conn,
infof(data, "\t SSL certificate verify ok.\n");
}
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+ !defined(OPENSSL_IS_BORINGSSL)
+ if(data->set.ssl.verifystatus) {
+ result = verifystatus(conn, connssl);
+ if(result) {
+ X509_free(connssl->server_cert);
+ connssl->server_cert = NULL;
+ return result;
+ }
+ }
+#endif
+
+ if(!strict)
+ /* when not strict, we don't bother about the verify cert problems */
+ result = CURLE_OK;
+
+ ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+ if(!result && ptr) {
+ result = pkp_pin_peer_pubkey(connssl->server_cert, ptr);
+ if(result)
+ failf(data, "SSL: public key does not match pinned public key!");
+ }
+
X509_free(connssl->server_cert);
connssl->server_cert = NULL;
connssl->connecting_state = ssl_connect_done;
- return retcode;
+ return result;
}
-
-static CURLcode
-ossl_connect_step3(struct connectdata *conn,
- int sockindex)
+static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
{
- CURLcode retcode = CURLE_OK;
- void *old_ssl_sessionid=NULL;
+ CURLcode result = CURLE_OK;
+ void *old_ssl_sessionid = NULL;
struct SessionHandle *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- int incache;
+ bool incache;
SSL_SESSION *our_ssl_sessionid;
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
-#ifdef HAVE_SSL_GET1_SESSION
our_ssl_sessionid = SSL_get1_session(connssl->handle);
- /* SSL_get1_session() will increment the reference
- count and the session will stay in memory until explicitly freed with
- SSL_SESSION_free(3), regardless of its state.
- This function was introduced in openssl 0.9.5a. */
-#else
- our_ssl_sessionid = SSL_get_session(connssl->handle);
-
- /* if SSL_get1_session() is unavailable, use SSL_get_session().
- This is an inferior option because the session can be flushed
- at any time by openssl. It is included only so curl compiles
- under versions of openssl < 0.9.5a.
-
- WARNING: How curl behaves if it's session is flushed is
- untested.
- */
-#endif
+ /* SSL_get1_session() will increment the reference count and the session
+ will stay in memory until explicitly freed with SSL_SESSION_free(3),
+ regardless of its state. */
incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
if(incache) {
@@ -2528,15 +2801,15 @@ ossl_connect_step3(struct connectdata *conn,
incache = FALSE;
}
}
+
if(!incache) {
- retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
- 0 /* unknown size */);
- if(retcode) {
+ result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
+ 0 /* unknown size */);
+ if(result) {
failf(data, "failed to store ssl session");
- return retcode;
+ return result;
}
}
-#ifdef HAVE_SSL_GET1_SESSION
else {
/* Session was incache, so refcount already incremented earlier.
* Avoid further increments with each SSL_get1_session() call.
@@ -2544,7 +2817,6 @@ ossl_connect_step3(struct connectdata *conn,
*/
SSL_SESSION_free(our_ssl_sessionid);
}
-#endif
/*
* We check certificates to authenticate the server; otherwise we risk
@@ -2553,26 +2825,24 @@ ossl_connect_step3(struct connectdata *conn,
* operations.
*/
- if(!data->set.ssl.verifypeer && !data->set.ssl.verifyhost)
- (void)servercert(conn, connssl, FALSE);
- else
- retcode = servercert(conn, connssl, TRUE);
+ result = servercert(conn, connssl,
+ (data->set.ssl.verifypeer || data->set.ssl.verifyhost));
- if(CURLE_OK == retcode)
+ if(!result)
connssl->connecting_state = ssl_connect_done;
- return retcode;
+
+ return result;
}
static Curl_recv ossl_recv;
static Curl_send ossl_send;
-static CURLcode
-ossl_connect_common(struct connectdata *conn,
- int sockindex,
- bool nonblocking,
- bool *done)
+static CURLcode ossl_connect_common(struct connectdata *conn,
+ int sockindex,
+ bool nonblocking,
+ bool *done)
{
- CURLcode retcode;
+ CURLcode result;
struct SessionHandle *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
curl_socket_t sockfd = conn->sock[sockindex];
@@ -2585,7 +2855,7 @@ ossl_connect_common(struct connectdata *conn,
return CURLE_OK;
}
- if(ssl_connect_1==connssl->connecting_state) {
+ if(ssl_connect_1 == connssl->connecting_state) {
/* Find out how much more time we're allowed */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -2594,9 +2864,10 @@ ossl_connect_common(struct connectdata *conn,
failf(data, "SSL connection timeout");
return CURLE_OPERATION_TIMEDOUT;
}
- retcode = ossl_connect_step1(conn, sockindex);
- if(retcode)
- return retcode;
+
+ result = ossl_connect_step1(conn, sockindex);
+ if(result)
+ return result;
}
while(ssl_connect_2 == connssl->connecting_state ||
@@ -2613,8 +2884,8 @@ ossl_connect_common(struct connectdata *conn,
}
/* if ssl is expecting something, check if it's available. */
- if(connssl->connecting_state == ssl_connect_2_reading
- || connssl->connecting_state == ssl_connect_2_writing) {
+ if(connssl->connecting_state == ssl_connect_2_reading ||
+ connssl->connecting_state == ssl_connect_2_writing) {
curl_socket_t writefd = ssl_connect_2_writing==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
@@ -2647,23 +2918,22 @@ ossl_connect_common(struct connectdata *conn,
* before step2 has completed while ensuring that a client using select()
* or epoll() will always have a valid fdset to wait on.
*/
- retcode = ossl_connect_step2(conn, sockindex);
- if(retcode || (nonblocking &&
- (ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state)))
- return retcode;
+ result = ossl_connect_step2(conn, sockindex);
+ if(result || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
+ return result;
} /* repeat step2 until all transactions are done. */
-
- if(ssl_connect_3==connssl->connecting_state) {
- retcode = ossl_connect_step3(conn, sockindex);
- if(retcode)
- return retcode;
+ if(ssl_connect_3 == connssl->connecting_state) {
+ result = ossl_connect_step3(conn, sockindex);
+ if(result)
+ return result;
}
- if(ssl_connect_done==connssl->connecting_state) {
+ if(ssl_connect_done == connssl->connecting_state) {
connssl->state = ssl_connection_complete;
conn->recv[sockindex] = ossl_recv;
conn->send[sockindex] = ossl_send;
@@ -2678,32 +2948,28 @@ ossl_connect_common(struct connectdata *conn,
return CURLE_OK;
}
-CURLcode
-Curl_ossl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
+CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done)
{
return ossl_connect_common(conn, sockindex, TRUE, done);
}
-CURLcode
-Curl_ossl_connect(struct connectdata *conn,
- int sockindex)
+CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex)
{
- CURLcode retcode;
+ CURLcode result;
bool done = FALSE;
- retcode = ossl_connect_common(conn, sockindex, FALSE, &done);
- if(retcode)
- return retcode;
+ result = ossl_connect_common(conn, sockindex, FALSE, &done);
+ if(result)
+ return result;
DEBUGASSERT(done);
return CURLE_OK;
}
-bool Curl_ossl_data_pending(const struct connectdata *conn,
- int connindex)
+bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex)
{
if(conn->ssl[connindex].handle)
/* SSL is in use */
@@ -2798,7 +3064,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
default:
/* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
value/errno" */
- /* http://www.openssl.org/docs/crypto/ERR_get_error.html */
+ /* https://www.openssl.org/docs/crypto/ERR_get_error.html */
sslerror = ERR_get_error();
if((nread < 0) || sslerror) {
/* If the return code was negative or there actually is an error in the
@@ -2821,8 +3087,11 @@ size_t Curl_ossl_version(char *buffer, size_t size)
to OpenSSL in all other aspects */
return snprintf(buffer, size, "yassl/%s", YASSL_VERSION);
#else /* YASSL_VERSION */
+#ifdef OPENSSL_IS_BORINGSSL
+ return snprintf(buffer, size, "BoringSSL");
+#else /* OPENSSL_IS_BORINGSSL */
-#if(SSLEAY_VERSION_NUMBER >= 0x905000)
+#if(OPENSSL_VERSION_NUMBER >= 0x905000)
{
char sub[3];
unsigned long ssleay_value;
@@ -2850,47 +3119,44 @@ size_t Curl_ossl_version(char *buffer, size_t size)
}
return snprintf(buffer, size, "%s/%lx.%lx.%lx%s",
-#ifdef OPENSSL_IS_BORINGSSL
- "BoringSSL"
-#else
#ifdef LIBRESSL_VERSION_NUMBER
"LibreSSL"
#else
"OpenSSL"
#endif
-#endif
, (ssleay_value>>28)&0xf,
(ssleay_value>>20)&0xff,
(ssleay_value>>12)&0xff,
sub);
}
-#else /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */
+#else /* OPENSSL_VERSION_NUMBER is less than 0.9.5 */
-#if(SSLEAY_VERSION_NUMBER >= 0x900000)
+#if(OPENSSL_VERSION_NUMBER >= 0x900000)
return snprintf(buffer, size, "OpenSSL/%lx.%lx.%lx",
- (SSLEAY_VERSION_NUMBER>>28)&0xff,
- (SSLEAY_VERSION_NUMBER>>20)&0xff,
- (SSLEAY_VERSION_NUMBER>>12)&0xf);
+ (OPENSSL_VERSION_NUMBER>>28)&0xff,
+ (OPENSSL_VERSION_NUMBER>>20)&0xff,
+ (OPENSSL_VERSION_NUMBER>>12)&0xf);
-#else /* (SSLEAY_VERSION_NUMBER >= 0x900000) */
+#else /* (OPENSSL_VERSION_NUMBER >= 0x900000) */
{
char sub[2];
sub[1]='\0';
- if(SSLEAY_VERSION_NUMBER&0x0f) {
- sub[0]=(SSLEAY_VERSION_NUMBER&0x0f) + 'a' -1;
+ if(OPENSSL_VERSION_NUMBER&0x0f) {
+ sub[0]=(OPENSSL_VERSION_NUMBER&0x0f) + 'a' -1;
}
else
sub[0]='\0';
return snprintf(buffer, size, "SSL/%x.%x.%x%s",
- (SSLEAY_VERSION_NUMBER>>12)&0xff,
- (SSLEAY_VERSION_NUMBER>>8)&0xf,
- (SSLEAY_VERSION_NUMBER>>4)&0xf, sub);
+ (OPENSSL_VERSION_NUMBER>>12)&0xff,
+ (OPENSSL_VERSION_NUMBER>>8)&0xf,
+ (OPENSSL_VERSION_NUMBER>>4)&0xf, sub);
}
-#endif /* (SSLEAY_VERSION_NUMBER >= 0x900000) */
-#endif /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */
+#endif /* (OPENSSL_VERSION_NUMBER >= 0x900000) */
+#endif /* OPENSSL_VERSION_NUMBER is less than 0.9.5 */
+#endif /* OPENSSL_IS_BORINGSSL */
#endif /* YASSL_VERSION */
}
@@ -2898,8 +3164,9 @@ size_t Curl_ossl_version(char *buffer, size_t size)
int Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy,
size_t length)
{
- if(data)
+ if(data) {
Curl_ossl_seed(data); /* Initiate the seed if not already done */
+ }
RAND_bytes(entropy, curlx_uztosi(length));
return 0; /* 0 as in no problem */
}
@@ -2915,4 +3182,28 @@ void Curl_ossl_md5sum(unsigned char *tmp, /* input */
MD5_Update(&MD5pw, tmp, tmplen);
MD5_Final(md5sum, &MD5pw);
}
-#endif /* USE_SSLEAY */
+
+#ifndef OPENSSL_NO_SHA256
+void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum /* output */,
+ size_t unused)
+{
+ SHA256_CTX SHA256pw;
+ (void)unused;
+ SHA256_Init(&SHA256pw);
+ SHA256_Update(&SHA256pw, tmp, tmplen);
+ SHA256_Final(sha256sum, &SHA256pw);
+}
+#endif
+
+bool Curl_ossl_cert_status_request(void)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+ !defined(OPENSSL_IS_BORINGSSL)
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+#endif /* USE_OPENSSL */