diff options
Diffstat (limited to 'libs/libcurl/src/vtls/openssl.c')
-rw-r--r-- | libs/libcurl/src/vtls/openssl.c | 286 |
1 files changed, 206 insertions, 80 deletions
diff --git a/libs/libcurl/src/vtls/openssl.c b/libs/libcurl/src/vtls/openssl.c index 7b04edfd6b..f6a4bd3fbf 100644 --- a/libs/libcurl/src/vtls/openssl.c +++ b/libs/libcurl/src/vtls/openssl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2018, 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 @@ -34,9 +34,7 @@ #ifdef USE_OPENSSL -#ifdef HAVE_LIMITS_H #include <limits.h> -#endif #include "urldata.h" #include "sendf.h" @@ -68,12 +66,7 @@ #include <openssl/rsa.h> #include <openssl/bio.h> #include <openssl/buffer.h> - -#ifndef OPENSSL_IS_BORINGSSL -/* BoringSSL does not support PKCS12 */ -#define HAVE_PKCS12_SUPPORT 1 #include <openssl/pkcs12.h> -#endif #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP) #include <openssl/ocsp.h> @@ -111,13 +104,22 @@ #endif #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \ - !defined(LIBRESSL_VERSION_NUMBER) + !(defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER < 0x20700000L) #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 */ #define CONST_EXTS const #define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1 + +/* funny typecast define due to difference in API */ +#ifdef LIBRESSL_VERSION_NUMBER +#define ARG2_X509_signature_print (X509_ALGOR *) +#else +#define ARG2_X509_signature_print +#endif + #else /* For OpenSSL before 1.1.0 */ #define ASN1_STRING_get0_data(x) ASN1_STRING_data(x) @@ -135,7 +137,8 @@ static unsigned long OpenSSL_version_num(void) #endif #if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \ - !defined(LIBRESSL_VERSION_NUMBER) + !(defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER < 0x20700000L) #define HAVE_X509_GET0_SIGNATURE 1 #endif @@ -154,7 +157,7 @@ static unsigned long OpenSSL_version_num(void) * Whether SSL_CTX_set_keylog_callback is available. * OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287 * BoringSSL: supported since d28f59c27bac (committed 2015-11-19) - * LibreSSL: unsupported in at least 2.5.1 (explicitly check for it since it + * LibreSSL: unsupported in at least 2.7.2 (explicitly check for it since it * lies and pretends to be OpenSSL 2.0.0). */ #if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \ @@ -182,6 +185,8 @@ static unsigned long OpenSSL_version_num(void) "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH" #endif +#define ENABLE_SSLKEYLOGFILE + #ifdef ENABLE_SSLKEYLOGFILE typedef struct ssl_tap_state { int master_key_length; @@ -264,11 +269,13 @@ static void tap_ssl_key(const SSL *ssl, ssl_tap_state_t *state) if(!session || !keylog_file_fp) return; -#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ + !(defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER < 0x20700000L) /* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that * we have a valid SSL context if we have a non-NULL session. */ SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE); - master_key_length = + master_key_length = (int) SSL_SESSION_get_master_key(session, master_key, SSL_MAX_MASTER_KEY_LENGTH); #else if(ssl->s3 && session->master_key_length > 0) { @@ -654,19 +661,28 @@ int cert_stuff(struct connectdata *conn, case SSL_FILETYPE_PKCS12: { -#ifdef HAVE_PKCS12_SUPPORT - FILE *f; - PKCS12 *p12; + BIO *fp = NULL; + PKCS12 *p12 = NULL; EVP_PKEY *pri; STACK_OF(X509) *ca = NULL; - f = fopen(cert_file, "rb"); - if(!f) { + fp = BIO_new(BIO_s_file()); + if(fp == NULL) { + failf(data, + "BIO_new return NULL, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + return 0; + } + + if(BIO_read_filename(fp, cert_file) <= 0) { failf(data, "could not open PKCS12 file '%s'", cert_file); + BIO_free(fp); return 0; } - p12 = d2i_PKCS12_fp(f, NULL); - fclose(f); + p12 = d2i_PKCS12_bio(fp, NULL); + BIO_free(fp); if(!p12) { failf(data, "error reading PKCS12 file '%s'", cert_file); @@ -741,10 +757,6 @@ int cert_stuff(struct connectdata *conn, if(!cert_done) return 0; /* failure! */ break; -#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); @@ -914,7 +926,7 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size) static int Curl_ossl_init(void) { #ifdef ENABLE_SSLKEYLOGFILE - const char *keylog_file_name; + char *keylog_file_name; #endif OPENSSL_load_builtin_modules(); @@ -954,14 +966,22 @@ static int Curl_ossl_init(void) #endif #ifdef ENABLE_SSLKEYLOGFILE - keylog_file_name = curl_getenv("SSLKEYLOGFILE"); - if(keylog_file_name && !keylog_file_fp) { - keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT); - if(keylog_file_fp) { - if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096)) { - fclose(keylog_file_fp); - keylog_file_fp = NULL; + if(!keylog_file_fp) { + keylog_file_name = curl_getenv("SSLKEYLOGFILE"); + if(keylog_file_name) { + keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT); + if(keylog_file_fp) { +#ifdef WIN32 + if(setvbuf(keylog_file_fp, NULL, _IONBF, 0)) +#else + if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096)) +#endif + { + fclose(keylog_file_fp); + keylog_file_fp = NULL; + } } + Curl_safefree(keylog_file_name); } } #endif @@ -1313,6 +1333,51 @@ static void Curl_ossl_close_all(struct Curl_easy *data) /* ====================================================== */ +/* + * Match subjectAltName against the host name. This requires a conversion + * in CURL_DOES_CONVERSIONS builds. + */ +static bool subj_alt_hostcheck(struct Curl_easy *data, + const char *match_pattern, const char *hostname, + const char *dispname) +#ifdef CURL_DOES_CONVERSIONS +{ + bool res = FALSE; + + /* Curl_cert_hostcheck uses host encoding, but we get ASCII from + OpenSSl. + */ + char *match_pattern2 = strdup(match_pattern); + + if(match_pattern2) { + if(Curl_convert_from_network(data, match_pattern2, + strlen(match_pattern2)) == CURLE_OK) { + if(Curl_cert_hostcheck(match_pattern2, hostname)) { + res = TRUE; + infof(data, + " subjectAltName: host \"%s\" matched cert's \"%s\"\n", + dispname, match_pattern2); + } + } + free(match_pattern2); + } + else { + failf(data, + "SSL: out of memory when allocating temporary for subjectAltName"); + } + return res; +} +#else +{ + if(Curl_cert_hostcheck(match_pattern, hostname)) { + infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"\n", + dispname, match_pattern); + return TRUE; + } + return FALSE; +} +#endif + /* Quote from RFC2818 section 3.1 "Server Identity" @@ -1412,11 +1477,8 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) if((altlen == strlen(altptr)) && /* if this isn't true, there was an embedded zero in the name string and we cannot match it. */ - Curl_cert_hostcheck(altptr, hostname)) { + subj_alt_hostcheck(data, altptr, hostname, dispname)) { dnsmatched = TRUE; - infof(data, - " subjectAltName: host \"%s\" matched cert's \"%s\"\n", - dispname, altptr); } break; @@ -1727,13 +1789,40 @@ static const char *ssl_msg_type(int ssl_ver, int msg) case SSL3_MT_CERTIFICATE_STATUS: return "Certificate Status"; #endif +#ifdef SSL3_MT_ENCRYPTED_EXTENSIONS + case SSL3_MT_ENCRYPTED_EXTENSIONS: + return "Encrypted Extensions"; +#endif +#ifdef SSL3_MT_END_OF_EARLY_DATA + case SSL3_MT_END_OF_EARLY_DATA: + return "End of early data"; +#endif +#ifdef SSL3_MT_KEY_UPDATE + case SSL3_MT_KEY_UPDATE: + return "Key update"; +#endif +#ifdef SSL3_MT_NEXT_PROTO + case SSL3_MT_NEXT_PROTO: + return "Next protocol"; +#endif +#ifdef SSL3_MT_MESSAGE_HASH + case SSL3_MT_MESSAGE_HASH: + return "Message hash"; +#endif } } return "Unknown"; } -static const char *tls_rt_type(int type) +static const char *tls_rt_type(int type, const void *buf, size_t buflen) { + (void)buf; + (void)buflen; +#ifdef SSL3_RT_INNER_CONTENT_TYPE + if(type == SSL3_RT_INNER_CONTENT_TYPE && buf && buflen >= 1) + type = *(unsigned char *)buf; +#endif + switch(type) { #ifdef SSL3_RT_HEADER case SSL3_RT_HEADER: @@ -1761,10 +1850,7 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, void *userp) { struct Curl_easy *data; - const char *msg_name, *tls_rt_name; - char ssl_buf[1024]; char unknown[32]; - int msg_type, txt_len; const char *verstr = NULL; struct connectdata *conn = userp; @@ -1812,6 +1898,10 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, } if(ssl_ver) { + const char *msg_name, *tls_rt_name; + char ssl_buf[1024]; + int msg_type, txt_len; + /* the info given when the version is zero is not that useful for us */ ssl_ver >>= 8; /* check the upper 8 bits only below */ @@ -1821,17 +1911,28 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, * is at 'buf[0]'. */ if(ssl_ver == SSL3_VERSION_MAJOR && content_type) - tls_rt_name = tls_rt_type(content_type); + tls_rt_name = tls_rt_type(content_type, buf, len); else tls_rt_name = ""; - msg_type = *(char *)buf; - msg_name = ssl_msg_type(ssl_ver, msg_type); +#ifdef SSL3_RT_INNER_CONTENT_TYPE + if(content_type == SSL3_RT_INNER_CONTENT_TYPE) { + msg_type = 0; + msg_name = "[no content]"; + } + else +#endif + { + 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); + if(0 <= txt_len && (unsigned)txt_len < sizeof(ssl_buf)) { + Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL); + } } Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT : @@ -2084,8 +2185,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_3: /* it will be handled later with the context options */ -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ - !defined(LIBRESSL_VERSION_NUMBER) +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) req_method = TLS_client_method(); #else req_method = SSLv23_client_method(); @@ -2415,8 +2515,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) /* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */ #if defined(ENABLE_SSLKEYLOGFILE) && defined(HAVE_KEYLOG_CALLBACK) - if(keylog_file) { - SSL_CTX_set_keylog_callback(connssl->ctx, ossl_keylog_callback); + if(keylog_file_fp) { + SSL_CTX_set_keylog_callback(BACKEND->ctx, ossl_keylog_callback); } #endif @@ -2802,7 +2902,7 @@ static CURLcode get_cert_chain(struct connectdata *conn, ASN1_STRING *a = ASN1_STRING_new(); if(a) { X509_get0_signature(&psig, &palg, x); - X509_signature_print(mem, palg, a); + X509_signature_print(mem, ARG2_X509_signature_print palg, a); ASN1_STRING_free(a); if(palg) { @@ -3037,7 +3137,8 @@ static CURLcode servercert(struct connectdata *conn, long lerr, len; struct Curl_easy *data = conn->data; X509 *issuer; - FILE *fp; + BIO *fp = NULL; + char error_buffer[256]=""; char buffer[2048]; const char *ptr; long * const certverifyresult = SSL_IS_PROXY() ? @@ -3048,8 +3149,20 @@ static CURLcode servercert(struct connectdata *conn, /* we've been asked to gather certificate info! */ (void)get_cert_chain(conn, connssl); + fp = BIO_new(BIO_s_file()); + if(fp == NULL) { + failf(data, + "BIO_new return NULL, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + BIO_free(mem); + return 0; + } + BACKEND->server_cert = SSL_get_peer_certificate(BACKEND->handle); if(!BACKEND->server_cert) { + BIO_free(fp); BIO_free(mem); if(!strict) return CURLE_OK; @@ -3079,6 +3192,7 @@ static CURLcode servercert(struct connectdata *conn, if(SSL_CONN_CONFIG(verifyhost)) { result = verifyhost(conn, BACKEND->server_cert); if(result) { + BIO_free(fp); X509_free(BACKEND->server_cert); BACKEND->server_cert = NULL; return result; @@ -3100,35 +3214,35 @@ static CURLcode servercert(struct connectdata *conn, /* e.g. match issuer name with provided issuer certificate */ if(SSL_SET_OPTION(issuercert)) { - fp = fopen(SSL_SET_OPTION(issuercert), FOPEN_READTEXT); - if(!fp) { + if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) { if(strict) failf(data, "SSL: Unable to open issuer cert (%s)", SSL_SET_OPTION(issuercert)); + BIO_free(fp); X509_free(BACKEND->server_cert); BACKEND->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } - issuer = PEM_read_X509(fp, NULL, ZERO_NULL, NULL); + issuer = PEM_read_bio_X509(fp, NULL, ZERO_NULL, NULL); if(!issuer) { if(strict) failf(data, "SSL: Unable to read issuer cert (%s)", SSL_SET_OPTION(issuercert)); - X509_free(BACKEND->server_cert); + BIO_free(fp); X509_free(issuer); - fclose(fp); + X509_free(BACKEND->server_cert); + BACKEND->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } - fclose(fp); - if(X509_check_issued(issuer, BACKEND->server_cert) != X509_V_OK) { if(strict) failf(data, "SSL: Certificate issuer check failed (%s)", SSL_SET_OPTION(issuercert)); - X509_free(BACKEND->server_cert); + BIO_free(fp); X509_free(issuer); + X509_free(BACKEND->server_cert); BACKEND->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; } @@ -3163,6 +3277,7 @@ static CURLcode servercert(struct connectdata *conn, if(SSL_CONN_CONFIG(verifystatus)) { result = verifystatus(conn, connssl); if(result) { + BIO_free(fp); X509_free(BACKEND->server_cert); BACKEND->server_cert = NULL; return result; @@ -3182,6 +3297,7 @@ static CURLcode servercert(struct connectdata *conn, failf(data, "SSL: public key does not match pinned public key!"); } + BIO_free(fp); X509_free(BACKEND->server_cert); BACKEND->server_cert = NULL; connssl->connecting_state = ssl_connect_done; @@ -3393,12 +3509,13 @@ static bool Curl_ossl_data_pending(const struct connectdata *conn, { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; const struct ssl_connect_data *proxyssl = &conn->proxy_ssl[connindex]; - if(BACKEND->handle) - /* SSL is in use */ - return (0 != SSL_pending(BACKEND->handle) || - (proxyssl->backend->handle && - 0 != SSL_pending(proxyssl->backend->handle))) ? - TRUE : FALSE; + + if(connssl->backend->handle && SSL_pending(connssl->backend->handle)) + return TRUE; + + if(proxyssl->backend->handle && SSL_pending(proxyssl->backend->handle)) + return TRUE; + return FALSE; } @@ -3581,25 +3698,34 @@ static CURLcode Curl_ossl_md5sum(unsigned char *tmp, /* input */ unsigned char *md5sum /* output */, size_t unused) { - MD5_CTX MD5pw; - (void)unused; - MD5_Init(&MD5pw); - MD5_Update(&MD5pw, tmp, tmplen); - MD5_Final(md5sum, &MD5pw); + EVP_MD_CTX *mdctx; + unsigned int len = 0; + (void) unused; + + mdctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(mdctx, EVP_md5(), NULL); + EVP_DigestUpdate(mdctx, tmp, tmplen); + EVP_DigestFinal_ex(mdctx, md5sum, &len); + EVP_MD_CTX_destroy(mdctx); return CURLE_OK; } #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) -static void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ +static CURLcode 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); + EVP_MD_CTX *mdctx; + unsigned int len = 0; + (void) unused; + + mdctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL); + EVP_DigestUpdate(mdctx, tmp, tmplen); + EVP_DigestFinal_ex(mdctx, sha256sum, &len); + EVP_MD_CTX_destroy(mdctx); + return CURLE_OK; } #endif @@ -3624,11 +3750,11 @@ static void *Curl_ossl_get_internals(struct ssl_connect_data *connssl, const struct Curl_ssl Curl_ssl_openssl = { { CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */ - 1, /* have_ca_path */ - 1, /* have_certinfo */ - 1, /* have_pinnedpubkey */ - 1, /* have_ssl_ctx */ - 1, /* support_https_proxy */ + SSLSUPP_CA_PATH | + SSLSUPP_CERTINFO | + SSLSUPP_PINNEDPUBKEY | + SSLSUPP_SSL_CTX | + SSLSUPP_HTTPS_PROXY, sizeof(struct ssl_backend_data), |