diff options
Diffstat (limited to 'Utilities/cmcurl/lib/vtls/openssl.c')
-rw-r--r-- | Utilities/cmcurl/lib/vtls/openssl.c | 998 |
1 files changed, 505 insertions, 493 deletions
diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c index 90e4c2b..3027ca3 100644 --- a/Utilities/cmcurl/lib/vtls/openssl.c +++ b/Utilities/cmcurl/lib/vtls/openssl.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * 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 http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * 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 @@ -68,7 +68,7 @@ #include <openssl/pkcs12.h> #endif -#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_IS_BORINGSSL) +#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP) #include <openssl/ocsp.h> #endif @@ -83,23 +83,8 @@ #error "OPENSSL_VERSION_NUMBER not defined" #endif -#if OPENSSL_VERSION_NUMBER >= 0x00907001L && !defined(OPENSSL_IS_BORINGSSL) -/* ENGINE_load_private_key() takes four arguments */ -#define HAVE_ENGINE_LOAD_FOUR_ARGS +#if defined(HAVE_OPENSSL_ENGINE_H) #include <openssl/ui.h> -#else -/* ENGINE_load_private_key() takes three arguments */ -#undef HAVE_ENGINE_LOAD_FOUR_ARGS -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x00903001L) && \ - defined(HAVE_OPENSSL_PKCS12_H) && \ - !defined(OPENSSL_IS_BORINGSSL) -/* OpenSSL has PKCS 12 support, BoringSSL does not */ -#define HAVE_PKCS12_SUPPORT -#else -/* OpenSSL does not have PKCS12 support */ -#undef HAVE_PKCS12_SUPPORT #endif #if OPENSSL_VERSION_NUMBER >= 0x00909000L @@ -108,18 +93,13 @@ #define SSL_METHOD_QUAL #endif -#if OPENSSL_VERSION_NUMBER >= 0x00907000L -/* 0.9.6 didn't have X509_STORE_set_flags() */ -#define HAVE_X509_STORE_SET_FLAGS 1 -#else -#define X509_STORE_set_flags(x,y) Curl_nop_stmt -#endif - -#ifdef OPENSSL_IS_BORINGSSL -/* BoringSSL has no ERR_remove_state() */ -#define ERR_remove_state(x) -#elif (OPENSSL_VERSION_NUMBER >= 0x10000000L) +#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 +#endif #endif #if !defined(HAVE_SSLV2_CLIENT_METHOD) || \ @@ -128,19 +108,39 @@ #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) +#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 */ +#endif + +#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \ + !defined(LIBRESSL_VERSION_NUMBER) +#define HAVE_X509_GET0_SIGNATURE 1 #endif -#if (OPENSSL_VERSION_NUMBER < 0x0090808fL) || defined(OPENSSL_IS_BORINGSSL) -/* not present in BoringSSL or older OpenSSL */ +#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 @@ -171,7 +171,6 @@ 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) @@ -187,7 +186,7 @@ static bool rand_enough(int nread) } #endif -static int ossl_seed(struct SessionHandle *data) +static int ossl_seed(struct Curl_easy *data) { char *buf = data->state.buffer; /* point to the big buffer */ int nread=0; @@ -256,7 +255,7 @@ static int ossl_seed(struct SessionHandle *data) return nread; } -static void Curl_ossl_seed(struct SessionHandle *data) +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 */ @@ -268,11 +267,6 @@ static void Curl_ossl_seed(struct SessionHandle *data) ssl_seeded = TRUE; } } -#else -/* BoringSSL needs no seeding */ -#define Curl_ossl_seed(x) -#endif - #ifndef SSL_FILETYPE_ENGINE #define SSL_FILETYPE_ENGINE 42 @@ -295,7 +289,7 @@ static int do_file_type(const char *type) return -1; } -#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_LOAD_FOUR_ARGS) +#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() @@ -345,7 +339,7 @@ int cert_stuff(struct connectdata *conn, char *key_file, const char *key_type) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int file_type = do_file_type(cert_type); @@ -369,7 +363,8 @@ int cert_stuff(struct connectdata *conn, if(SSL_CTX_use_certificate_chain_file(ctx, cert_file) != 1) { failf(data, - "could not load PEM client certificate, OpenSSL error %s, " + "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) ); return 0; @@ -384,7 +379,8 @@ int cert_stuff(struct connectdata *conn, cert_file, file_type) != 1) { failf(data, - "could not load ASN1 client certificate, OpenSSL error %s, " + "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; @@ -445,12 +441,11 @@ int cert_stuff(struct connectdata *conn, case SSL_FILETYPE_PKCS12: { -#ifdef HAVE_PKCS12_SUPPORT +#ifdef HAVE_OPENSSL_PKCS12_H FILE *f; PKCS12 *p12; EVP_PKEY *pri; STACK_OF(X509) *ca = NULL; - int i; f = fopen(cert_file, "rb"); if(!f) { @@ -470,7 +465,8 @@ int cert_stuff(struct connectdata *conn, if(!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509, &ca)) { failf(data, - "could not parse PKCS12 file, check password, OpenSSL error %s", + "could not parse PKCS12 file, check password, " OSSL_PACKAGE + " error %s", ERR_error_string(ERR_get_error(), NULL) ); PKCS12_free(p12); return 0; @@ -480,7 +476,8 @@ int cert_stuff(struct connectdata *conn, if(SSL_CTX_use_certificate(ctx, x509) != 1) { failf(data, - "could not load PKCS12 client certificate, OpenSSL error %s", + "could not load PKCS12 client certificate, " OSSL_PACKAGE + " error %s", ERR_error_string(ERR_get_error(), NULL) ); goto fail; } @@ -497,8 +494,8 @@ int cert_stuff(struct connectdata *conn, goto fail; } /* Set Certificate Verification chain */ - if(ca && sk_X509_num(ca)) { - for(i = 0; i < sk_X509_num(ca); i++) { + 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 @@ -508,6 +505,7 @@ int cert_stuff(struct connectdata *conn, */ 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"); goto fail; } @@ -561,28 +559,23 @@ int cert_stuff(struct connectdata *conn, { /* XXXX still needs some work */ EVP_PKEY *priv_key = NULL; if(data->state.engine) { -#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS UI_METHOD *ui_method = UI_create_method((char *)"cURL user interface"); if(!ui_method) { - failf(data, "unable do create OpenSSL user-interface method"); + 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); -#endif /* the typecast below was added to please mingw32 */ priv_key = (EVP_PKEY *) ENGINE_load_private_key(data->state.engine, key_file, -#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS ui_method, -#endif data->set.str[STRING_KEY_PASSWD]); -#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS UI_destroy_method(ui_method); -#endif if(!priv_key) { failf(data, "failed to load private key from crypto engine"); return 0; @@ -679,7 +672,7 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size) /* Return error string for last OpenSSL error */ -static char *SSL_strerror(unsigned long error, char *buf, size_t size) +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 @@ -702,16 +695,6 @@ int Curl_ossl_init(void) ENGINE_load_builtin_engines(); #endif - /* 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(); - - /* 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 @@ -728,6 +711,15 @@ int Curl_ossl_init(void) 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(); + return 1; } @@ -751,15 +743,24 @@ void Curl_ossl_cleanup(void) ERR_free_strings(); /* Free thread local error state, destroying hash upon zero refcount */ -#ifdef HAVE_ERR_REMOVE_THREAD_STATE +#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 uses SSL_peek to determine connection status. + * This function is used to determine connection status. * * Return codes: * 1 means the connection is still in place @@ -768,22 +769,51 @@ void Curl_ossl_cleanup(void) */ int Curl_ossl_check_cxn(struct connectdata *conn) { - int rc; + /* SSL_peek takes data out of the raw recv buffer without peeking so we use + recv MSG_PEEK instead. Bug #795 */ +#ifdef MSG_PEEK char buf; - - rc = SSL_peek(conn->ssl[FIRSTSOCKET].handle, (void*)&buf, 1); - if(rc > 0) - return 1; /* connection still in place */ - - if(rc == 0) + ssize_t nread; + 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 */ - + else if(nread == 1) + 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 || +#endif +#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 SessionHandle *data, const char *engine) +CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine) { #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) ENGINE *e; @@ -814,7 +844,7 @@ CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine) ENGINE_free(e); failf(data, "Failed to initialise SSL Engine '%s':\n%s", - engine, SSL_strerror(ERR_get_error(), buf, sizeof(buf))); + engine, ossl_strerror(ERR_get_error(), buf, sizeof(buf))); return CURLE_SSL_ENGINE_INITFAILED; } data->state.engine = e; @@ -828,7 +858,7 @@ CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine) /* Sets engine as default for all SSL operations */ -CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data) +CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data) { #ifdef HAVE_OPENSSL_ENGINE_H if(data->state.engine) { @@ -850,7 +880,7 @@ CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data) /* Return list of OpenSSL crypto engine names. */ -struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data) +struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data) { struct curl_slist *list = NULL; #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) @@ -899,9 +929,9 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) { int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; - char buf[120]; /* We will use this for the OpenSSL error buffer, so it has - to be at least 120 bytes long. */ + 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. */ unsigned long sslerror; ssize_t nread; int buffsize; @@ -949,8 +979,8 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) default: /* openssl/ssl.h says "look at error stack/return value/errno" */ sslerror = ERR_get_error(); - failf(conn->data, "SSL read: %s, errno %d", - ERR_error_string(sslerror, buf), + failf(conn->data, OSSL_PACKAGE " SSL read: %s, errno %d", + ossl_strerror(sslerror, buf, sizeof(buf)), SOCKERRNO); done = 1; break; @@ -1002,7 +1032,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! */ -void Curl_ossl_close_all(struct SessionHandle *data) +void Curl_ossl_close_all(struct Curl_easy *data) { #ifdef HAVE_OPENSSL_ENGINE_H if(data->state.engine) { @@ -1015,49 +1045,6 @@ void Curl_ossl_close_all(struct SessionHandle *data) #endif } -static int asn1_output(const ASN1_UTCTIME *tm, - char *buf, - size_t sizeofbuf) -{ - const char *asn1_string; - int gmt=FALSE; - int i; - int year=0, month=0, day=0, hour=0, minute=0, second=0; - - i=tm->length; - asn1_string=(const char *)tm->data; - - if(i < 10) - return 1; - if(asn1_string[i-1] == 'Z') - gmt=TRUE; - for(i=0; i<10; i++) - if((asn1_string[i] > '9') || (asn1_string[i] < '0')) - return 2; - - year= (asn1_string[0]-'0')*10+(asn1_string[1]-'0'); - if(year < 50) - year+=100; - - month= (asn1_string[2]-'0')*10+(asn1_string[3]-'0'); - if((month > 12) || (month < 1)) - return 3; - - day= (asn1_string[4]-'0')*10+(asn1_string[5]-'0'); - hour= (asn1_string[6]-'0')*10+(asn1_string[7]-'0'); - minute= (asn1_string[8]-'0')*10+(asn1_string[9]-'0'); - - if((asn1_string[10] >= '0') && (asn1_string[10] <= '9') && - (asn1_string[11] >= '0') && (asn1_string[11] <= '9')) - second= (asn1_string[10]-'0')*10+(asn1_string[11]-'0'); - - snprintf(buf, sizeofbuf, - "%04d-%02d-%02d %02d:%02d:%02d %s", - year+1900, month, day, hour, minute, second, (gmt?"GMT":"")); - - return 0; -} - /* ====================================================== */ @@ -1084,11 +1071,10 @@ static int asn1_output(const ASN1_UTCTIME *tm, */ 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 */ + bool matched = FALSE; int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */ size_t addrlen = 0; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; STACK_OF(GENERAL_NAME) *altnames; #ifdef ENABLE_IPV6 struct in6_addr addr; @@ -1096,6 +1082,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) struct in_addr addr; #endif CURLcode result = CURLE_OK; + bool dNSName = FALSE; /* if a dNSName field exists in the cert */ #ifdef ENABLE_IPV6 if(conn->bits.ipv6_ip && @@ -1116,16 +1103,23 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) if(altnames) { int numalts; int i; + bool dnsmatched = FALSE; + bool ipmatched = FALSE; /* get amount of alternatives, RFC2459 claims there MUST be at least one, but we don't depend on it... */ numalts = sk_GENERAL_NAME_num(altnames); - /* loop through all alternatives while none has matched */ - for(i=0; (i<numalts) && (matched != 1); i++) { + /* loop through all alternatives - until a dnsmatch */ + for(i=0; (i < numalts) && !dnsmatched; i++) { /* get a handle to alternative name number i */ const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i); + /* If a subjectAltName extension of type dNSName is present, that MUST + be used as the identity. / RFC2818 section 3.1 */ + if(check->type == GEN_DNS) + dNSName = TRUE; + /* only check alternatives of the same type the target is */ if(check->type == target) { /* get data and length */ @@ -1147,33 +1141,42 @@ 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, conn->host.name)) - matched = 1; - else - matched = 0; + Curl_cert_hostcheck(altptr, conn->host.name)) { + dnsmatched = TRUE; + infof(data, + " subjectAltName: host \"%s\" matched cert's \"%s\"\n", + conn->host.dispname, altptr); + } break; case GEN_IPADD: /* IP address comparison */ /* compare alternative IP address if the data chunk is the same size our server IP address is */ - if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) - matched = 1; - else - matched = 0; + if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) { + ipmatched = TRUE; + infof(data, + " subjectAltName: host \"%s\" matched cert's IP address!\n", + conn->host.dispname); + } break; } } } GENERAL_NAMES_free(altnames); + + if(dnsmatched || (!dNSName && ipmatched)) { + /* count as a match if the dnsname matched or if there was no dnsname + fields at all AND there was an IP field match */ + matched = TRUE; + } } - if(matched == 1) - /* an alternative name matched the server hostname */ - infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname); - else if(matched == 0) { - /* an alternative name field existed, but didn't match and then - we MUST fail */ - infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname); + if(matched) + /* an alternative name matched */ + ; + else if(dNSName) { + /* an dNSName field existed, but didn't match and then we MUST fail */ + infof(data, " 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); result = CURLE_PEER_FAILED_VERIFICATION; @@ -1183,7 +1186,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) distinguished one to get the most significant one. */ int j, i=-1; -/* The following is done because of a bug in 0.9.6b */ + /* The following is done because of a bug in 0.9.6b */ unsigned char *nulstr = (unsigned char *)""; unsigned char *peer_CN = nulstr; @@ -1255,7 +1258,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) result = CURLE_PEER_FAILED_VERIFICATION; } else { - infof(data, "\t common name: %s (matched)\n", peer_CN); + infof(data, " common name: %s (matched)\n", peer_CN); } if(peer_CN) OPENSSL_free(peer_CN); @@ -1265,14 +1268,14 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) } #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_IS_BORINGSSL) + !defined(OPENSSL_NO_OCSP) 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; + struct Curl_easy *data = conn->data; OCSP_RESPONSE *rsp = NULL; OCSP_BASICRESP *br = NULL; @@ -1351,7 +1354,8 @@ static CURLcode verifystatus(struct connectdata *conn, ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; - if(!(single = OCSP_resp_get0(br, i))) + single = OCSP_resp_get0(br, i); + if(!single) continue; cert_status = OCSP_single_get0_status(single, &crl_reason, &rev, @@ -1487,7 +1491,7 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, const void *buf, size_t len, SSL *ssl, void *userp) { - struct SessionHandle *data; + struct Curl_easy *data; const char *msg_name, *tls_rt_name; char ssl_buf[1024]; char unknown[32]; @@ -1620,12 +1624,12 @@ select_next_proto_cb(SSL *ssl, (void)ssl; #ifdef USE_NGHTTP2 - if(conn->data->set.httpversion == CURL_HTTP_VERSION_2_0 && + if(conn->data->set.httpversion >= CURL_HTTP_VERSION_2 && !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 = CURL_HTTP_VERSION_2_0; + conn->negnpn = CURL_HTTP_VERSION_2; return SSL_TLSEXT_ERR_OK; } #endif @@ -1673,9 +1677,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; char *ciphers; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; 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]; @@ -1707,7 +1710,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) 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) + !defined(LIBRESSL_VERSION_NUMBER) req_method = TLS_client_method(); #else req_method = SSLv23_client_method(); @@ -1716,7 +1719,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) break; case CURL_SSLVERSION_SSLv2: #ifdef OPENSSL_NO_SSL2 - failf(data, "OpenSSL was built without SSLv2 support"); + failf(data, OSSL_PACKAGE " was built without SSLv2 support"); return CURLE_NOT_BUILT_IN; #else #ifdef USE_TLS_SRP @@ -1729,7 +1732,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #endif case CURL_SSLVERSION_SSLv3: #ifdef OPENSSL_NO_SSL3_METHOD - failf(data, "OpenSSL was built without SSLv3 support"); + failf(data, OSSL_PACKAGE " was built without SSLv3 support"); return CURLE_NOT_BUILT_IN; #else #ifdef USE_TLS_SRP @@ -1887,17 +1890,17 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) SSL_CTX_set_options(connssl->ctx, ctx_options); #ifdef HAS_NPN - if(data->set.ssl_enable_npn) + if(conn->bits.tls_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) { + if(conn->bits.tls_enable_alpn) { int cur = 0; unsigned char protocols[128]; #ifdef USE_NGHTTP2 - if(data->set.httpversion == CURL_HTTP_VERSION_2_0) { + if(data->set.httpversion >= CURL_HTTP_VERSION_2) { protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN; memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID, @@ -1997,6 +2000,13 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]: "none"); } +#ifdef CURL_CA_FALLBACK + else if(data->set.ssl.verifypeer) { + /* verfying the peer without any CA certificates won't + work so use openssl's built in default as fallback */ + SSL_CTX_set_default_verify_paths(connssl->ctx); + } +#endif if(data->set.str[STRING_SSL_CRLFILE]) { /* tell SSL where to find CRL file that is used to check certificate @@ -2063,7 +2073,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) } #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_IS_BORINGSSL) + !defined(OPENSSL_NO_OCSP) if(data->set.ssl.verifystatus) SSL_set_tlsext_status_type(connssl->handle, TLSEXT_STATUSTYPE_ocsp); #endif @@ -2084,15 +2094,22 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #endif /* Check if there's a cached ID we can/should use here! */ - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { - /* 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)); - return CURLE_SSL_CONNECT_ERROR; + if(conn->ssl_config.sessionid) { + void *ssl_sessionid = NULL; + + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { + /* we got a session id, use it! */ + if(!SSL_set_session(connssl->handle, ssl_sessionid)) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "SSL: SSL_set_session failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof (data, "SSL re-using session ID\n"); } - /* Informational message */ - infof (data, "SSL re-using session ID\n"); + Curl_ssl_sessionid_unlock(conn); } /* pass the raw socket into the SSL layers */ @@ -2109,7 +2126,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int err; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; DEBUGASSERT(ssl_connect_2 == connssl->connecting_state @@ -2141,27 +2158,22 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) least 256 bytes long. */ CURLcode result; long lerr; + int lib; + int reason; - connssl->connecting_state = ssl_connect_2; /* the connection failed, - we're not waiting for - anything else. */ - - errdetail = ERR_get_error(); /* Gets the earliest error code from the - thread's error queue and removes the - entry. */ - - switch(errdetail) { - case 0x1407E086: - /* 1407E086: - SSL routines: - SSL2_SET_CERTIFICATE: - certificate verify failed */ - /* fall-through */ - case 0x14090086: - /* 14090086: - SSL routines: - SSL3_GET_SERVER_CERTIFICATE: - certificate verify failed */ + /* the connection failed, we're not waiting for anything else. */ + connssl->connecting_state = ssl_connect_2; + + /* Get the earliest error code from the thread's error queue and removes + the entry. */ + errdetail = ERR_get_error(); + + /* Extract which lib and reason */ + lib = ERR_GET_LIB(errdetail); + reason = ERR_GET_REASON(errdetail); + + if((lib == ERR_LIB_SSL) && + (reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) { result = CURLE_SSL_CACERT; lerr = SSL_get_verify_result(connssl->handle); @@ -2173,13 +2185,11 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) else /* 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: + strcpy(error_buffer, "SSL certificate verification failed"); + } + else { result = CURLE_SSL_CONNECT_ERROR; - SSL_strerror(errdetail, error_buffer, sizeof(error_buffer)); - break; + ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)); } /* detail is already set to the SSL error above */ @@ -2213,7 +2223,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) /* Sets data and len to negotiated protocol, len is 0 if no protocol was * negotiated */ - if(data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_alpn) { const unsigned char* neg_protocol; unsigned int len; SSL_get0_alpn_selected(connssl->handle, &neg_protocol, &len); @@ -2223,7 +2233,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) #ifdef USE_NGHTTP2 if(len == NGHTTP2_PROTO_VERSION_ID_LEN && !memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len)) { - conn->negnpn = CURL_HTTP_VERSION_2_0; + conn->negnpn = CURL_HTTP_VERSION_2; } else #endif @@ -2256,58 +2266,59 @@ static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) return 0; } -static void pubkey_show(struct SessionHandle *data, +#define push_certinfo(_label, _num) \ +do { \ + long info_len = BIO_get_mem_data(mem, &ptr); \ + Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \ + if(1!=BIO_reset(mem)) \ + break; \ +} WHILE_FALSE + +static void pubkey_show(struct Curl_easy *data, + BIO *mem, int num, const char *type, const char *name, - unsigned char *raw, - int len) +#ifdef HAVE_OPAQUE_RSA_DSA_DH + const +#endif + BIGNUM *bn) { - size_t left; - int i; + char *ptr; char namebuf[32]; - char *buffer; - - left = len*3 + 1; - buffer = malloc(left); - if(buffer) { - char *ptr=buffer; - snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); - for(i=0; i< len; i++) { - snprintf(ptr, left, "%02x:", raw[i]); - ptr += 3; - left -= 3; - } - infof(data, " %s: %s\n", namebuf, buffer); - Curl_ssl_push_certinfo(data, num, namebuf, buffer); - free(buffer); - } + + snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); + + if(bn) + BN_print(mem, bn); + push_certinfo(namebuf, num); } +#ifdef HAVE_OPAQUE_RSA_DSA_DH +#define print_pubkey_BN(_type, _name, _num) \ + pubkey_show(data, mem, _num, #_type, #_name, _name) + +#else #define print_pubkey_BN(_type, _name, _num) \ do { \ - 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); \ - bufp[len] = 0; \ - pubkey_show(data, _num, #_type, #_name, (unsigned char*)bufp, len); \ - } \ + if(_type->_name) { \ + pubkey_show(data, mem, _num, #_type, #_name, _type->_name); \ } \ } WHILE_FALSE +#endif -static int X509V3_ext(struct SessionHandle *data, +static int X509V3_ext(struct Curl_easy *data, int certnum, STACK_OF(X509_EXTENSION) *exts) { int i; size_t j; - if(sk_X509_EXTENSION_num(exts) <= 0) + if((int)sk_X509_EXTENSION_num(exts) <= 0) /* no extensions, bail out */ return 1; - for(i=0; i<sk_X509_EXTENSION_num(exts); i++) { + for(i=0; i < (int)sk_X509_EXTENSION_num(exts); i++) { ASN1_OBJECT *obj; X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); BUF_MEM *biomem; @@ -2323,18 +2334,12 @@ static int X509V3_ext(struct SessionHandle *data, asn1_object_dump(obj, namebuf, sizeof(namebuf)); - infof(data, "%s: %s\n", namebuf, - X509_EXTENSION_get_critical(ext)?"(critical)":""); - if(!X509V3_EXT_print(bio_out, ext, 0, 0)) ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext)); BIO_get_mem_ptr(bio_out, &biomem); - /* biomem->length bytes at biomem->data, this little loop here is only - done for the infof() call, we send the "raw" data to the certinfo - function */ - for(j=0; j<(size_t)biomem->length; j++) { + for(j = 0; j < (size_t)biomem->length; j++) { const char *sep=""; if(biomem->data[j] == '\n') { sep=", "; @@ -2346,7 +2351,6 @@ static int X509V3_ext(struct SessionHandle *data, ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep, biomem->data[j]); } - infof(data, " %s\n", buf); Curl_ssl_push_certinfo(data, certnum, namebuf, buf); @@ -2356,46 +2360,6 @@ static int X509V3_ext(struct SessionHandle *data, return 0; /* all is fine */ } - -static void X509_signature(struct SessionHandle *data, - int numcert, - ASN1_STRING *sig) -{ - 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]); - - infof(data, " Signature: %s\n", buf); - Curl_ssl_push_certinfo(data, numcert, "Signature", buf); -} - -static void dumpcert(struct SessionHandle *data, X509 *x, int numcert) -{ - BIO *bio_out = BIO_new(BIO_s_mem()); - BUF_MEM *biomem; - - /* this outputs the cert in this 64 column wide style with newlines and - -----BEGIN CERTIFICATE----- texts and more */ - PEM_write_bio_X509(bio_out, x); - - BIO_get_mem_ptr(bio_out, &biomem); - - Curl_ssl_push_certinfo_len(data, numcert, - "Cert", biomem->data, biomem->length); - - BIO_free(bio_out); -} - -/* - * This size was previously 512 which has been reported "too small" without - * any specifics, so it was enlarged to allow more data to get shown uncut. - * The "perfect" size is yet to figure out. - */ -#define CERTBUFFERSIZE 8192 - static CURLcode get_cert_chain(struct connectdata *conn, struct ssl_connect_data *connssl) @@ -2403,17 +2367,12 @@ static CURLcode get_cert_chain(struct connectdata *conn, CURLcode result; STACK_OF(X509) *sk; int i; - char *bufp; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int numcerts; - - bufp = malloc(CERTBUFFERSIZE); - if(!bufp) - return CURLE_OUT_OF_MEMORY; + BIO *mem; sk = SSL_get_peer_cert_chain(connssl->handle); if(!sk) { - free(bufp); return CURLE_OUT_OF_MEMORY; } @@ -2421,99 +2380,122 @@ static CURLcode get_cert_chain(struct connectdata *conn, result = Curl_ssl_init_certinfo(data, numcerts); if(result) { - free(bufp); return result; } - infof(data, "--- Certificate chain\n"); - for(i=0; i<numcerts; i++) { - long value; - ASN1_INTEGER *num; - ASN1_TIME *certdate; + mem = BIO_new(BIO_s_mem()); - /* get the certs in "importance order" */ -#if 0 - X509 *x = sk_X509_value(sk, numcerts - i - 1); -#else + for(i = 0; i < numcerts; i++) { + ASN1_INTEGER *num; X509 *x = sk_X509_value(sk, i); -#endif - - X509_CINF *cinf; EVP_PKEY *pubkey=NULL; int j; char *ptr; + ASN1_BIT_STRING *psig = NULL; - (void)x509_name_oneline(X509_get_subject_name(x), bufp, CERTBUFFERSIZE); - infof(data, "%2d Subject: %s\n", i, bufp); - Curl_ssl_push_certinfo(data, i, "Subject", bufp); + X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); + push_certinfo("Subject", i); - (void)x509_name_oneline(X509_get_issuer_name(x), bufp, CERTBUFFERSIZE); - infof(data, " Issuer: %s\n", bufp); - Curl_ssl_push_certinfo(data, i, "Issuer", bufp); + X509_NAME_print_ex(mem, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE); + push_certinfo("Issuer", i); - value = X509_get_version(x); - infof(data, " Version: %lu (0x%lx)\n", value+1, value); - snprintf(bufp, CERTBUFFERSIZE, "%lx", value); - Curl_ssl_push_certinfo(data, i, "Version", bufp); /* hex */ + BIO_printf(mem, "%lx", X509_get_version(x)); + push_certinfo("Version", i); - num=X509_get_serialNumber(x); - { - int left = CERTBUFFERSIZE; + num = X509_get_serialNumber(x); + if(num->type == V_ASN1_NEG_INTEGER) + BIO_puts(mem, "-"); + for(j = 0; j < num->length; j++) + BIO_printf(mem, "%02x", num->data[j]); + push_certinfo("Serial Number", i); - ptr = bufp; - if(num->type == V_ASN1_NEG_INTEGER) { - *ptr++='-'; - left--; - } - - for(j=0; (j<num->length) && (left>=3); j++) { - snprintf(ptr, left, "%02x", num->data[j]); - ptr += 2; - left -= 2; +#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS) + { + X509_ALGOR *palg = NULL; + ASN1_STRING *a = ASN1_STRING_new(); + if(a) { + X509_get0_signature(&psig, &palg, x); + X509_signature_print(mem, palg, a); + ASN1_STRING_free(a); + + if(palg) { + i2a_ASN1_OBJECT(mem, palg->algorithm); + push_certinfo("Public Key Algorithm", i); + } } - if(num->length) - infof(data, " Serial Number: %s\n", bufp); - else - bufp[0]=0; + X509V3_ext(data, i, X509_get0_extensions(x)); } - if(bufp[0]) - Curl_ssl_push_certinfo(data, i, "Serial Number", bufp); /* hex */ - - cinf = x->cert_info; +#else + { + /* before OpenSSL 1.0.2 */ + X509_CINF *cinf = x->cert_info; - j = asn1_object_dump(cinf->signature->algorithm, bufp, CERTBUFFERSIZE); - if(!j) { - infof(data, " Signature Algorithm: %s\n", bufp); - Curl_ssl_push_certinfo(data, i, "Signature Algorithm", bufp); - } + i2a_ASN1_OBJECT(mem, cinf->signature->algorithm); + push_certinfo("Signature Algorithm", i); - certdate = X509_get_notBefore(x); - asn1_output(certdate, bufp, CERTBUFFERSIZE); - infof(data, " Start date: %s\n", bufp); - Curl_ssl_push_certinfo(data, i, "Start date", bufp); + i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm); + push_certinfo("Public Key Algorithm", i); - certdate = X509_get_notAfter(x); - asn1_output(certdate, bufp, CERTBUFFERSIZE); - infof(data, " Expire date: %s\n", bufp); - Curl_ssl_push_certinfo(data, i, "Expire date", bufp); + X509V3_ext(data, i, cinf->extensions); - j = asn1_object_dump(cinf->key->algor->algorithm, bufp, CERTBUFFERSIZE); - if(!j) { - infof(data, " Public Key Algorithm: %s\n", bufp); - Curl_ssl_push_certinfo(data, i, "Public Key Algorithm", bufp); + psig = x->signature; } +#endif + + ASN1_TIME_print(mem, X509_get_notBefore(x)); + push_certinfo("Start date", i); + + ASN1_TIME_print(mem, X509_get_notAfter(x)); + push_certinfo("Expire date", i); pubkey = X509_get_pubkey(x); if(!pubkey) infof(data, " Unable to load public key\n"); else { - switch(pubkey->type) { + int pktype; +#ifdef HAVE_OPAQUE_EVP_PKEY + pktype = EVP_PKEY_id(pubkey); +#else + pktype = pubkey->type; +#endif + switch(pktype) { case EVP_PKEY_RSA: - infof(data, " RSA Public Key (%d bits)\n", - BN_num_bits(pubkey->pkey.rsa->n)); - snprintf(bufp, CERTBUFFERSIZE, "%d", BN_num_bits(pubkey->pkey.rsa->n)); - Curl_ssl_push_certinfo(data, i, "RSA Public Key", bufp); - + { + RSA *rsa; +#ifdef HAVE_OPAQUE_EVP_PKEY + rsa = EVP_PKEY_get0_RSA(pubkey); +#else + rsa = pubkey->pkey.rsa; +#endif + +#ifdef HAVE_OPAQUE_RSA_DSA_DH + { + const BIGNUM *n; + const BIGNUM *e; + const BIGNUM *d; + const BIGNUM *p; + const BIGNUM *q; + const BIGNUM *dmp1; + const BIGNUM *dmq1; + const BIGNUM *iqmp; + + RSA_get0_key(rsa, &n, &e, &d); + RSA_get0_factors(rsa, &p, &q); + RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); + BN_print(mem, n); + push_certinfo("RSA Public Key", i); + print_pubkey_BN(rsa, n, i); + print_pubkey_BN(rsa, e, i); + print_pubkey_BN(rsa, d, i); + print_pubkey_BN(rsa, p, i); + print_pubkey_BN(rsa, q, i); + print_pubkey_BN(rsa, dmp1, i); + print_pubkey_BN(rsa, dmq1, i); + print_pubkey_BN(rsa, iqmp, i); + } +#else + BIO_printf(mem, "%d", BN_num_bits(rsa->n)); + push_certinfo("RSA Public Key", i); print_pubkey_BN(rsa, n, i); print_pubkey_BN(rsa, e, i); print_pubkey_BN(rsa, d, i); @@ -2522,20 +2504,75 @@ static CURLcode get_cert_chain(struct connectdata *conn, print_pubkey_BN(rsa, dmp1, i); print_pubkey_BN(rsa, dmq1, i); print_pubkey_BN(rsa, iqmp, i); +#endif + break; + } case EVP_PKEY_DSA: + { + DSA *dsa; +#ifdef HAVE_OPAQUE_EVP_PKEY + dsa = EVP_PKEY_get0_DSA(pubkey); +#else + dsa = pubkey->pkey.dsa; +#endif +#ifdef HAVE_OPAQUE_RSA_DSA_DH + { + const BIGNUM *p; + const BIGNUM *q; + const BIGNUM *g; + const BIGNUM *priv_key; + const BIGNUM *pub_key; + + DSA_get0_pqg(dsa, &p, &q, &g); + DSA_get0_key(dsa, &pub_key, &priv_key); + + print_pubkey_BN(dsa, p, i); + print_pubkey_BN(dsa, q, i); + print_pubkey_BN(dsa, g, i); + print_pubkey_BN(dsa, priv_key, i); + print_pubkey_BN(dsa, pub_key, i); + } +#else print_pubkey_BN(dsa, p, i); print_pubkey_BN(dsa, q, i); print_pubkey_BN(dsa, g, i); print_pubkey_BN(dsa, priv_key, i); print_pubkey_BN(dsa, pub_key, i); +#endif break; + } case EVP_PKEY_DH: + { + DH *dh; +#ifdef HAVE_OPAQUE_EVP_PKEY + dh = EVP_PKEY_get0_DH(pubkey); +#else + dh = pubkey->pkey.dh; +#endif +#ifdef HAVE_OPAQUE_RSA_DSA_DH + { + const BIGNUM *p; + const BIGNUM *q; + const BIGNUM *g; + const BIGNUM *priv_key; + const BIGNUM *pub_key; + DH_get0_pqg(dh, &p, &q, &g); + DH_get0_key(dh, &pub_key, &priv_key); + print_pubkey_BN(dh, p, i); + print_pubkey_BN(dh, q, i); + print_pubkey_BN(dh, g, i); + print_pubkey_BN(dh, priv_key, i); + print_pubkey_BN(dh, pub_key, i); + } +#else print_pubkey_BN(dh, p, i); print_pubkey_BN(dh, g, i); print_pubkey_BN(dh, priv_key, i); print_pubkey_BN(dh, pub_key, i); +#endif break; + } #if 0 case EVP_PKEY_EC: /* symbol not present in OpenSSL 0.9.6 */ /* left TODO */ @@ -2545,14 +2582,17 @@ static CURLcode get_cert_chain(struct connectdata *conn, EVP_PKEY_free(pubkey); } - X509V3_ext(data, i, cinf->extensions); - - X509_signature(data, i, x->signature); + if(psig) { + for(j = 0; j < psig->length; j++) + BIO_printf(mem, "%02x:", psig->data[j]); + push_certinfo("Signature", i); + } - dumpcert(data, x, i); + PEM_write_bio_X509(mem, x); + push_certinfo("Cert", i); } - free(bufp); + BIO_free(mem); return CURLE_OK; } @@ -2561,7 +2601,8 @@ 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) +static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, + const char *pinnedpubkey) { /* Scratch */ int len1 = 0, len2 = 0; @@ -2606,7 +2647,7 @@ static CURLcode pkp_pin_peer_pubkey(X509* cert, const char *pinnedpubkey) /* End Gyrations */ /* The one good exit point */ - result = Curl_pin_peer_pubkey(pinnedpubkey, buff1, len1); + result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1); } while(0); /* https://www.openssl.org/docs/crypto/buffer.html */ @@ -2630,13 +2671,13 @@ static CURLcode servercert(struct connectdata *conn, { CURLcode result = CURLE_OK; int rc; - long lerr; - ASN1_TIME *certdate; - struct SessionHandle *data = conn->data; + long lerr, len; + struct Curl_easy *data = conn->data; X509 *issuer; FILE *fp; char *buffer = data->state.buffer; const char *ptr; + BIO *mem = BIO_new(BIO_s_mem()); if(data->set.ssl.certinfo) /* we've been asked to gather certificate info! */ @@ -2644,8 +2685,10 @@ static CURLcode servercert(struct connectdata *conn, connssl->server_cert = SSL_get_peer_certificate(connssl->handle); if(!connssl->server_cert) { - if(strict) - failf(data, "SSL: couldn't get peer certificate!"); + if(!strict) + return CURLE_OK; + + failf(data, "SSL: couldn't get peer certificate!"); return CURLE_PEER_FAILED_VERIFICATION; } @@ -2653,15 +2696,19 @@ static CURLcode servercert(struct connectdata *conn, rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert), buffer, BUFSIZE); - infof(data, "\t subject: %s\n", rc?"[NONE]":buffer); + infof(data, " subject: %s\n", rc?"[NONE]":buffer); + + ASN1_TIME_print(mem, X509_get_notBefore(connssl->server_cert)); + len = BIO_get_mem_data(mem, (char **) &ptr); + infof(data, " start date: %.*s\n", len, ptr); + rc = BIO_reset(mem); - certdate = X509_get_notBefore(connssl->server_cert); - asn1_output(certdate, buffer, BUFSIZE); - infof(data, "\t start date: %s\n", buffer); + ASN1_TIME_print(mem, X509_get_notAfter(connssl->server_cert)); + len = BIO_get_mem_data(mem, (char **) &ptr); + infof(data, " expire date: %.*s\n", len, ptr); + rc = BIO_reset(mem); - certdate = X509_get_notAfter(connssl->server_cert); - asn1_output(certdate, buffer, BUFSIZE); - infof(data, "\t expire date: %s\n", buffer); + BIO_free(mem); if(data->set.ssl.verifyhost) { result = verifyhost(conn, connssl->server_cert); @@ -2680,7 +2727,7 @@ static CURLcode servercert(struct connectdata *conn, result = CURLE_SSL_CONNECT_ERROR; } else { - infof(data, "\t issuer: %s\n", buffer); + infof(data, " issuer: %s\n", buffer); /* We could do all sorts of certificate verification stuff here before deallocating the certificate. */ @@ -2720,7 +2767,7 @@ static CURLcode servercert(struct connectdata *conn, return CURLE_SSL_ISSUER_ERROR; } - infof(data, "\t SSL certificate issuer check ok (%s)\n", + infof(data, " SSL certificate issuer check ok (%s)\n", data->set.str[STRING_SSL_ISSUERCERT]); X509_free(issuer); } @@ -2738,16 +2785,16 @@ static CURLcode servercert(struct connectdata *conn, result = CURLE_PEER_FAILED_VERIFICATION; } else - infof(data, "\t SSL certificate verify result: %s (%ld)," + infof(data, " SSL certificate verify result: %s (%ld)," " continuing anyway.\n", X509_verify_cert_error_string(lerr), lerr); } else - infof(data, "\t SSL certificate verify ok.\n"); + infof(data, " SSL certificate verify ok.\n"); } #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_IS_BORINGSSL) + !defined(OPENSSL_NO_OCSP) if(data->set.ssl.verifystatus) { result = verifystatus(conn, connssl); if(result) { @@ -2764,7 +2811,7 @@ static CURLcode servercert(struct connectdata *conn, ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; if(!result && ptr) { - result = pkp_pin_peer_pubkey(connssl->server_cert, ptr); + result = pkp_pin_peer_pubkey(data, connssl->server_cert, ptr); if(result) failf(data, "SSL: public key does not match pinned public key!"); } @@ -2779,43 +2826,49 @@ static CURLcode servercert(struct connectdata *conn, static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; - void *old_ssl_sessionid = NULL; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - bool incache; - SSL_SESSION *our_ssl_sessionid; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - our_ssl_sessionid = SSL_get1_session(connssl->handle); + if(conn->ssl_config.sessionid) { + bool incache; + SSL_SESSION *our_ssl_sessionid; + void *old_ssl_sessionid = NULL; - /* 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. */ + our_ssl_sessionid = SSL_get1_session(connssl->handle); - incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); - if(incache) { - if(old_ssl_sessionid != our_ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - incache = FALSE; + /* 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. */ + + Curl_ssl_sessionid_lock(conn); + incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); + if(incache) { + if(old_ssl_sessionid != our_ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing\n"); + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + incache = FALSE; + } } - } - if(!incache) { - result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */); - if(result) { - failf(data, "failed to store ssl session"); - return result; + if(!incache) { + result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, + 0 /* unknown size */); + if(result) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "failed to store ssl session"); + return result; + } } - } - else { - /* Session was incache, so refcount already incremented earlier. - * Avoid further increments with each SSL_get1_session() call. - * This does not free the session as refcount remains > 0 - */ - SSL_SESSION_free(our_ssl_sessionid); + else { + /* Session was incache, so refcount already incremented earlier. + * Avoid further increments with each SSL_get1_session() call. + * This does not free the session as refcount remains > 0 + */ + SSL_SESSION_free(our_ssl_sessionid); + } + Curl_ssl_sessionid_unlock(conn); } /* @@ -2843,7 +2896,7 @@ static CURLcode ossl_connect_common(struct connectdata *conn, bool *done) { CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; long timeout_ms; @@ -2987,7 +3040,7 @@ static ssize_t ossl_send(struct connectdata *conn, /* SSL_write() is said to return 'int' while write() and send() returns 'size_t' */ int err; - char error_buffer[120]; /* OpenSSL documents that this must be at least 120 + char error_buffer[256]; /* OpenSSL documents that this must be at least 256 bytes long. */ unsigned long sslerror; int memlen; @@ -3019,7 +3072,7 @@ static ssize_t ossl_send(struct connectdata *conn, The OpenSSL error queue contains more information on the error. */ sslerror = ERR_get_error(); failf(conn->data, "SSL_write() error: %s", - ERR_error_string(sslerror, error_buffer)); + ossl_strerror(sslerror, error_buffer, sizeof(error_buffer))); *curlcode = CURLE_SEND_ERROR; return -1; } @@ -3038,8 +3091,8 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ size_t buffersize, /* max amount to read */ CURLcode *curlcode) { - char error_buffer[120]; /* OpenSSL documents that this must be at - least 120 bytes long. */ + char error_buffer[256]; /* OpenSSL documents that this must be at + least 256 bytes long. */ unsigned long sslerror; ssize_t nread; int buffsize; @@ -3070,7 +3123,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ /* If the return code was negative or there actually is an error in the queue */ failf(conn->data, "SSL read: %s, errno %d", - ERR_error_string(sslerror, error_buffer), + ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)), SOCKERRNO); *curlcode = CURLE_RECV_ERROR; return -1; @@ -3082,86 +3135,45 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ size_t Curl_ossl_version(char *buffer, size_t size) { -#ifdef YASSL_VERSION - /* yassl provides an OpenSSL API compatibility layer so it looks identical - 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"); + return snprintf(buffer, size, OSSL_PACKAGE); #else /* OPENSSL_IS_BORINGSSL */ - -#if(OPENSSL_VERSION_NUMBER >= 0x905000) - { - char sub[3]; - unsigned long ssleay_value; - sub[2]='\0'; - sub[1]='\0'; - ssleay_value=SSLeay(); - if(ssleay_value < 0x906000) { - ssleay_value=SSLEAY_VERSION_NUMBER; - sub[0]='\0'; - } - else { - if(ssleay_value&0xff0) { - int minor_ver = (ssleay_value >> 4) & 0xff; - if(minor_ver > 26) { - /* handle extended version introduced for 0.9.8za */ - sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1); - sub[0] = 'z'; - } - else { - sub[0]=(char)(((ssleay_value>>4)&0xff) + 'a' -1); - } - } - else - sub[0]='\0'; - } - - return snprintf(buffer, size, "%s/%lx.%lx.%lx%s", -#ifdef LIBRESSL_VERSION_NUMBER - "LibreSSL" -#else - "OpenSSL" -#endif - , (ssleay_value>>28)&0xf, - (ssleay_value>>20)&0xff, - (ssleay_value>>12)&0xff, - sub); + char sub[3]; + unsigned long ssleay_value; + sub[2]='\0'; + sub[1]='\0'; + ssleay_value=SSLeay(); + if(ssleay_value < 0x906000) { + ssleay_value=SSLEAY_VERSION_NUMBER; + sub[0]='\0'; } - -#else /* OPENSSL_VERSION_NUMBER is less than 0.9.5 */ - -#if(OPENSSL_VERSION_NUMBER >= 0x900000) - return snprintf(buffer, size, "OpenSSL/%lx.%lx.%lx", - (OPENSSL_VERSION_NUMBER>>28)&0xff, - (OPENSSL_VERSION_NUMBER>>20)&0xff, - (OPENSSL_VERSION_NUMBER>>12)&0xf); - -#else /* (OPENSSL_VERSION_NUMBER >= 0x900000) */ - { - char sub[2]; - sub[1]='\0'; - if(OPENSSL_VERSION_NUMBER&0x0f) { - sub[0]=(OPENSSL_VERSION_NUMBER&0x0f) + 'a' -1; + else { + if(ssleay_value&0xff0) { + int minor_ver = (ssleay_value >> 4) & 0xff; + if(minor_ver > 26) { + /* handle extended version introduced for 0.9.8za */ + sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1); + sub[0] = 'z'; + } + else { + sub[0]=(char)(((ssleay_value>>4)&0xff) + 'a' -1); + } } else sub[0]='\0'; - - return snprintf(buffer, size, "SSL/%x.%x.%x%s", - (OPENSSL_VERSION_NUMBER>>12)&0xff, - (OPENSSL_VERSION_NUMBER>>8)&0xf, - (OPENSSL_VERSION_NUMBER>>4)&0xf, sub); } -#endif /* (OPENSSL_VERSION_NUMBER >= 0x900000) */ -#endif /* OPENSSL_VERSION_NUMBER is less than 0.9.5 */ + return snprintf(buffer, size, "%s/%lx.%lx.%lx%s", + OSSL_PACKAGE, + (ssleay_value>>28)&0xf, + (ssleay_value>>20)&0xff, + (ssleay_value>>12)&0xff, + sub); #endif /* OPENSSL_IS_BORINGSSL */ -#endif /* YASSL_VERSION */ } /* can be called with data == NULL */ -int Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy, +int Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { if(data) { @@ -3183,7 +3195,7 @@ void Curl_ossl_md5sum(unsigned char *tmp, /* input */ MD5_Final(md5sum, &MD5pw); } -#ifndef OPENSSL_NO_SHA256 +#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ size_t tmplen, unsigned char *sha256sum /* output */, @@ -3200,7 +3212,7 @@ void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ bool Curl_ossl_cert_status_request(void) { #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_IS_BORINGSSL) + !defined(OPENSSL_NO_OCSP) return TRUE; #else return FALSE; |