summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/vtls/openssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/vtls/openssl.c')
-rw-r--r--libs/libcurl/src/vtls/openssl.c143
1 files changed, 112 insertions, 31 deletions
diff --git a/libs/libcurl/src/vtls/openssl.c b/libs/libcurl/src/vtls/openssl.c
index 760758d234..726ff6e7ca 100644
--- a/libs/libcurl/src/vtls/openssl.c
+++ b/libs/libcurl/src/vtls/openssl.c
@@ -142,10 +142,6 @@
#endif
#endif
-#ifdef LIBRESSL_VERSION_NUMBER
-#define OpenSSL_version_num() LIBRESSL_VERSION_NUMBER
-#endif
-
#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \
!(defined(LIBRESSL_VERSION_NUMBER) && \
LIBRESSL_VERSION_NUMBER < 0x20700000L)
@@ -392,11 +388,20 @@ static const char *SSL_ERROR_to_str(int err)
*/
static char *ossl_strerror(unsigned long error, char *buf, size_t size)
{
+ if(size)
+ *buf = '\0';
+
#ifdef OPENSSL_IS_BORINGSSL
ERR_error_string_n((uint32_t)error, buf, size);
#else
ERR_error_string_n(error, buf, size);
#endif
+
+ if(size > 1 && !*buf) {
+ strncpy(buf, (error ? "Unknown error" : "No error"), size);
+ buf[size - 1] = '\0';
+ }
+
return buf;
}
@@ -2768,19 +2773,29 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
infof(data, " CRLfile: %s\n", ssl_crlfile);
}
- /* 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(verifypeer) {
+ /* 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)
X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx),
X509_V_FLAG_TRUSTED_FIRST);
- }
#endif
+#ifdef X509_V_FLAG_PARTIAL_CHAIN
+ if(!SSL_SET_OPTION(no_partialchain)) {
+ /* Have intermediate certificates in the trust store be treated as
+ trust-anchors, in the same way as self-signed root CA certificates
+ are. This allows users to verify servers using the intermediate cert
+ only, instead of needing the whole chain. */
+ X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx),
+ X509_V_FLAG_PARTIAL_CHAIN);
+ }
+#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
@@ -2806,8 +2821,10 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
+ Curl_set_in_callback(data, true);
result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx,
data->set.ssl.fsslctxp);
+ Curl_set_in_callback(data, false);
if(result) {
failf(data, "error signaled by ssl ctx callback");
return result;
@@ -2988,8 +3005,13 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
const char * const hostname = SSL_IS_PROXY() ?
conn->http_proxy.host.name : conn->host.name;
const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
+ char extramsg[80]="";
+ int sockerr = SOCKERRNO;
+ if(sockerr && detail == SSL_ERROR_SYSCALL)
+ Curl_strerror(sockerr, extramsg, sizeof(extramsg));
failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%ld ",
- SSL_ERROR_to_str(detail), hostname, port);
+ extramsg[0] ? extramsg : SSL_ERROR_to_str(detail),
+ hostname, port);
return result;
}
@@ -3065,7 +3087,7 @@ do { \
Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \
if(1 != BIO_reset(mem)) \
break; \
-} WHILE_FALSE
+} while(0)
static void pubkey_show(struct Curl_easy *data,
BIO *mem,
@@ -3097,7 +3119,7 @@ do { \
if(_type->_name) { \
pubkey_show(data, mem, _num, #_type, #_name, _type->_name); \
} \
-} WHILE_FALSE
+} while(0)
#endif
static int X509V3_ext(struct Curl_easy *data,
@@ -3826,10 +3848,22 @@ static ssize_t ossl_send(struct connectdata *conn,
*curlcode = CURLE_AGAIN;
return -1;
case SSL_ERROR_SYSCALL:
- Curl_strerror(SOCKERRNO, error_buffer, sizeof(error_buffer));
- failf(conn->data, OSSL_PACKAGE " SSL_write: %s", error_buffer);
- *curlcode = CURLE_SEND_ERROR;
- return -1;
+ {
+ int sockerr = SOCKERRNO;
+ sslerror = ERR_get_error();
+ if(sslerror)
+ ossl_strerror(sslerror, error_buffer, sizeof(error_buffer));
+ else if(sockerr)
+ Curl_strerror(sockerr, error_buffer, sizeof(error_buffer));
+ else {
+ strncpy(error_buffer, SSL_ERROR_to_str(err), sizeof(error_buffer));
+ error_buffer[sizeof(error_buffer) - 1] = '\0';
+ }
+ failf(conn->data, OSSL_PACKAGE " SSL_write: %s, errno %d",
+ error_buffer, sockerr);
+ *curlcode = CURLE_SEND_ERROR;
+ return -1;
+ }
case SSL_ERROR_SSL:
/* A failure in the SSL library occurred, usually a protocol error.
The OpenSSL error queue contains more information on the error. */
@@ -3894,11 +3928,6 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
/* there's data pending, re-invoke SSL_read() */
*curlcode = CURLE_AGAIN;
return -1;
- case SSL_ERROR_SYSCALL:
- Curl_strerror(SOCKERRNO, error_buffer, sizeof(error_buffer));
- failf(conn->data, OSSL_PACKAGE " SSL_read: %s", error_buffer);
- *curlcode = CURLE_RECV_ERROR;
- return -1;
default:
/* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
value/errno" */
@@ -3907,14 +3936,44 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
if((nread < 0) || sslerror) {
/* If the return code was negative or there actually is an error in the
queue */
+ int sockerr = SOCKERRNO;
+ if(sslerror)
+ ossl_strerror(sslerror, error_buffer, sizeof(error_buffer));
+ else if(sockerr && err == SSL_ERROR_SYSCALL)
+ Curl_strerror(sockerr, error_buffer, sizeof(error_buffer));
+ else {
+ strncpy(error_buffer, SSL_ERROR_to_str(err), sizeof(error_buffer));
+ error_buffer[sizeof(error_buffer) - 1] = '\0';
+ }
failf(conn->data, OSSL_PACKAGE " SSL_read: %s, errno %d",
- (sslerror ?
- ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)) :
- SSL_ERROR_to_str(err)),
- SOCKERRNO);
+ error_buffer, sockerr);
*curlcode = CURLE_RECV_ERROR;
return -1;
}
+ /* For debug builds be a little stricter and error on any
+ SSL_ERROR_SYSCALL. For example a server may have closed the connection
+ abruptly without a close_notify alert. For compatibility with older
+ peers we don't do this by default. #4624
+
+ We can use this to gauge how many users may be affected, and
+ if it goes ok eventually transition to allow in dev and release with
+ the newest OpenSSL: #if (OPENSSL_VERSION_NUMBER >= 0x10101000L) */
+#ifdef DEBUGBUILD
+ if(err == SSL_ERROR_SYSCALL) {
+ int sockerr = SOCKERRNO;
+ if(sockerr)
+ Curl_strerror(sockerr, error_buffer, sizeof(error_buffer));
+ else {
+ msnprintf(error_buffer, sizeof(error_buffer),
+ "Connection closed abruptly");
+ }
+ failf(conn->data, OSSL_PACKAGE " SSL_read: %s, errno %d"
+ " (Fatal because this is a curl debug build)",
+ error_buffer, sockerr);
+ *curlcode = CURLE_RECV_ERROR;
+ return -1;
+ }
+#endif
}
}
return nread;
@@ -3922,13 +3981,35 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
static size_t Curl_ossl_version(char *buffer, size_t size)
{
-#ifdef OPENSSL_IS_BORINGSSL
+#ifdef LIBRESSL_VERSION_NUMBER
+#if LIBRESSL_VERSION_NUMBER < 0x2070100fL
+ return msnprintf(buffer, size, "%s/%lx.%lx.%lx",
+ OSSL_PACKAGE,
+ (LIBRESSL_VERSION_NUMBER>>28)&0xf,
+ (LIBRESSL_VERSION_NUMBER>>20)&0xff,
+ (LIBRESSL_VERSION_NUMBER>>12)&0xff);
+#else /* OpenSSL_version() first appeared in LibreSSL 2.7.1 */
+ char *p;
+ int count;
+ const char *ver = OpenSSL_version(OPENSSL_VERSION);
+ const char expected[] = OSSL_PACKAGE " "; /* ie "LibreSSL " */
+ if(Curl_strncasecompare(ver, expected, sizeof(expected) - 1)) {
+ ver += sizeof(expected) - 1;
+ }
+ count = msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, ver);
+ for(p = buffer; *p; ++p) {
+ if(ISSPACE(*p))
+ *p = '_';
+ }
+ return count;
+#endif
+#elif defined(OPENSSL_IS_BORINGSSL)
return msnprintf(buffer, size, OSSL_PACKAGE);
#elif defined(HAVE_OPENSSL_VERSION) && defined(OPENSSL_VERSION_STRING)
return msnprintf(buffer, size, "%s/%s",
OSSL_PACKAGE, OpenSSL_version(OPENSSL_VERSION_STRING));
#else
- /* not BoringSSL and not using OpenSSL_version */
+ /* not LibreSSL, BoringSSL and not using OpenSSL_version */
char sub[3];
unsigned long ssleay_value;