diff options
Diffstat (limited to 'Utilities/cmcurl/lib/vtls')
-rw-r--r-- | Utilities/cmcurl/lib/vtls/bearssl.c | 142 | ||||
-rw-r--r-- | Utilities/cmcurl/lib/vtls/gskit.c | 39 | ||||
-rw-r--r-- | Utilities/cmcurl/lib/vtls/gtls.c | 129 | ||||
-rw-r--r-- | Utilities/cmcurl/lib/vtls/mbedtls.c | 202 | ||||
-rw-r--r-- | Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c | 27 | ||||
-rw-r--r-- | Utilities/cmcurl/lib/vtls/mesalink.c | 18 | ||||
-rw-r--r-- | Utilities/cmcurl/lib/vtls/nss.c | 92 | ||||
-rw-r--r-- | Utilities/cmcurl/lib/vtls/openssl.c | 228 | ||||
-rw-r--r-- | Utilities/cmcurl/lib/vtls/rustls.c | 66 | ||||
-rw-r--r-- | Utilities/cmcurl/lib/vtls/schannel.c | 808 | ||||
-rw-r--r-- | Utilities/cmcurl/lib/vtls/schannel_verify.c | 10 | ||||
-rw-r--r-- | Utilities/cmcurl/lib/vtls/sectransp.c | 202 | ||||
-rw-r--r-- | Utilities/cmcurl/lib/vtls/vtls.c | 65 | ||||
-rw-r--r-- | Utilities/cmcurl/lib/vtls/vtls.h | 7 | ||||
-rw-r--r-- | Utilities/cmcurl/lib/vtls/wolfssl.c | 73 |
15 files changed, 1170 insertions, 938 deletions
diff --git a/Utilities/cmcurl/lib/vtls/bearssl.c b/Utilities/cmcurl/lib/vtls/bearssl.c index 7f72971..e87649e 100644 --- a/Utilities/cmcurl/lib/vtls/bearssl.c +++ b/Utilities/cmcurl/lib/vtls/bearssl.c @@ -68,6 +68,14 @@ struct cafile_parser { size_t dn_len; }; +#define CAFILE_SOURCE_PATH 1 +#define CAFILE_SOURCE_BLOB 2 +struct cafile_source { + const int type; + const char * const data; + const size_t len; +}; + static void append_dn(void *ctx, const void *buf, size_t len) { struct cafile_parser *ca = ctx; @@ -90,7 +98,8 @@ static void x509_push(void *ctx, const void *buf, size_t len) br_x509_decoder_push(&ca->xc, buf, len); } -static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors, +static CURLcode load_cafile(struct cafile_source *source, + br_x509_trust_anchor **anchors, size_t *anchors_len) { struct cafile_parser ca; @@ -100,13 +109,22 @@ static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors, br_x509_trust_anchor *new_anchors; size_t new_anchors_len; br_x509_pkey *pkey; - FILE *fp; - unsigned char buf[BUFSIZ], *p; + FILE *fp = 0; + unsigned char buf[BUFSIZ]; + const unsigned char *p; const char *name; size_t n, i, pushed; - fp = fopen(path, "rb"); - if(!fp) + DEBUGASSERT(source->type == CAFILE_SOURCE_PATH + || source->type == CAFILE_SOURCE_BLOB); + + if(source->type == CAFILE_SOURCE_PATH) { + fp = fopen(source->data, "rb"); + if(!fp) + return CURLE_SSL_CACERT_BADFILE; + } + + if(source->type == CAFILE_SOURCE_BLOB && source->len > (size_t)INT_MAX) return CURLE_SSL_CACERT_BADFILE; ca.err = CURLE_OK; @@ -115,11 +133,17 @@ static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors, ca.anchors_len = 0; br_pem_decoder_init(&pc); br_pem_decoder_setdest(&pc, x509_push, &ca); - for(;;) { - n = fread(buf, 1, sizeof(buf), fp); - if(n == 0) - break; - p = buf; + do { + if(source->type == CAFILE_SOURCE_PATH) { + n = fread(buf, 1, sizeof(buf), fp); + if(n == 0) + break; + p = buf; + } + else if(source->type == CAFILE_SOURCE_BLOB) { + n = source->len; + p = (unsigned char *) source->data; + } while(n) { pushed = br_pem_decoder_push(&pc, p, n); if(ca.err) @@ -211,12 +235,13 @@ static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors, goto fail; } } - } - if(ferror(fp)) + } while(source->type != CAFILE_SOURCE_BLOB); + if(fp && ferror(fp)) ca.err = CURLE_READ_ERROR; fail: - fclose(fp); + if(fp) + fclose(fp); if(ca.err == CURLE_OK) { *anchors = ca.anchors; *anchors_len = ca.anchors_len; @@ -299,8 +324,11 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data, { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_backend_data *backend = connssl->backend; - const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); - const char * const hostname = SSL_HOST_NAME(); + const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob); + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile)); + const char *hostname = SSL_HOST_NAME(); const bool verifypeer = SSL_CONN_CONFIG(verifypeer); const bool verifyhost = SSL_CONN_CONFIG(verifyhost); CURLcode ret; @@ -340,8 +368,30 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data, return CURLE_SSL_CONNECT_ERROR; } + if(ca_info_blob) { + struct cafile_source source = { + CAFILE_SOURCE_BLOB, + ca_info_blob->data, + ca_info_blob->len, + }; + ret = load_cafile(&source, &backend->anchors, &backend->anchors_len); + if(ret != CURLE_OK) { + if(verifypeer) { + failf(data, "error importing CA certificate blob"); + return ret; + } + /* Only warn if no certificate verification is required. */ + infof(data, "error importing CA certificate blob, continuing anyway"); + } + } + if(ssl_cafile) { - ret = load_cafile(ssl_cafile, &backend->anchors, &backend->anchors_len); + struct cafile_source source = { + CAFILE_SOURCE_PATH, + ssl_cafile, + 0, + }; + ret = load_cafile(&source, &backend->anchors, &backend->anchors_len); if(ret != CURLE_OK) { if(verifypeer) { failf(data, "error setting certificate verify locations." @@ -349,7 +399,7 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data, return ret; } infof(data, "error setting certificate verify locations," - " continuing anyway:\n"); + " continuing anyway:"); } } @@ -373,7 +423,7 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data, if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE, &session, NULL, sockindex)) { br_ssl_engine_set_session_parameters(&backend->ctx.eng, session); - infof(data, "BearSSL: re-using session ID\n"); + infof(data, "BearSSL: re-using session ID"); } Curl_ssl_sessionid_unlock(data); } @@ -392,12 +442,12 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data, #endif ) { backend->protocols[cur++] = ALPN_H2; - infof(data, "ALPN, offering %s\n", ALPN_H2); + infof(data, "ALPN, offering %s", ALPN_H2); } #endif backend->protocols[cur++] = ALPN_HTTP_1_1; - infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + infof(data, "ALPN, offering %s", ALPN_HTTP_1_1); br_ssl_engine_set_protocol_names(&backend->ctx.eng, backend->protocols, cur); @@ -538,7 +588,7 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data, protocol = br_ssl_engine_get_selected_protocol(&backend->ctx.eng); if(protocol) { - infof(data, "ALPN, server accepted to use %s\n", protocol); + infof(data, "ALPN, server accepted to use %s", protocol); #ifdef USE_HTTP2 if(!strcmp(protocol, ALPN_H2)) @@ -548,12 +598,12 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data, if(!strcmp(protocol, ALPN_HTTP_1_1)) conn->negnpn = CURL_HTTP_VERSION_1_1; else - infof(data, "ALPN, unrecognized protocol %s\n", protocol); + infof(data, "ALPN, unrecognized protocol %s", protocol); Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } else - infof(data, "ALPN, server did not agree to a protocol\n"); + infof(data, "ALPN, server did not agree to a protocol"); } if(SSL_SET_OPTION(primary.sessionid)) { @@ -840,30 +890,32 @@ static CURLcode bearssl_sha256sum(const unsigned char *input, } const struct Curl_ssl Curl_ssl_bearssl = { - { CURLSSLBACKEND_BEARSSL, "bearssl" }, - 0, + { CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */ + SSLSUPP_CAINFO_BLOB, sizeof(struct ssl_backend_data), - Curl_none_init, - Curl_none_cleanup, - bearssl_version, - Curl_none_check_cxn, - Curl_none_shutdown, - bearssl_data_pending, - bearssl_random, - Curl_none_cert_status_request, - bearssl_connect, - bearssl_connect_nonblocking, - Curl_ssl_getsock, - bearssl_get_internals, - bearssl_close, - Curl_none_close_all, - bearssl_session_free, - Curl_none_set_engine, - Curl_none_set_engine_default, - Curl_none_engines_list, - Curl_none_false_start, - bearssl_sha256sum + Curl_none_init, /* init */ + Curl_none_cleanup, /* cleanup */ + bearssl_version, /* version */ + Curl_none_check_cxn, /* check_cxn */ + Curl_none_shutdown, /* shutdown */ + bearssl_data_pending, /* data_pending */ + bearssl_random, /* random */ + Curl_none_cert_status_request, /* cert_status_request */ + bearssl_connect, /* connect */ + bearssl_connect_nonblocking, /* connect_nonblocking */ + Curl_ssl_getsock, /* getsock */ + bearssl_get_internals, /* get_internals */ + bearssl_close, /* close_one */ + Curl_none_close_all, /* close_all */ + bearssl_session_free, /* session_free */ + Curl_none_set_engine, /* set_engine */ + Curl_none_set_engine_default, /* set_engine_default */ + Curl_none_engines_list, /* engines_list */ + Curl_none_false_start, /* false_start */ + bearssl_sha256sum, /* sha256sum */ + NULL, /* associate_connection */ + NULL /* disassociate_connection */ }; #endif /* USE_BEARSSL */ diff --git a/Utilities/cmcurl/lib/vtls/gskit.c b/Utilities/cmcurl/lib/vtls/gskit.c index ca95376..e451f6a 100644 --- a/Utilities/cmcurl/lib/vtls/gskit.c +++ b/Utilities/cmcurl/lib/vtls/gskit.c @@ -180,6 +180,7 @@ static bool is_separator(char c) static CURLcode gskit_status(struct Curl_easy *data, int rc, const char *procname, CURLcode defcode) { + char buffer[STRERROR_LEN]; /* Process GSKit status and map it to a CURLcode. */ switch(rc) { case GSK_OK: @@ -208,7 +209,8 @@ static CURLcode gskit_status(struct Curl_easy *data, int rc, case ENOMEM: return CURLE_OUT_OF_MEMORY; default: - failf(data, "%s I/O error: %s", procname, strerror(errno)); + failf(data, "%s I/O error: %s", procname, + Curl_strerror(errno, buffer, sizeof(buffer))); break; } break; @@ -223,13 +225,15 @@ static CURLcode gskit_status(struct Curl_easy *data, int rc, static CURLcode set_enum(struct Curl_easy *data, gsk_handle h, GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok) { + char buffer[STRERROR_LEN]; int rc = gsk_attribute_set_enum(h, id, value); switch(rc) { case GSK_OK: return CURLE_OK; case GSK_ERROR_IO: - failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno)); + failf(data, "gsk_attribute_set_enum() I/O error: %s", + Curl_strerror(errno, buffer, sizeof(buffer))); break; case GSK_ATTRIBUTE_INVALID_ID: if(unsupported_ok) @@ -245,13 +249,15 @@ static CURLcode set_enum(struct Curl_easy *data, gsk_handle h, static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h, GSK_BUF_ID id, const char *buffer, bool unsupported_ok) { + char buffer[STRERROR_LEN]; int rc = gsk_attribute_set_buffer(h, id, buffer, 0); switch(rc) { case GSK_OK: return CURLE_OK; case GSK_ERROR_IO: - failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno)); + failf(data, "gsk_attribute_set_buffer() I/O error: %s", + Curl_strerror(errno, buffer, sizeof(buffer))); break; case GSK_ATTRIBUTE_INVALID_ID: if(unsupported_ok) @@ -267,6 +273,7 @@ static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h, static CURLcode set_numeric(struct Curl_easy *data, gsk_handle h, GSK_NUM_ID id, int value) { + char buffer[STRERROR_LEN]; int rc = gsk_attribute_set_numeric_value(h, id, value); switch(rc) { @@ -274,7 +281,7 @@ static CURLcode set_numeric(struct Curl_easy *data, return CURLE_OK; case GSK_ERROR_IO: failf(data, "gsk_attribute_set_numeric_value() I/O error: %s", - strerror(errno)); + Curl_strerror(errno, buffer, sizeof(buffer))); break; default: failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc)); @@ -287,13 +294,15 @@ static CURLcode set_numeric(struct Curl_easy *data, static CURLcode set_callback(struct Curl_easy *data, gsk_handle h, GSK_CALLBACK_ID id, void *info) { + char buffer[STRERROR_LEN]; int rc = gsk_attribute_set_callback(h, id, info); switch(rc) { case GSK_OK: return CURLE_OK; case GSK_ERROR_IO: - failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno)); + failf(data, "gsk_attribute_set_callback() I/O error: %s", + Curl_strerror(errno, buffer, sizeof(buffer))); break; default: failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc)); @@ -966,7 +975,9 @@ static CURLcode gskit_connect_step2(struct Curl_easy *data, continue; /* Retry. */ } if(errno != ETIME) { - failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno)); + char buffer[STRERROR_LEN]; + failf(data, "QsoWaitForIOCompletion() I/O error: %s", + Curl_strerror(errno, buffer, sizeof(buffer))); cancel_async_handshake(conn, sockindex); close_async_handshake(connssl); return CURLE_SSL_CONNECT_ERROR; @@ -1011,7 +1022,7 @@ static CURLcode gskit_connect_step3(struct Curl_easy *data, CURLE_OK) { int i; - infof(data, "Server certificate:\n"); + infof(data, "Server certificate:"); p = cdev; for(i = 0; i++ < cdec; p++) switch(p->cert_data_id) { @@ -1020,16 +1031,16 @@ static CURLcode gskit_connect_step3(struct Curl_easy *data, certend = cert + cdev->cert_data_l; break; case CERT_DN_PRINTABLE: - infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p); + infof(data, "\t subject: %.*s", p->cert_data_l, p->cert_data_p); break; case CERT_ISSUER_DN_PRINTABLE: - infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p); + infof(data, "\t issuer: %.*s", p->cert_data_l, p->cert_data_p); break; case CERT_VALID_FROM: - infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p); + infof(data, "\t start date: %.*s", p->cert_data_l, p->cert_data_p); break; case CERT_VALID_TO: - infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p); + infof(data, "\t expire date: %.*s", p->cert_data_l, p->cert_data_p); break; } } @@ -1192,6 +1203,7 @@ static int gskit_shutdown(struct Curl_easy *data, int what; int rc; char buf[120]; + int loop = 10; /* don't get stuck */ if(!BACKEND->handle) return 0; @@ -1206,7 +1218,7 @@ static int gskit_shutdown(struct Curl_easy *data, what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); - for(;;) { + while(loop--) { ssize_t nread; if(what < 0) { @@ -1228,7 +1240,8 @@ static int gskit_shutdown(struct Curl_easy *data, nread = read(conn->sock[sockindex], buf, sizeof(buf)); if(nread < 0) { - failf(data, "read: %s", strerror(errno)); + char buffer[STRERROR_LEN]; + failf(data, "read: %s", Curl_strerror(errno, buffer, sizeof(buffer))); rc = -1; } diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c index ecde5c4..1b145d8 100644 --- a/Utilities/cmcurl/lib/vtls/gtls.c +++ b/Utilities/cmcurl/lib/vtls/gtls.c @@ -147,7 +147,7 @@ static void showtime(struct Curl_easy *data, msnprintf(str, sizeof(str), - "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT", + " %s: %s, %02d %s %4d %02d:%02d:%02d GMT", text, Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], tm->tm_mday, @@ -156,7 +156,7 @@ static void showtime(struct Curl_easy *data, tm->tm_hour, tm->tm_min, tm->tm_sec); - infof(data, "%s\n", str); + infof(data, "%s", str); } #endif @@ -266,7 +266,7 @@ static CURLcode handshake(struct Curl_easy *data, if(!strerr) strerr = gnutls_strerror(rc); - infof(data, "gnutls_handshake() warning: %s\n", strerr); + infof(data, "gnutls_handshake() warning: %s", strerr); continue; } else if(rc < 0) { @@ -330,6 +330,9 @@ set_ssl_version_min_max(struct Curl_easy *data, ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; } } + else if(ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT) { + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3; + } switch(ssl_version | ssl_version_max) { case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0: @@ -338,11 +341,11 @@ set_ssl_version_min_max(struct Curl_easy *data, return CURLE_OK; case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.0:+VERS-TLS1.1"; + "+VERS-TLS1.1:+VERS-TLS1.0"; return CURLE_OK; case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2"; + "+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0"; return CURLE_OK; case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" @@ -350,7 +353,7 @@ set_ssl_version_min_max(struct Curl_easy *data, return CURLE_OK; case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.1:+VERS-TLS1.2"; + "+VERS-TLS1.2:+VERS-TLS1.1"; return CURLE_OK; case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" @@ -360,25 +363,16 @@ set_ssl_version_min_max(struct Curl_easy *data, *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.3"; return CURLE_OK; - case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2" - ":+VERS-TLS1.3"; - return CURLE_OK; - case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT: - *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.1:+VERS-TLS1.2" - ":+VERS-TLS1.3"; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_3: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0"; return CURLE_OK; - case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT: + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_3: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.2" - ":+VERS-TLS1.3"; + "+VERS-TLS1.3:+VERS-TLS1.2:+VERS-TLS1.1"; return CURLE_OK; - case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_DEFAULT: + case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_3: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.2" - ":+VERS-TLS1.3"; + "+VERS-TLS1.3:+VERS-TLS1.2"; return CURLE_OK; } @@ -438,7 +432,7 @@ gtls_connect_step1(struct Curl_easy *data, #ifdef HAVE_GNUTLS_SRP if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { - infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username)); + infof(data, "Using TLS-SRP username: %s", SSL_SET_OPTION(username)); rc = gnutls_srp_allocate_client_credentials( &backend->srp_client_cred); @@ -468,7 +462,7 @@ gtls_connect_step1(struct Curl_easy *data, SSL_CONN_CONFIG(CAfile), GNUTLS_X509_FMT_PEM); if(rc < 0) { - infof(data, "error reading ca cert file %s (%s)\n", + infof(data, "error reading ca cert file %s (%s)", SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc)); if(SSL_CONN_CONFIG(verifypeer)) { *certverifyresult = rc; @@ -476,7 +470,7 @@ gtls_connect_step1(struct Curl_easy *data, } } else - infof(data, "found %d certificates in %s\n", rc, + infof(data, "found %d certificates in %s", rc, SSL_CONN_CONFIG(CAfile)); } @@ -486,7 +480,7 @@ gtls_connect_step1(struct Curl_easy *data, SSL_CONN_CONFIG(CApath), GNUTLS_X509_FMT_PEM); if(rc < 0) { - infof(data, "error reading ca cert file %s (%s)\n", + infof(data, "error reading ca cert file %s (%s)", SSL_CONN_CONFIG(CApath), gnutls_strerror(rc)); if(SSL_CONN_CONFIG(verifypeer)) { *certverifyresult = rc; @@ -494,7 +488,7 @@ gtls_connect_step1(struct Curl_easy *data, } } else - infof(data, "found %d certificates in %s\n", + infof(data, "found %d certificates in %s", rc, SSL_CONN_CONFIG(CApath)); } @@ -517,7 +511,7 @@ gtls_connect_step1(struct Curl_easy *data, return CURLE_SSL_CRL_BADFILE; } else - infof(data, "found %d CRL in %s\n", + infof(data, "found %d CRL in %s", rc, SSL_SET_OPTION(CRLfile)); } @@ -550,7 +544,7 @@ gtls_connect_step1(struct Curl_easy *data, (gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname, strlen(hostname)) < 0)) infof(data, "WARNING: failed to configure server name indication (SNI) " - "TLS extension\n"); + "TLS extension"); /* Use default priorities */ rc = gnutls_set_default_priority(session); @@ -603,11 +597,12 @@ gtls_connect_step1(struct Curl_easy *data, free(prioritysrp); if((rc == GNUTLS_E_INVALID_REQUEST) && err) { - infof(data, "This GnuTLS does not support SRP\n"); + infof(data, "This GnuTLS does not support SRP"); } } else { #endif + infof(data, "GnuTLS ciphers: %s", prioritylist); rc = gnutls_priority_set_direct(session, prioritylist, &err); #ifdef HAVE_GNUTLS_SRP } @@ -632,14 +627,14 @@ gtls_connect_step1(struct Curl_easy *data, protocols[cur].data = (unsigned char *)ALPN_H2; protocols[cur].size = ALPN_H2_LENGTH; cur++; - infof(data, "ALPN, offering %.*s\n", ALPN_H2_LENGTH, ALPN_H2); + infof(data, "ALPN, offering %.*s", ALPN_H2_LENGTH, ALPN_H2); } #endif protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1; protocols[cur].size = ALPN_HTTP_1_1_LENGTH; cur++; - infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + infof(data, "ALPN, offering %s", ALPN_HTTP_1_1); gnutls_alpn_set_protocols(session, protocols, cur, 0); } @@ -745,7 +740,7 @@ gtls_connect_step1(struct Curl_easy *data, gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); /* Informational message */ - infof(data, "SSL re-using session ID\n"); + infof(data, "SSL re-using session ID"); } Curl_ssl_sessionid_unlock(data); } @@ -848,7 +843,7 @@ gtls_connect_step3(struct Curl_easy *data, gnutls_cipher_get(session), gnutls_mac_get(session)); - infof(data, "SSL connection using %s / %s\n", + infof(data, "SSL connection using %s / %s", gnutls_protocol_get_name(version), ptr); /* This function will return the peer's raw certificate (chain) as sent by @@ -861,7 +856,7 @@ gtls_connect_step3(struct Curl_easy *data, if(!chainp) { if(SSL_CONN_CONFIG(verifypeer) || SSL_CONN_CONFIG(verifyhost) || - SSL_SET_OPTION(issuercert)) { + SSL_CONN_CONFIG(issuercert)) { #ifdef HAVE_GNUTLS_SRP if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP && SSL_SET_OPTION(username) != NULL @@ -879,7 +874,7 @@ gtls_connect_step3(struct Curl_easy *data, } #endif } - infof(data, "\t common name: WARNING couldn't obtain\n"); + infof(data, " common name: WARNING couldn't obtain"); } if(data->set.ssl.certinfo && chainp) { @@ -926,13 +921,13 @@ gtls_connect_step3(struct Curl_easy *data, return CURLE_PEER_FAILED_VERIFICATION; } else - infof(data, "\t server certificate verification FAILED\n"); + infof(data, " server certificate verification FAILED"); } else - infof(data, "\t server certificate verification OK\n"); + infof(data, " server certificate verification OK"); } else - infof(data, "\t server certificate verification SKIPPED\n"); + infof(data, " server certificate verification SKIPPED"); if(SSL_CONN_CONFIG(verifystatus)) { if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) { @@ -944,7 +939,7 @@ gtls_connect_step3(struct Curl_easy *data, rc = gnutls_ocsp_status_request_get(session, &status_request); - infof(data, "\t server certificate status verification FAILED\n"); + infof(data, " server certificate status verification FAILED"); if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { failf(data, "No OCSP response received"); @@ -1032,10 +1027,10 @@ gtls_connect_step3(struct Curl_easy *data, return CURLE_SSL_INVALIDCERTSTATUS; } else - infof(data, "\t server certificate status verification OK\n"); + infof(data, " server certificate status verification OK"); } else - infof(data, "\t server certificate status verification SKIPPED\n"); + infof(data, " server certificate status verification SKIPPED"); /* initialize an X.509 certificate structure. */ gnutls_x509_crt_init(&x509_cert); @@ -1045,21 +1040,21 @@ gtls_connect_step3(struct Curl_easy *data, gnutls_x509_crt_t format */ gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); - if(SSL_SET_OPTION(issuercert)) { + if(SSL_CONN_CONFIG(issuercert)) { gnutls_x509_crt_init(&x509_issuer); - issuerp = load_file(SSL_SET_OPTION(issuercert)); + issuerp = load_file(SSL_CONN_CONFIG(issuercert)); gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer); gnutls_x509_crt_deinit(x509_issuer); unload_file(issuerp); if(rc <= 0) { failf(data, "server certificate issuer check failed (IssuerCert: %s)", - SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); + SSL_CONN_CONFIG(issuercert)?SSL_CONN_CONFIG(issuercert):"none"); gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_ISSUER_ERROR; } - infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n", - SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); + infof(data, " server certificate issuer check OK (Issuer Cert: %s)", + SSL_CONN_CONFIG(issuercert)?SSL_CONN_CONFIG(issuercert):"none"); } size = sizeof(certname); @@ -1069,7 +1064,7 @@ gtls_connect_step3(struct Curl_easy *data, certname, &size); if(rc) { - infof(data, "error fetching CN from cert:%s\n", + infof(data, "error fetching CN from cert:%s", gnutls_strerror(rc)); } @@ -1129,11 +1124,11 @@ gtls_connect_step3(struct Curl_easy *data, return CURLE_PEER_FAILED_VERIFICATION; } else - infof(data, "\t common name: %s (does not match '%s')\n", + infof(data, " common name: %s (does not match '%s')", certname, SSL_HOST_DISPNAME()); } else - infof(data, "\t common name: %s (matched)\n", certname); + infof(data, " common name: %s (matched)", certname); /* Check for time-based validity */ certclock = gnutls_x509_crt_get_expiration_time(x509_cert); @@ -1146,7 +1141,7 @@ gtls_connect_step3(struct Curl_easy *data, return CURLE_SSL_CONNECT_ERROR; } else - infof(data, "\t server certificate expiration date verify FAILED\n"); + infof(data, " server certificate expiration date verify FAILED"); } else { if(certclock < time(NULL)) { @@ -1157,10 +1152,10 @@ gtls_connect_step3(struct Curl_easy *data, return CURLE_PEER_FAILED_VERIFICATION; } else - infof(data, "\t server certificate expiration date FAILED\n"); + infof(data, " server certificate expiration date FAILED"); } else - infof(data, "\t server certificate expiration date OK\n"); + infof(data, " server certificate expiration date OK"); } certclock = gnutls_x509_crt_get_activation_time(x509_cert); @@ -1173,7 +1168,7 @@ gtls_connect_step3(struct Curl_easy *data, return CURLE_SSL_CONNECT_ERROR; } else - infof(data, "\t server certificate activation date verify FAILED\n"); + infof(data, " server certificate activation date verify FAILED"); } else { if(certclock > time(NULL)) { @@ -1184,10 +1179,10 @@ gtls_connect_step3(struct Curl_easy *data, return CURLE_PEER_FAILED_VERIFICATION; } else - infof(data, "\t server certificate activation date FAILED\n"); + infof(data, " server certificate activation date FAILED"); } else - infof(data, "\t server certificate activation date OK\n"); + infof(data, " server certificate activation date OK"); } ptr = SSL_PINNED_PUB_KEY(); @@ -1213,19 +1208,19 @@ gtls_connect_step3(struct Curl_easy *data, #ifndef CURL_DISABLE_VERBOSE_STRINGS /* public key algorithm's parameters */ algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits); - infof(data, "\t certificate public key: %s\n", + infof(data, " certificate public key: %s", gnutls_pk_algorithm_get_name(algo)); /* version of the X.509 certificate. */ - infof(data, "\t certificate version: #%d\n", + infof(data, " certificate version: #%d", gnutls_x509_crt_get_version(x509_cert)); rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields); if(rc) - infof(data, "Failed to get certificate name\n"); + infof(data, "Failed to get certificate name"); else { - infof(data, "\t subject: %s\n", certfields.data); + infof(data, " subject: %s", certfields.data); certclock = gnutls_x509_crt_get_activation_time(x509_cert); showtime(data, "start date", certclock); @@ -1238,9 +1233,9 @@ gtls_connect_step3(struct Curl_easy *data, rc = gnutls_x509_crt_get_issuer_dn2(x509_cert, &certfields); if(rc) - infof(data, "Failed to get certificate issuer\n"); + infof(data, "Failed to get certificate issuer"); else { - infof(data, "\t issuer: %s\n", certfields.data); + infof(data, " issuer: %s", certfields.data); gnutls_free(certfields.data); } @@ -1251,7 +1246,7 @@ gtls_connect_step3(struct Curl_easy *data, if(conn->bits.tls_enable_alpn) { rc = gnutls_alpn_get_selected_protocol(session, &proto); if(rc == 0) { - infof(data, "ALPN, server accepted to use %.*s\n", proto.size, + infof(data, "ALPN, server accepted to use %.*s", proto.size, proto.data); #ifdef USE_HTTP2 @@ -1268,7 +1263,7 @@ gtls_connect_step3(struct Curl_easy *data, } } else - infof(data, "ALPN, server did not agree to a protocol\n"); + infof(data, "ALPN, server did not agree to a protocol"); Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); @@ -1438,6 +1433,10 @@ static void close_one(struct ssl_connect_data *connssl) { struct ssl_backend_data *backend = connssl->backend; if(backend->session) { + char buf[32]; + /* Maybe the server has already sent a close notify alert. + Read it to avoid an RST on the TCP connection. */ + (void)gnutls_record_recv(backend->session, buf, sizeof(buf)); gnutls_bye(backend->session, GNUTLS_SHUT_WR); gnutls_deinit(backend->session); backend->session = NULL; @@ -1506,7 +1505,7 @@ static int gtls_shutdown(struct Curl_easy *data, struct connectdata *conn, break; case GNUTLS_E_AGAIN: case GNUTLS_E_INTERRUPTED: - infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n"); + infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED"); break; default: retval = -1; @@ -1620,7 +1619,7 @@ static bool gtls_cert_status_request(void) } static void *gtls_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) + CURLINFO info UNUSED_PARAM) { struct ssl_backend_data *backend = connssl->backend; (void)info; diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c index 3a0be0f..780d13e 100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls.c +++ b/Utilities/cmcurl/lib/vtls/mbedtls.c @@ -41,7 +41,9 @@ #include <mbedtls/net.h> #endif #include <mbedtls/ssl.h> +#if MBEDTLS_VERSION_NUMBER < 0x03000000 #include <mbedtls/certs.h> +#endif #include <mbedtls/x509.h> #include <mbedtls/error.h> @@ -89,6 +91,10 @@ struct ssl_backend_data { #define THREADING_SUPPORT #endif +#ifndef MBEDTLS_ERROR_C +#define mbedtls_strerror(a,b,c) b[0] = 0 +#endif + #if defined(THREADING_SUPPORT) static mbedtls_entropy_context ts_entropy; @@ -179,6 +185,17 @@ static Curl_send mbed_send; static CURLcode mbedtls_version_from_curl(int *mbedver, long version) { +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + switch(version) { + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: + case CURL_SSLVERSION_TLSv1_2: + *mbedver = MBEDTLS_SSL_MINOR_VERSION_3; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3: + break; + } +#else switch(version) { case CURL_SSLVERSION_TLSv1_0: *mbedver = MBEDTLS_SSL_MINOR_VERSION_1; @@ -192,6 +209,8 @@ static CURLcode mbedtls_version_from_curl(int *mbedver, long version) case CURL_SSLVERSION_TLSv1_3: break; } +#endif + return CURLE_SSL_CONNECT_ERROR; } @@ -201,8 +220,13 @@ set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn, { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_backend_data *backend = connssl->backend; +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3; + int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_3; +#else int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1; int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1; +#endif long ssl_version = SSL_CONN_CONFIG(version); long ssl_version_max = SSL_CONN_CONFIG(version_max); CURLcode result = CURLE_OK; @@ -250,12 +274,14 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, const bool verifypeer = SSL_CONN_CONFIG(verifypeer); const char * const ssl_capath = SSL_CONN_CONFIG(CApath); char * const ssl_cert = SSL_SET_OPTION(primary.clientcert); + const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob); const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); const char * const hostname = SSL_HOST_NAME(); +#ifndef CURL_DISABLE_VERBOSE_STRINGS const long int port = SSL_HOST_PORT(); +#endif int ret = -1; char errorbuf[128]; - errorbuf[0] = 0; if((SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) || (SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3)) { @@ -270,9 +296,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, entropy_func_mutex, &ts_entropy, NULL, 0); if(ret) { -#ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s", -ret, errorbuf); } @@ -283,9 +307,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, mbedtls_entropy_func, &backend->entropy, NULL, 0); if(ret) { -#ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s", -ret, errorbuf); } @@ -298,9 +320,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, ret = mbedtls_x509_crt_parse_file(&backend->cacert, ssl_cafile); if(ret<0) { -#ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s", ssl_cafile, -ret, errorbuf); @@ -313,9 +333,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, ret = mbedtls_x509_crt_parse_path(&backend->cacert, ssl_capath); if(ret<0) { -#ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s", ssl_capath, -ret, errorbuf); @@ -331,9 +349,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, ret = mbedtls_x509_crt_parse_file(&backend->clicert, ssl_cert); if(ret) { -#ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s", ssl_cert, -ret, errorbuf); @@ -341,27 +357,72 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, } } - /* Load the client private key */ - mbedtls_pk_init(&backend->pk); - - if(SSL_SET_OPTION(key)) { - ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key), - SSL_SET_OPTION(key_passwd)); - if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) || - mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY))) - ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; + if(ssl_cert_blob) { + const unsigned char *blob_data = + (const unsigned char *)ssl_cert_blob->data; + ret = mbedtls_x509_crt_parse(&backend->clicert, blob_data, + ssl_cert_blob->len); if(ret) { -#ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s", SSL_SET_OPTION(key), -ret, errorbuf); - return CURLE_SSL_CERTPROBLEM; } } + /* Load the client private key */ + mbedtls_pk_init(&backend->pk); + + if(SSL_SET_OPTION(key) || SSL_SET_OPTION(key_blob)) { + if(SSL_SET_OPTION(key)) { +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key), + SSL_SET_OPTION(key_passwd), + mbedtls_ctr_drbg_random, + &backend->ctr_drbg); +#else + ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key), + SSL_SET_OPTION(key_passwd)); +#endif + + if(ret) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s", + SSL_SET_OPTION(key), -ret, errorbuf); + return CURLE_SSL_CERTPROBLEM; + } + } + else { + const struct curl_blob *ssl_key_blob = SSL_SET_OPTION(key_blob); + const unsigned char *key_data = + (const unsigned char *)ssl_key_blob->data; + const char *passwd = SSL_SET_OPTION(key_passwd); +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len, + (const unsigned char *)passwd, + passwd ? strlen(passwd) : 0, + mbedtls_ctr_drbg_random, + &backend->ctr_drbg); +#else + ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len, + (const unsigned char *)passwd, + passwd ? strlen(passwd) : 0); +#endif + + if(ret) { + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Error parsing private key - mbedTLS: (-0x%04X) %s", + -ret, errorbuf); + return CURLE_SSL_CERTPROBLEM; + } + } + + if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) || + mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY))) + ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; + } + /* Load the CRL */ mbedtls_x509_crl_init(&backend->crl); @@ -369,9 +430,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, ret = mbedtls_x509_crl_parse_file(&backend->crl, ssl_crlfile); if(ret) { -#ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s", ssl_crlfile, -ret, errorbuf); @@ -379,7 +438,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, } } - infof(data, "mbedTLS: Connecting to %s:%ld\n", hostname, port); + infof(data, "mbedTLS: Connecting to %s:%ld", hostname, port); mbedtls_ssl_config_init(&backend->config); @@ -404,10 +463,12 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: +#if MBEDTLS_VERSION_NUMBER < 0x03000000 mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1); - infof(data, "mbedTLS: Set min SSL version to TLS 1.0\n"); + infof(data, "mbedTLS: Set min SSL version to TLS 1.0"); break; +#endif case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_2: @@ -459,7 +520,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret); return CURLE_SSL_CONNECT_ERROR; } - infof(data, "mbedTLS re-using session\n"); + infof(data, "mbedTLS re-using session"); } Curl_ssl_sessionid_unlock(data); } @@ -468,7 +529,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, &backend->cacert, &backend->crl); - if(SSL_SET_OPTION(key)) { + if(SSL_SET_OPTION(key) || SSL_SET_OPTION(key_blob)) { mbedtls_ssl_conf_own_cert(&backend->config, &backend->clicert, &backend->pk); } @@ -497,7 +558,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } for(p = &backend->protocols[0]; *p; ++p) - infof(data, "ALPN, offering %s\n", *p); + infof(data, "ALPN, offering %s", *p); } #endif @@ -553,18 +614,14 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, } else if(ret) { char errorbuf[128]; - errorbuf[0] = 0; -#ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s", -ret, errorbuf); return CURLE_SSL_CONNECT_ERROR; } - infof(data, "mbedTLS: Handshake complete, cipher is %s\n", - mbedtls_ssl_get_ciphersuite(&backend->ssl) - ); + infof(data, "mbedTLS: Handshake complete, cipher is %s", + mbedtls_ssl_get_ciphersuite(&backend->ssl)); ret = mbedtls_ssl_get_verify_result(&backend->ssl); @@ -601,9 +658,9 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, return CURLE_OUT_OF_MEMORY; if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0) - infof(data, "Dumping cert info:\n%s\n", buffer); + infof(data, "Dumping cert info: %s", buffer); else - infof(data, "Unable to dump certificate information.\n"); + infof(data, "Unable to dump certificate information"); free(buffer); } @@ -611,10 +668,15 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, if(pinnedpubkey) { int size; CURLcode result; - mbedtls_x509_crt *p; - unsigned char pubkey[PUB_DER_MAX_BYTES]; + mbedtls_x509_crt *p = NULL; + unsigned char *pubkey = NULL; +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) || + !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) { +#else if(!peercert || !peercert->raw.p || !peercert->raw.len) { +#endif failf(data, "Failed due to missing peer certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } @@ -624,39 +686,54 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, if(!p) return CURLE_OUT_OF_MEMORY; + pubkey = malloc(PUB_DER_MAX_BYTES); + + if(!pubkey) { + result = CURLE_OUT_OF_MEMORY; + goto pinnedpubkey_error; + } + mbedtls_x509_crt_init(p); /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der needs a non-const key, for now. https://github.com/ARMmbed/mbedtls/issues/396 */ +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + if(mbedtls_x509_crt_parse_der(p, + peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p), + peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))) { +#else if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { +#endif failf(data, "Failed copying peer certificate"); - mbedtls_x509_crt_free(p); - free(p); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + goto pinnedpubkey_error; } +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + size = mbedtls_pk_write_pubkey_der(&p->MBEDTLS_PRIVATE(pk), pubkey, + PUB_DER_MAX_BYTES); +#else size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); +#endif if(size <= 0) { failf(data, "Failed copying public key from peer certificate"); - mbedtls_x509_crt_free(p); - free(p); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + goto pinnedpubkey_error; } /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */ result = Curl_pin_peer_pubkey(data, pinnedpubkey, &pubkey[PUB_DER_MAX_BYTES - size], size); + pinnedpubkey_error: + mbedtls_x509_crt_free(p); + free(p); + free(pubkey); if(result) { - mbedtls_x509_crt_free(p); - free(p); return result; } - - mbedtls_x509_crt_free(p); - free(p); } #ifdef HAS_ALPN @@ -664,7 +741,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, const char *next_protocol = mbedtls_ssl_get_alpn_protocol(&backend->ssl); if(next_protocol) { - infof(data, "ALPN, server accepted to use %s\n", next_protocol); + infof(data, "ALPN, server accepted to use %s", next_protocol); #ifdef USE_NGHTTP2 if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID, NGHTTP2_PROTO_VERSION_ID_LEN) && @@ -679,7 +756,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, } } else { - infof(data, "ALPN, server did not agree to a protocol\n"); + infof(data, "ALPN, server did not agree to a protocol"); } Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); @@ -687,7 +764,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, #endif connssl->connecting_state = ssl_connect_3; - infof(data, "SSL connected\n"); + infof(data, "SSL connected"); return CURLE_OK; } @@ -775,8 +852,13 @@ static void mbedtls_close(struct Curl_easy *data, { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_backend_data *backend = connssl->backend; - + char buf[32]; (void) data; + + /* Maybe the server has already sent a close notify alert. + Read it to avoid an RST on the TCP connection. */ + (void)mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, sizeof(buf)); + mbedtls_pk_free(&backend->pk); mbedtls_x509_crt_free(&backend->clicert); mbedtls_x509_crt_free(&backend->cacert); @@ -844,15 +926,12 @@ static CURLcode mbedtls_random(struct Curl_easy *data, mbedtls_ctr_drbg_context ctr_drbg; mbedtls_entropy_init(&ctr_entropy); mbedtls_ctr_drbg_init(&ctr_drbg); - errorbuf[0] = 0; ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &ctr_entropy, NULL, 0); if(ret) { -#ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ failf(data, "Failed - mbedTLS: ctr_drbg_seed returned (-0x%04X) %s", -ret, errorbuf); } @@ -860,9 +939,7 @@ static CURLcode mbedtls_random(struct Curl_easy *data, ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length); if(ret) { -#ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* MBEDTLS_ERROR_C */ failf(data, "mbedTLS: ctr_drbg_init returned (-0x%04X) %s", -ret, errorbuf); } @@ -1046,12 +1123,17 @@ static CURLcode mbedtls_sha256sum(const unsigned char *input, unsigned char *sha256sum, size_t sha256len UNUSED_PARAM) { + /* TODO: explain this for different mbedtls 2.x vs 3 version */ (void)sha256len; #if MBEDTLS_VERSION_NUMBER < 0x02070000 mbedtls_sha256(input, inputlen, sha256sum, 0); #else /* returns 0 on success, otherwise failure */ +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + if(mbedtls_sha256(input, inputlen, sha256sum, 0) != 0) +#else if(mbedtls_sha256_ret(input, inputlen, sha256sum, 0) != 0) +#endif return CURLE_BAD_FUNCTION_ARGUMENT; #endif return CURLE_OK; diff --git a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c index 473f517..751755c 100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c +++ b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2013 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2013 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com> * * This software is licensed as described in the file COPYING, which @@ -55,10 +55,8 @@ int Curl_mbedtlsthreadlock_thread_setup(void) return 0; /* error, no number of threads defined */ for(i = 0; i < NUMT; i++) { - int ret; #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) - ret = pthread_mutex_init(&mutex_buf[i], NULL); - if(ret) + if(pthread_mutex_init(&mutex_buf[i], NULL)) return 0; /* pthread_mutex_init failed */ #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) mutex_buf[i] = CreateMutex(0, FALSE, 0); @@ -78,14 +76,11 @@ int Curl_mbedtlsthreadlock_thread_cleanup(void) return 0; /* error, no threads locks defined */ for(i = 0; i < NUMT; i++) { - int ret; #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) - ret = pthread_mutex_destroy(&mutex_buf[i]); - if(ret) + if(pthread_mutex_destroy(&mutex_buf[i])) return 0; /* pthread_mutex_destroy failed */ #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) - ret = CloseHandle(mutex_buf[i]); - if(!ret) + if(!CloseHandle(mutex_buf[i])) return 0; /* CloseHandle failed */ #endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ } @@ -98,17 +93,14 @@ int Curl_mbedtlsthreadlock_thread_cleanup(void) int Curl_mbedtlsthreadlock_lock_function(int n) { if(n < NUMT) { - int ret; #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) - ret = pthread_mutex_lock(&mutex_buf[n]); - if(ret) { + if(pthread_mutex_lock(&mutex_buf[n])) { DEBUGF(fprintf(stderr, "Error: mbedtlsthreadlock_lock_function failed\n")); return 0; /* pthread_mutex_lock failed */ } #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) - ret = (WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED?1:0); - if(ret) { + if(WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED) { DEBUGF(fprintf(stderr, "Error: mbedtlsthreadlock_lock_function failed\n")); return 0; /* pthread_mutex_lock failed */ @@ -121,17 +113,14 @@ int Curl_mbedtlsthreadlock_lock_function(int n) int Curl_mbedtlsthreadlock_unlock_function(int n) { if(n < NUMT) { - int ret; #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) - ret = pthread_mutex_unlock(&mutex_buf[n]); - if(ret) { + if(pthread_mutex_unlock(&mutex_buf[n])) { DEBUGF(fprintf(stderr, "Error: mbedtlsthreadlock_unlock_function failed\n")); return 0; /* pthread_mutex_unlock failed */ } #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) - ret = ReleaseMutex(mutex_buf[n]); - if(!ret) { + if(!ReleaseMutex(mutex_buf[n])) { DEBUGF(fprintf(stderr, "Error: mbedtlsthreadlock_unlock_function failed\n")); return 0; /* pthread_mutex_lock failed */ diff --git a/Utilities/cmcurl/lib/vtls/mesalink.c b/Utilities/cmcurl/lib/vtls/mesalink.c index bf8600d..3db9184 100644 --- a/Utilities/cmcurl/lib/vtls/mesalink.c +++ b/Utilities/cmcurl/lib/vtls/mesalink.c @@ -167,14 +167,14 @@ mesalink_connect_step1(struct Curl_easy *data, } infof(data, "error setting certificate verify locations," - " continuing anyway:\n"); + " continuing anyway:"); } else { - infof(data, "successfully set certificate verify locations:\n"); + infof(data, "successfully set certificate verify locations:"); } - infof(data, " CAfile: %s\n", + infof(data, " CAfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): "none"); - infof(data, " CApath: %s\n", + infof(data, " CApath: %s", SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath): "none"); } @@ -196,7 +196,7 @@ mesalink_connect_step1(struct Curl_easy *data, return CURLE_SSL_CONNECT_ERROR; } infof(data, - "client cert: %s\n", + "client cert: %s", SSL_CONN_CONFIG(clientcert)? SSL_CONN_CONFIG(clientcert): "none"); } @@ -209,7 +209,7 @@ mesalink_connect_step1(struct Curl_easy *data, return CURLE_SSL_CIPHER; } #endif - infof(data, "Cipher selection: %s\n", ciphers); + infof(data, "Cipher selection: %s", ciphers); } if(BACKEND->handle) @@ -273,7 +273,7 @@ mesalink_connect_step1(struct Curl_easy *data, return CURLE_SSL_CONNECT_ERROR; } /* Informational message */ - infof(data, "SSL re-using session ID\n"); + infof(data, "SSL re-using session ID"); } Curl_ssl_sessionid_unlock(data); } @@ -326,7 +326,7 @@ mesalink_connect_step2(struct Curl_easy *data, connssl->connecting_state = ssl_connect_3; infof(data, - "SSL connection using %s / %s\n", + "SSL connection using %s / %s", SSL_get_version(BACKEND->handle), SSL_get_cipher_name(BACKEND->handle)); @@ -356,7 +356,7 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex) sockindex)); if(incache) { if(old_ssl_sessionid != our_ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); + infof(data, "old SSL session ID is stale, removing"); Curl_ssl_delsessionid(data, old_ssl_sessionid); incache = FALSE; } diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c index 1582b1e..cf65789 100644 --- a/Utilities/cmcurl/lib/vtls/nss.c +++ b/Utilities/cmcurl/lib/vtls/nss.c @@ -433,7 +433,7 @@ static char *dup_nickname(struct Curl_easy *data, const char *str) n = strchr(str, '/'); if(!n) { infof(data, "warning: certificate file name \"%s\" handled as nickname; " - "please use \"./%s\" to force file name\n", str, str); + "please use \"./%s\" to force file name", str, str); return strdup(str); } @@ -824,7 +824,7 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig, #endif if(!SSL_CONN_CONFIG(verifypeer)) { - infof(data, "skipping SSL peer certificate verification\n"); + infof(data, "skipping SSL peer certificate verification"); return SECSuccess; } @@ -857,15 +857,15 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg) #endif case SSL_NEXT_PROTO_NO_SUPPORT: case SSL_NEXT_PROTO_NO_OVERLAP: - infof(data, "ALPN/NPN, server did not agree to a protocol\n"); + infof(data, "ALPN/NPN, server did not agree to a protocol"); return; #ifdef SSL_ENABLE_ALPN case SSL_NEXT_PROTO_SELECTED: - infof(data, "ALPN, server accepted to use %.*s\n", buflen, buf); + infof(data, "ALPN, server accepted to use %.*s", buflen, buf); break; #endif case SSL_NEXT_PROTO_NEGOTIATED: - infof(data, "NPN, server accepted to use %.*s\n", buflen, buf); + infof(data, "NPN, server accepted to use %.*s", buflen, buf); break; } @@ -937,7 +937,7 @@ static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data, *canFalseStart = PR_TRUE; - infof(data, "Trying TLS False Start\n"); + infof(data, "Trying TLS False Start"); end: return SECSuccess; @@ -955,17 +955,17 @@ static void display_cert_info(struct Curl_easy *data, subject = CERT_NameToAscii(&cert->subject); issuer = CERT_NameToAscii(&cert->issuer); common_name = CERT_GetCommonName(&cert->subject); - infof(data, "\tsubject: %s\n", subject); + infof(data, "subject: %s\n", subject); CERT_GetCertTimes(cert, ¬Before, ¬After); PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime); PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime); - infof(data, "\tstart date: %s\n", timeString); + infof(data, " start date: %s", timeString); PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime); PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime); - infof(data, "\texpire date: %s\n", timeString); - infof(data, "\tcommon name: %s\n", common_name); - infof(data, "\tissuer: %s\n", issuer); + infof(data, " expire date: %s", timeString); + infof(data, " common name: %s", common_name); + infof(data, " issuer: %s", issuer); PR_Free(subject); PR_Free(issuer); @@ -987,13 +987,13 @@ static CURLcode display_conn_info(struct Curl_easy *data, PRFileDesc *sock) channel.cipherSuite) { if(SSL_GetCipherSuiteInfo(channel.cipherSuite, &suite, sizeof(suite)) == SECSuccess) { - infof(data, "SSL connection using %s\n", suite.cipherSuiteName); + infof(data, "SSL connection using %s", suite.cipherSuiteName); } } cert = SSL_PeerCertificate(sock); if(cert) { - infof(data, "Server certificate:\n"); + infof(data, "Server certificate:"); if(!data->set.ssl.certinfo) { display_cert_info(data, cert); @@ -1058,7 +1058,7 @@ static SECStatus BadCertHandler(void *arg, PRFileDesc *sock) /* print only info about the cert, the error is printed off the callback */ cert = SSL_PeerCertificate(sock); if(cert) { - infof(data, "Server certificate:\n"); + infof(data, "Server certificate:"); display_cert_info(data, cert); CERT_DestroyCertificate(cert); } @@ -1132,7 +1132,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, /* report the resulting status */ switch(result) { case CURLE_OK: - infof(data, "pinned public key verified successfully!\n"); + infof(data, "pinned public key verified successfully!"); break; case CURLE_SSL_PINNEDPUBKEYNOTMATCH: failf(data, "failed to verify pinned public key"); @@ -1196,7 +1196,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, return SECFailure; } - infof(data, "NSS: client certificate from file\n"); + infof(data, "NSS: client certificate from file"); display_cert_info(data, cert); *pRetCert = cert; @@ -1234,7 +1234,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, return SECFailure; } - infof(data, "NSS: using client certificate: %s\n", nickname); + infof(data, "NSS: using client certificate: %s", nickname); display_cert_info(data, *pRetCert); return SECSuccess; } @@ -1355,7 +1355,7 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir) if(!certpath) return CURLE_OUT_OF_MEMORY; - infof(data, "Initializing NSS with certpath: %s\n", certpath); + infof(data, "Initializing NSS with certpath: %s", certpath); nss_context = NSS_InitContext(certpath, "", "", "", &initparams, NSS_INIT_READONLY | NSS_INIT_PK11RELOAD); free(certpath); @@ -1365,10 +1365,10 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir) err = PR_GetError(); err_name = nss_error_to_name(err); - infof(data, "Unable to initialize NSS database: %d (%s)\n", err, err_name); + infof(data, "Unable to initialize NSS database: %d (%s)", err, err_name); } - infof(data, "Initializing NSS with certpath: none\n"); + infof(data, "Initializing NSS with certpath: none"); nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD); @@ -1546,6 +1546,14 @@ static void close_one(struct ssl_connect_data *connssl) const bool client_cert = (backend->client_nickname != NULL) || (backend->obj_clicert != NULL); + if(backend->handle) { + char buf[32]; + /* Maybe the server has already sent a close notify alert. + Read it to avoid an RST on the TCP connection. */ + (void)PR_Recv(backend->handle, buf, (int)sizeof(buf), 0, + PR_INTERVAL_NO_WAIT); + } + free(backend->client_nickname); backend->client_nickname = NULL; @@ -1650,8 +1658,8 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data, if(capath && !capath[0]) capath = NULL; - infof(data, " CAfile: %s\n", cafile ? cafile : "none"); - infof(data, " CApath: %s\n", capath ? capath : "none"); + infof(data, " CAfile: %s", cafile ? cafile : "none"); + infof(data, " CApath: %s", capath ? capath : "none"); /* load libnssckbi.so if no other trust roots were specified */ use_trust_module = !cafile && !capath; @@ -1660,7 +1668,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data, if(use_trust_module && !trust_module) { /* libnssckbi.so needed but not yet loaded --> load it! */ result = nss_load_module(&trust_module, trust_library, "trust"); - infof(data, "%s %s\n", (result) ? "failed to load" : "loaded", + infof(data, "%s %s", (result) ? "failed to load" : "loaded", trust_library); if(result == CURLE_FAILED_INIT) /* If libnssckbi.so is not available (or fails to load), one can still @@ -1669,7 +1677,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data, } else if(!use_trust_module && trust_module) { /* libnssckbi.so not needed but already loaded --> unload it! */ - infof(data, "unloading %s\n", trust_library); + infof(data, "unloading %s", trust_library); nss_unload_module(&trust_module); } PR_Unlock(nss_trustload_lock); @@ -1702,7 +1710,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data, if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE)) /* This is purposefully tolerant of errors so non-PEM files can * be in the same directory */ - infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath); + infof(data, "failed to load '%s' from CURLOPT_CAPATH", fullpath); free(fullpath); } @@ -1710,7 +1718,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data, PR_CloseDir(dir); } else - infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath); + infof(data, "warning: CURLOPT_CAPATH not a directory (%s)", capath); } return CURLE_OK; @@ -1813,7 +1821,7 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, curlerr = CURLE_SSL_CERTPROBLEM; /* print the error number and error string */ - infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err)); + infof(data, "NSS error %d (%s)", err, nss_error_to_name(err)); /* print a human-readable message describing the error if available */ nss_print_error_message(data, err); @@ -1887,7 +1895,7 @@ static CURLcode nss_setup_connect(struct Curl_easy *data, PR_Unlock(nss_initlock); if(result == CURLE_FAILED_INIT) infof(data, "WARNING: failed to load NSS PEM library %s. Using " - "OpenSSL PEM certificates will not work.\n", pem_library); + "OpenSSL PEM certificates will not work.", pem_library); else if(result) goto error; @@ -1922,8 +1930,8 @@ static CURLcode nss_setup_connect(struct Curl_easy *data, sslver_req_str = nss_sslver_to_name(sslver.max); sslver_supp_str = nss_sslver_to_name(sslver_supported.max); if(sslver_req_str && sslver_supp_str) - infof(data, "Falling back from %s to max supported SSL version (%s)\n", - sslver_req_str, sslver_supp_str); + infof(data, "Falling back from %s to max supported SSL version (%s)", + sslver_req_str, sslver_supp_str); free(sslver_req_str); free(sslver_supp_str); sslver.max = sslver_supported.max; @@ -1936,11 +1944,11 @@ static CURLcode nss_setup_connect(struct Curl_easy *data, /* unless the user explicitly asks to allow the protocol vulnerability, we use the work-around */ if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess) - infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d\n", + infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d", ssl_cbc_random_iv); #else if(ssl_cbc_random_iv) - infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n"); + infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in"); #endif if(SSL_CONN_CONFIG(cipher_list)) { @@ -1951,7 +1959,7 @@ static CURLcode nss_setup_connect(struct Curl_easy *data, } if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost)) - infof(data, "warning: ignoring value of ssl.verifyhost\n"); + infof(data, "warning: ignoring value of ssl.verifyhost"); /* bypass the default SSL_AuthCertificate() hook in case we do not want to * verify peer */ @@ -1971,7 +1979,7 @@ static CURLcode nss_setup_connect(struct Curl_easy *data, const CURLcode rv = nss_load_ca_certificates(data, conn, sockindex); if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer)) /* not a fatal error because we are not going to verify the peer */ - infof(data, "warning: CA certificates failed to load\n"); + infof(data, "warning: CA certificates failed to load"); else if(rv) { result = rv; goto error; @@ -1984,7 +1992,7 @@ static CURLcode nss_setup_connect(struct Curl_easy *data, result = rv; goto error; } - infof(data, " CRLfile: %s\n", SSL_SET_OPTION(CRLfile)); + infof(data, " CRLfile: %s", SSL_SET_OPTION(CRLfile)); } if(SSL_SET_OPTION(primary.clientcert)) { @@ -2179,9 +2187,9 @@ static CURLcode nss_do_connect(struct Curl_easy *data, if(result) goto error; - if(SSL_SET_OPTION(issuercert)) { + if(SSL_CONN_CONFIG(issuercert)) { SECStatus ret = SECFailure; - char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert)); + char *nickname = dup_nickname(data, SSL_CONN_CONFIG(issuercert)); if(nickname) { /* we support only nicknames in case of issuercert for now */ ret = check_issuer_cert(backend->handle, nickname); @@ -2189,12 +2197,12 @@ static CURLcode nss_do_connect(struct Curl_easy *data, } if(SECFailure == ret) { - infof(data, "SSL certificate issuer check failed\n"); + infof(data, "SSL certificate issuer check failed"); result = CURLE_SSL_ISSUER_ERROR; goto error; } else { - infof(data, "SSL certificate issuer check ok\n"); + infof(data, "SSL certificate issuer check ok"); } } @@ -2306,7 +2314,7 @@ static ssize_t nss_send(struct Curl_easy *data, /* transfer */ else { /* print the error number and error string */ const char *err_name = nss_error_to_name(err); - infof(data, "SSL write: error %d (%s)\n", err, err_name); + infof(data, "SSL write: error %d (%s)", err, err_name); /* print a human-readable message describing the error if available */ nss_print_error_message(data, err); @@ -2348,7 +2356,7 @@ static ssize_t nss_recv(struct Curl_easy *data, /* transfer */ else { /* print the error number and error string */ const char *err_name = nss_error_to_name(err); - infof(data, "SSL read: errno %d (%s)\n", err, err_name); + infof(data, "SSL read: errno %d (%s)", err, err_name); /* print a human-readable message describing the error if available */ nss_print_error_message(data, err); @@ -2427,7 +2435,7 @@ static bool nss_false_start(void) } static void *nss_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) + CURLINFO info UNUSED_PARAM) { struct ssl_backend_data *backend = connssl->backend; (void)info; diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c index ebd7abc..87f4b02 100644 --- a/Utilities/cmcurl/lib/vtls/openssl.c +++ b/Utilities/cmcurl/lib/vtls/openssl.c @@ -194,7 +194,7 @@ !defined(OPENSSL_IS_BORINGSSL)) #define HAVE_SSL_CTX_SET_CIPHERSUITES #define HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH -/* SET_EC_CURVES available under the same preconditions: see +/* SET_EC_CURVES is available under the same preconditions: see * https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set1_groups.html */ #define HAVE_SSL_CTX_SET_EC_CURVES @@ -209,8 +209,8 @@ #endif #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) -/* up2date versions of OpenSSL maintain the default reasonably secure without - * breaking compatibility, so it is better not to override the default by curl +/* up2date versions of OpenSSL maintain reasonably secure defaults without + * breaking compatibility, so it is better not to override the defaults in curl */ #define DEFAULT_CIPHER_SELECTION NULL #else @@ -435,17 +435,16 @@ static bool rand_enough(void) static CURLcode ossl_seed(struct Curl_easy *data) { - /* we have the "SSL is seeded" boolean static to prevent multiple - time-consuming seedings in vain */ - static bool ssl_seeded = FALSE; char fname[256]; - if(ssl_seeded) + /* This might get called before it has been added to a multi handle */ + if(data->multi && data->multi->ssl_seeded) return CURLE_OK; if(rand_enough()) { /* OpenSSL 1.1.0+ will return here */ - ssl_seeded = TRUE; + if(data->multi) + data->multi->ssl_seeded = TRUE; return CURLE_OK; } @@ -518,7 +517,7 @@ static CURLcode ossl_seed(struct Curl_easy *data) return CURLE_OK; } - infof(data, "libcurl is now using a weak random seed!\n"); + infof(data, "libcurl is now using a weak random seed!"); return (rand_enough() ? CURLE_OK : CURLE_SSL_CONNECT_ERROR /* confusing error code */); } @@ -1193,7 +1192,7 @@ static int ossl_init(void) CONF_MFLAGS_IGNORE_MISSING_FILE); #endif - /* Lets get nice error messages */ + /* Let's get nice error messages */ SSL_load_error_strings(); /* Init the global ciphers and digests */ @@ -1354,7 +1353,7 @@ static CURLcode ossl_set_engine_default(struct Curl_easy *data) #ifdef USE_OPENSSL_ENGINE 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'", ENGINE_get_id(data->state.engine)); } else { @@ -1400,7 +1399,13 @@ static void ossl_closeone(struct Curl_easy *data, { struct ssl_backend_data *backend = connssl->backend; if(backend->handle) { + char buf[32]; set_logger(conn, data); + + /* Maybe the server has already sent a close notify alert. + Read it to avoid an RST on the TCP connection. */ + (void)SSL_read(backend->handle, buf, (int)sizeof(buf)); + (void)SSL_shutdown(backend->handle); SSL_set_connect_state(backend->handle); @@ -1442,6 +1447,7 @@ static int ossl_shutdown(struct Curl_easy *data, int err; bool done = FALSE; struct ssl_backend_data *backend = connssl->backend; + int loop = 10; #ifndef CURL_DISABLE_FTP /* This has only been tested on the proftpd server, and the mod_tls code @@ -1455,7 +1461,7 @@ static int ossl_shutdown(struct Curl_easy *data, if(backend->handle) { buffsize = (int)sizeof(buf); - while(!done) { + while(!done && loop--) { int what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); if(what > 0) { @@ -1475,11 +1481,11 @@ static int ossl_shutdown(struct Curl_easy *data, break; case SSL_ERROR_WANT_READ: /* there's data pending, re-invoke SSL_read() */ - infof(data, "SSL_ERROR_WANT_READ\n"); + infof(data, "SSL_ERROR_WANT_READ"); break; case SSL_ERROR_WANT_WRITE: /* SSL wants a write. Really odd. Let's bail out. */ - infof(data, "SSL_ERROR_WANT_WRITE\n"); + infof(data, "SSL_ERROR_WANT_WRITE"); done = TRUE; break; default: @@ -1511,14 +1517,14 @@ static int ossl_shutdown(struct Curl_easy *data, #ifdef HAVE_SSL_GET_SHUTDOWN switch(SSL_get_shutdown(backend->handle)) { case SSL_SENT_SHUTDOWN: - infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n"); + infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN"); break; case SSL_RECEIVED_SHUTDOWN: - infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n"); + infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN"); break; case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN: infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|" - "SSL_RECEIVED__SHUTDOWN\n"); + "SSL_RECEIVED__SHUTDOWN"); break; } #endif @@ -1585,7 +1591,7 @@ static bool subj_alt_hostcheck(struct Curl_easy *data, if(Curl_cert_hostcheck(match_pattern2, hostname)) { res = TRUE; infof(data, - " subjectAltName: host \"%s\" matched cert's \"%s\"\n", + " subjectAltName: host \"%s\" matched cert's \"%s\"", dispname, match_pattern2); } } @@ -1604,7 +1610,7 @@ static bool subj_alt_hostcheck(struct Curl_easy *data, (void)data; #endif if(Curl_cert_hostcheck(match_pattern, hostname)) { - infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"\n", + infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"", dispname, match_pattern); return TRUE; } @@ -1724,7 +1730,7 @@ static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn, if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) { ipmatched = TRUE; infof(data, - " subjectAltName: host \"%s\" matched cert's IP address!\n", + " subjectAltName: host \"%s\" matched cert's IP address!", dispname); } break; @@ -1741,7 +1747,7 @@ static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn, /* an alternative name matched */ ; else if(dNSName || iPAddress) { - infof(data, " subjectAltName does not match %s\n", dispname); + infof(data, " subjectAltName does not match %s", dispname); failf(data, "SSL: no alternative certificate subject name matches " "target host name '%s'", dispname); result = CURLE_PEER_FAILED_VERIFICATION; @@ -1763,7 +1769,7 @@ static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn, /* we have the name entry and we will now convert this to a string that we can use for comparison. Doing this we support BMPstring, - UTF8 etc. */ + UTF8, etc. */ if(i >= 0) { ASN1_STRING *tmp = @@ -1823,7 +1829,7 @@ static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn, result = CURLE_PEER_FAILED_VERIFICATION; } else { - infof(data, " common name: %s (matched)\n", peer_CN); + infof(data, " common name: %s (matched)", peer_CN); } if(peer_CN) OPENSSL_free(peer_CN); @@ -1959,7 +1965,7 @@ static CURLcode verifystatus(struct Curl_easy *data, goto end; } - infof(data, "SSL certificate status: %s (%d)\n", + infof(data, "SSL certificate status: %s (%d)", OCSP_cert_status_str(cert_status), cert_status); switch(cert_status) { @@ -2054,6 +2060,10 @@ static const char *ssl_msg_type(int ssl_ver, int msg) case SSL3_MT_ENCRYPTED_EXTENSIONS: return "Encrypted Extensions"; #endif +#ifdef SSL3_MT_SUPPLEMENTAL_DATA + case SSL3_MT_SUPPLEMENTAL_DATA: + return "Supplemental data"; +#endif #ifdef SSL3_MT_END_OF_EARLY_DATA case SSL3_MT_END_OF_EARLY_DATA: return "End of early data"; @@ -2152,7 +2162,7 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, /* Log progress for interesting records only (like Handshake or Alert), skip * all raw record headers (content_type == SSL3_RT_HEADER or ssl_ver == 0). - * For TLS 1.3, skip notification of the decrypted inner Content Type. + * For TLS 1.3, skip notification of the decrypted inner Content-Type. */ if(ssl_ver #ifdef SSL3_RT_INNER_CONTENT_TYPE @@ -2263,7 +2273,7 @@ select_next_proto_cb(SSL *ssl, #ifdef USE_HTTP2 if(data->state.httpwant >= CURL_HTTP_VERSION_2 && !select_next_protocol(out, outlen, in, inlen, ALPN_H2, ALPN_H2_LENGTH)) { - infof(data, "NPN, negotiated HTTP2 (%s)\n", ALPN_H2); + infof(data, "NPN, negotiated HTTP2 (%s)", ALPN_H2); conn->negnpn = CURL_HTTP_VERSION_2; return SSL_TLSEXT_ERR_OK; } @@ -2271,12 +2281,12 @@ select_next_proto_cb(SSL *ssl, if(!select_next_protocol(out, outlen, in, inlen, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) { - infof(data, "NPN, negotiated HTTP1.1\n"); + infof(data, "NPN, negotiated HTTP1.1"); conn->negnpn = CURL_HTTP_VERSION_1_1; return SSL_TLSEXT_ERR_OK; } - infof(data, "NPN, no overlap, use HTTP1.1\n"); + infof(data, "NPN, no overlap, use HTTP1.1"); *out = (unsigned char *)ALPN_HTTP_1_1; *outlen = ALPN_HTTP_1_1_LENGTH; conn->negnpn = CURL_HTTP_VERSION_1_1; @@ -2293,7 +2303,7 @@ set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn) long curl_ssl_version_min = SSL_CONN_CONFIG(version); long curl_ssl_version_max; - /* convert cURL min SSL version option to OpenSSL constant */ + /* convert curl min SSL version option to OpenSSL constant */ #if defined(OPENSSL_IS_BORINGSSL) || defined(LIBRESSL_VERSION_NUMBER) uint16_t ossl_ssl_version_min = 0; uint16_t ossl_ssl_version_max = 0; @@ -2323,7 +2333,7 @@ set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn) We don't want to pass 0 to SSL_CTX_set_min_proto_version as it would enable all versions down to the lowest supported by the library. - So we skip this, and stay with the OS default + So we skip this, and stay with the library default */ if(curl_ssl_version_min != CURL_SSLVERSION_DEFAULT) { if(!SSL_CTX_set_min_proto_version(ctx, ossl_ssl_version_min)) { @@ -2334,7 +2344,7 @@ set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn) /* ... then, TLS max version */ curl_ssl_version_max = SSL_CONN_CONFIG(version_max); - /* convert cURL max SSL version option to OpenSSL constant */ + /* convert curl max SSL version option to OpenSSL constant */ switch(curl_ssl_version_max) { case CURL_SSLVERSION_MAX_TLSv1_0: ossl_ssl_version_max = TLS1_VERSION; @@ -2493,7 +2503,7 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) &old_ssl_sessionid, NULL, sockindex)); if(incache) { if(old_ssl_sessionid != ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); + infof(data, "old SSL session ID is stale, removing"); Curl_ssl_delsessionid(data, old_ssl_sessionid); incache = FALSE; } @@ -2517,7 +2527,7 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) static CURLcode load_cacert_from_memory(SSL_CTX *ctx, const struct curl_blob *ca_info_blob) { - /* these need freed at the end */ + /* these need to be freed at the end */ BIO *cbio = NULL; STACK_OF(X509_INFO) *inf = NULL; @@ -2652,8 +2662,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, return CURLE_SSL_CONNECT_ERROR; } - if(backend->ctx) - SSL_CTX_free(backend->ctx); + DEBUGASSERT(!backend->ctx); backend->ctx = SSL_CTX_new(req_method); if(!backend->ctx) { @@ -2675,23 +2684,23 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, } #endif - /* OpenSSL contains code to work-around lots of bugs and flaws in various + /* OpenSSL contains code to work around lots of bugs and flaws in various SSL-implementations. SSL_CTX_set_options() is used to enabled those work-arounds. The man page for this option states that SSL_OP_ALL enables all the work-arounds and that "It is usually safe to use SSL_OP_ALL to enable the bug workaround options if compatibility with somewhat broken implementations is desired." - The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to + The "-no_ticket" option was introduced in OpenSSL 0.9.8j. It's a flag to disable "rfc4507bis session ticket support". rfc4507bis was later turned 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 - the session data is some overhead. .I suggest that you just use your + libcurl stops a connection and then resumes a TLS session. Also, sending + the session data is some overhead. I suggest that you just use your proposed patch (which explicitly disables TICKET). - If someone writes an application with libcurl and openssl who wants to + If someone writes an application with libcurl and OpenSSL who wants to enable the feature, one can do this in the SSL callback. SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper @@ -2727,7 +2736,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, #endif #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS - /* unless the user explicitly ask to allow the protocol vulnerability we + /* unless the user explicitly asks to allow the protocol vulnerability we use the work-around */ if(!SSL_SET_OPTION(enable_beast)) ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; @@ -2787,14 +2796,14 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, memcpy(&protocols[cur], ALPN_H2, ALPN_H2_LENGTH); cur += ALPN_H2_LENGTH; - infof(data, "ALPN, offering %s\n", ALPN_H2); + infof(data, "ALPN, offering %s", ALPN_H2); } #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); + infof(data, "ALPN, offering %s", ALPN_HTTP_1_1); /* expects length prefixed preference ordered list of protocols in wire * format @@ -2826,7 +2835,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, failf(data, "failed setting cipher list: %s", ciphers); return CURLE_SSL_CIPHER; } - infof(data, "Cipher selection: %s\n", ciphers); + infof(data, "Cipher selection: %s", ciphers); } #ifdef HAVE_SSL_CTX_SET_CIPHERSUITES @@ -2837,7 +2846,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13); return CURLE_SSL_CIPHER; } - infof(data, "TLS 1.3 cipher selection: %s\n", ciphers13); + infof(data, "TLS 1.3 cipher selection: %s", ciphers13); } } #endif @@ -2863,7 +2872,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, if(ssl_authtype == CURL_TLSAUTH_SRP) { char * const ssl_username = SSL_SET_OPTION(username); - infof(data, "Using TLS-SRP username: %s\n", ssl_username); + infof(data, "Using TLS-SRP username: %s", ssl_username); if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) { failf(data, "Unable to set SRP user name"); @@ -2874,7 +2883,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, return CURLE_BAD_FUNCTION_ARGUMENT; } if(!SSL_CONN_CONFIG(cipher_list)) { - infof(data, "Setting cipher list SRP\n"); + infof(data, "Setting cipher list SRP"); if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) { failf(data, "failed setting SRP cipher list"); @@ -2927,7 +2936,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, NULL, cert_name, sizeof(cert_name))) { strcpy(cert_name, "Unknown"); } - infof(data, "SSL: Checking cert \"%s\"\n", cert_name); + infof(data, "SSL: Checking cert %s\"\n", cert_name); #endif encoded_cert = (const unsigned char *)pContext->pbCertEncoded; @@ -3009,7 +3018,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, OpenSSL. */ if(X509_STORE_add_cert(store, x509) == 1) { #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) - infof(data, "SSL: Imported cert \"%s\"\n", cert_name); + infof(data, "SSL: Imported cert \"%s\"", cert_name); #endif imported_native_ca = true; } @@ -3024,9 +3033,9 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, return result; } if(imported_native_ca) - infof(data, "successfully imported windows ca store\n"); + infof(data, "successfully imported Windows CA store"); else - infof(data, "error importing windows ca store, continuing anyway\n"); + infof(data, "error importing Windows CA store, continuing anyway"); } #endif @@ -3038,8 +3047,8 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, failf(data, "error importing CA certificate blob"); return result; } - /* Only warning if no certificate verification is required. */ - infof(data, "error importing CA certificate blob, continuing anyway\n"); + /* Only warn if no certificate verification is required. */ + infof(data, "error importing CA certificate blob, continuing anyway"); } } @@ -3053,10 +3062,10 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, failf(data, "error setting certificate file: %s", ssl_cafile); return CURLE_SSL_CACERT_BADFILE; } - /* Continue with a warning if no certificate verif is required. */ - infof(data, "error setting certificate file, continuing anyway\n"); + /* Continue with warning if certificate verification isn't required. */ + infof(data, "error setting certificate file, continuing anyway"); } - infof(data, " CAfile: %s\n", ssl_cafile); + infof(data, " CAfile: %s", ssl_cafile); } if(ssl_capath) { if(!SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) { @@ -3065,16 +3074,16 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, failf(data, "error setting certificate path: %s", ssl_capath); return CURLE_SSL_CACERT_BADFILE; } - /* Continue with a warning if no certificate verif is required. */ - infof(data, "error setting certificate path, continuing anyway\n"); + /* Continue with warning if certificate verification isn't required. */ + infof(data, "error setting certificate path, continuing anyway"); } - infof(data, " CApath: %s\n", ssl_capath); + infof(data, " CApath: %s", ssl_capath); } } #else if(ssl_cafile || ssl_capath) { /* tell SSL where to find CA certificates that are used to verify - the servers certificate. */ + the server's certificate. */ if(!SSL_CTX_load_verify_locations(backend->ctx, ssl_cafile, ssl_capath)) { if(verifypeer && !imported_native_ca) { /* Fail if we insist on successfully verifying the server. */ @@ -3087,14 +3096,14 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, /* Just continue with a warning if no strict certificate verification is required. */ infof(data, "error setting certificate verify locations," - " continuing anyway:\n"); + " continuing anyway:"); } else { /* Everything is fine. */ - infof(data, "successfully set certificate verify locations:\n"); + infof(data, "successfully set certificate verify locations:"); } - infof(data, " CAfile: %s\n", ssl_cafile ? ssl_cafile : "none"); - infof(data, " CApath: %s\n", ssl_capath ? ssl_capath : "none"); + infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); } #endif @@ -3102,13 +3111,13 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, if(verifypeer && !ca_info_blob && !ssl_cafile && !ssl_capath && !imported_native_ca) { /* verifying the peer without any CA certificates won't - work so use openssl's built in default as fallback */ + work so use openssl's built-in default as fallback */ SSL_CTX_set_default_verify_paths(backend->ctx); } #endif if(ssl_crlfile) { - /* tell SSL where to find CRL file that is used to check certificate + /* tell OpenSSL where to find CRL file that is used to check certificate * revocation */ lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(backend->ctx), X509_LOOKUP_file()); @@ -3118,11 +3127,11 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, return CURLE_SSL_CRL_BADFILE; } /* Everything is fine. */ - infof(data, "successfully load CRL file:\n"); + infof(data, "successfully loaded CRL file:"); X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); - infof(data, " CRLfile: %s\n", ssl_crlfile); + infof(data, " CRLfile: %s", ssl_crlfile); } if(verifypeer) { @@ -3144,7 +3153,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, only, instead of needing the whole chain. Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we - cannot do partial chains with CRL check. + cannot do partial chains with a CRL check. */ X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), X509_V_FLAG_PARTIAL_CHAIN); @@ -3152,7 +3161,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, #endif } - /* SSL always tries to verify the peer, this only says whether it should + /* OpenSSL 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. */ @@ -3167,7 +3176,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, #endif /* Enable the session cache because it's a prerequisite for the "new session" - * callback. Use the "external storage" mode to avoid that OpenSSL creates + * callback. Use the "external storage" mode to prevent OpenSSL from creating * an internal session cache. */ SSL_CTX_set_session_cache_mode(backend->ctx, @@ -3186,7 +3195,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, } } - /* Lets make an SSL structure */ + /* Let's make an SSL structure */ if(backend->handle) SSL_free(backend->handle); backend->handle = SSL_new(backend->ctx); @@ -3226,7 +3235,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, data->state.buffer[nlen] = 0; if(!SSL_set_tlsext_host_name(backend->handle, data->state.buffer)) infof(data, "WARNING: failed to configure server name indication (SNI) " - "TLS extension\n"); + "TLS extension"); } #endif @@ -3244,7 +3253,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, return CURLE_SSL_CONNECT_ERROR; } /* Informational message */ - infof(data, "SSL re-using session ID\n"); + infof(data, "SSL re-using session ID"); } Curl_ssl_sessionid_unlock(data); @@ -3326,7 +3335,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data, /* 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 + /* Get the earliest error code from the thread's error queue and remove the entry. */ errdetail = ERR_get_error(); @@ -3355,7 +3364,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data, !defined(LIBRESSL_VERSION_NUMBER) && \ !defined(OPENSSL_IS_BORINGSSL)) /* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on - OpenSSL version above v1.1.1, not Libre SSL nor BoringSSL */ + OpenSSL version above v1.1.1, not LibreSSL nor BoringSSL */ else if((lib == ERR_LIB_SSL) && (reason == SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)) { /* If client certificate is required, communicate the @@ -3372,7 +3381,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data, /* detail is already set to the SSL error above */ /* If we e.g. use SSLv2 request-method and the server doesn't like us - * (RST connection etc.), OpenSSL gives no explanation whatsoever and + * (RST connection, etc.), OpenSSL gives no explanation whatsoever and * the SO_ERROR is also lost. */ if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) { @@ -3395,11 +3404,11 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data, } } else { - /* we have been connected fine, we're not waiting for anything else. */ + /* we connected fine, we're not waiting for anything else. */ connssl->connecting_state = ssl_connect_3; /* Informational message */ - infof(data, "SSL connection using %s / %s\n", + infof(data, "SSL connection using %s / %s", SSL_get_version(backend->handle), SSL_get_cipher(backend->handle)); @@ -3412,7 +3421,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data, unsigned int len; SSL_get0_alpn_selected(backend->handle, &neg_protocol, &len); if(len) { - infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol); + infof(data, "ALPN, server accepted to use %.*s", len, neg_protocol); #ifdef USE_HTTP2 if(len == ALPN_H2_LENGTH && @@ -3427,7 +3436,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data, } } else - infof(data, "ALPN, server did not agree to a protocol\n"); + infof(data, "ALPN, server did not agree to a protocol"); Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); @@ -3637,7 +3646,7 @@ static CURLcode get_cert_chain(struct Curl_easy *data, pubkey = X509_get_pubkey(x); if(!pubkey) - infof(data, " Unable to load public key\n"); + infof(data, " Unable to load public key"); else { int pktype; #ifdef HAVE_OPAQUE_EVP_PKEY @@ -3814,7 +3823,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, } /* - * Get the server cert, verify it and show it etc, only call failf() if the + * 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! * @@ -3851,23 +3860,23 @@ static CURLcode servercert(struct Curl_easy *data, return CURLE_PEER_FAILED_VERIFICATION; } - infof(data, "%s certificate:\n", SSL_IS_PROXY() ? "Proxy" : "Server"); + infof(data, "%s certificate:", SSL_IS_PROXY() ? "Proxy" : "Server"); rc = x509_name_oneline(X509_get_subject_name(backend->server_cert), buffer, sizeof(buffer)); - infof(data, " subject: %s\n", rc?"[NONE]":buffer); + infof(data, " subject: %s", rc?"[NONE]":buffer); #ifndef CURL_DISABLE_VERBOSE_STRINGS { long len; ASN1_TIME_print(mem, X509_get0_notBefore(backend->server_cert)); len = BIO_get_mem_data(mem, (char **) &ptr); - infof(data, " start date: %.*s\n", len, ptr); + infof(data, " start date: %.*s", (int)len, ptr); (void)BIO_reset(mem); ASN1_TIME_print(mem, X509_get0_notAfter(backend->server_cert)); len = BIO_get_mem_data(mem, (char **) &ptr); - infof(data, " expire date: %.*s\n", len, ptr); + infof(data, " expire date: %.*s", (int)len, ptr); (void)BIO_reset(mem); } #endif @@ -3891,16 +3900,16 @@ static CURLcode servercert(struct Curl_easy *data, result = CURLE_PEER_FAILED_VERIFICATION; } else { - infof(data, " issuer: %s\n", buffer); + infof(data, " issuer: %s", buffer); /* We could do all sorts of certificate verification stuff here before deallocating the certificate. */ /* e.g. match issuer name with provided issuer certificate */ - if(SSL_SET_OPTION(issuercert) || SSL_SET_OPTION(issuercert_blob)) { - if(SSL_SET_OPTION(issuercert_blob)) - fp = BIO_new_mem_buf(SSL_SET_OPTION(issuercert_blob)->data, - (int)SSL_SET_OPTION(issuercert_blob)->len); + if(SSL_CONN_CONFIG(issuercert) || SSL_CONN_CONFIG(issuercert_blob)) { + if(SSL_CONN_CONFIG(issuercert_blob)) + fp = BIO_new_mem_buf(SSL_CONN_CONFIG(issuercert_blob)->data, + (int)SSL_CONN_CONFIG(issuercert_blob)->len); else { fp = BIO_new(BIO_s_file()); if(!fp) { @@ -3914,10 +3923,10 @@ static CURLcode servercert(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } - if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) { + if(BIO_read_filename(fp, SSL_CONN_CONFIG(issuercert)) <= 0) { if(strict) failf(data, "SSL: Unable to open issuer cert (%s)", - SSL_SET_OPTION(issuercert)); + SSL_CONN_CONFIG(issuercert)); BIO_free(fp); X509_free(backend->server_cert); backend->server_cert = NULL; @@ -3929,7 +3938,7 @@ static CURLcode servercert(struct Curl_easy *data, if(!issuer) { if(strict) failf(data, "SSL: Unable to read issuer cert (%s)", - SSL_SET_OPTION(issuercert)); + SSL_CONN_CONFIG(issuercert)); BIO_free(fp); X509_free(issuer); X509_free(backend->server_cert); @@ -3940,7 +3949,7 @@ static CURLcode servercert(struct Curl_easy *data, 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)); + SSL_CONN_CONFIG(issuercert)); BIO_free(fp); X509_free(issuer); X509_free(backend->server_cert); @@ -3948,8 +3957,8 @@ static CURLcode servercert(struct Curl_easy *data, return CURLE_SSL_ISSUER_ERROR; } - infof(data, " SSL certificate issuer check ok (%s)\n", - SSL_SET_OPTION(issuercert)); + infof(data, " SSL certificate issuer check ok (%s)", + SSL_CONN_CONFIG(issuercert)); BIO_free(fp); X509_free(issuer); } @@ -3967,11 +3976,11 @@ static CURLcode servercert(struct Curl_easy *data, } else infof(data, " SSL certificate verify result: %s (%ld)," - " continuing anyway.\n", + " continuing anyway.", X509_verify_cert_error_string(lerr), lerr); } else - infof(data, " SSL certificate verify ok.\n"); + infof(data, " SSL certificate verify ok."); } #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ @@ -4015,7 +4024,7 @@ static CURLcode ossl_connect_step3(struct Curl_easy *data, /* * We check certificates to authenticate the server; otherwise we risk * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to - * verify the peer ignore faults and failures from the server cert + * verify the peer, ignore faults and failures from the server cert * operations. */ @@ -4053,7 +4062,7 @@ static CURLcode ossl_connect_common(struct Curl_easy *data, const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { - /* no need to continue if time already is up */ + /* no need to continue if time is already up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } @@ -4244,7 +4253,7 @@ static ssize_t ossl_send(struct Curl_easy *data, #endif ) { char ver[120]; - ossl_version(ver, 120); + (void)ossl_version(ver, sizeof(ver)); failf(data, "Error: %s does not support double SSL tunneling.", ver); } else @@ -4534,9 +4543,6 @@ static void ossl_disassociate_connection(struct Curl_easy *data, return; if(SSL_SET_OPTION(primary.sessionid)) { - bool isproxy = FALSE; - bool incache; - void *old_ssl_sessionid = NULL; int data_idx = ossl_get_ssl_data_index(); int connectdata_idx = ossl_get_ssl_conn_index(); int sockindex_idx = ossl_get_ssl_sockindex_index(); @@ -4544,9 +4550,6 @@ static void ossl_disassociate_connection(struct Curl_easy *data, if(data_idx >= 0 && connectdata_idx >= 0 && sockindex_idx >= 0 && proxy_idx >= 0) { - /* Invalidate the session cache entry, if any */ - isproxy = SSL_get_ex_data(backend->handle, proxy_idx) ? TRUE : FALSE; - /* Disable references to data in "new session" callback to avoid * accessing a stale pointer. */ SSL_set_ex_data(backend->handle, data_idx, NULL); @@ -4554,13 +4557,6 @@ static void ossl_disassociate_connection(struct Curl_easy *data, SSL_set_ex_data(backend->handle, sockindex_idx, NULL); SSL_set_ex_data(backend->handle, proxy_idx, NULL); } - - Curl_ssl_sessionid_lock(data); - incache = !(Curl_ssl_getsessionid(data, conn, isproxy, - &old_ssl_sessionid, NULL, sockindex)); - if(incache) - Curl_ssl_delsessionid(data, old_ssl_sessionid); - Curl_ssl_sessionid_unlock(data); } } diff --git a/Utilities/cmcurl/lib/vtls/rustls.c b/Utilities/cmcurl/lib/vtls/rustls.c index d5247f9..2ac97ce 100644 --- a/Utilities/cmcurl/lib/vtls/rustls.c +++ b/Utilities/cmcurl/lib/vtls/rustls.c @@ -34,7 +34,7 @@ #include "sendf.h" #include "vtls.h" #include "select.h" - +#include "strerror.h" #include "multiif.h" struct ssl_backend_data @@ -73,7 +73,7 @@ cr_connect(struct Curl_easy *data UNUSED_PARAM, struct connectdata *conn UNUSED_PARAM, int sockindex UNUSED_PARAM) { - infof(data, "rustls_connect: unimplemented\n"); + infof(data, "rustls_connect: unimplemented"); return CURLE_SSL_CONNECT_ERROR; } @@ -129,10 +129,12 @@ cr_recv(struct Curl_easy *data, int sockindex, io_error = rustls_connection_read_tls(rconn, read_cb, &conn->sock[sockindex], &tls_bytes_read); if(io_error == EAGAIN || io_error == EWOULDBLOCK) { - infof(data, "sread: EAGAIN or EWOULDBLOCK\n"); + infof(data, "sread: EAGAIN or EWOULDBLOCK"); } else if(io_error) { - failf(data, "reading from socket: %s", strerror(io_error)); + char buffer[STRERROR_LEN]; + failf(data, "reading from socket: %s", + Curl_strerror(io_error, buffer, sizeof(buffer))); *err = CURLE_READ_ERROR; return -1; } @@ -142,7 +144,7 @@ cr_recv(struct Curl_easy *data, int sockindex, return -1; } - infof(data, "cr_recv read %ld bytes from the network\n", tls_bytes_read); + infof(data, "cr_recv read %ld bytes from the network", tls_bytes_read); rresult = rustls_connection_process_new_packets(rconn); if(rresult != RUSTLS_RESULT_OK) { @@ -173,12 +175,12 @@ cr_recv(struct Curl_easy *data, int sockindex, available data has been read." If we bring in more ciphertext with read_tls, more plaintext will become available. So don't tell curl this is an EOF. Instead, say "come back later." */ - infof(data, "cr_recv got 0 bytes of plaintext\n"); + infof(data, "cr_recv got 0 bytes of plaintext"); backend->data_pending = FALSE; break; } else { - infof(data, "cr_recv copied out %ld bytes of plaintext\n", n); + infof(data, "cr_recv copied out %ld bytes of plaintext", n); plain_bytes_copied += n; } } @@ -218,7 +220,7 @@ cr_send(struct Curl_easy *data, int sockindex, rustls_result rresult; rustls_io_result io_error; - infof(data, "cr_send %ld bytes of plaintext\n", plainlen); + infof(data, "cr_send %ld bytes of plaintext", plainlen); if(plainlen > 0) { rresult = rustls_connection_write(rconn, plainbuf, plainlen, @@ -239,12 +241,14 @@ cr_send(struct Curl_easy *data, int sockindex, io_error = rustls_connection_write_tls(rconn, write_cb, &conn->sock[sockindex], &tlswritten); if(io_error == EAGAIN || io_error == EWOULDBLOCK) { - infof(data, "swrite: EAGAIN after %ld bytes\n", tlswritten_total); + infof(data, "swrite: EAGAIN after %ld bytes", tlswritten_total); *err = CURLE_AGAIN; return -1; } else if(io_error) { - failf(data, "writing to socket: %s", strerror(io_error)); + char buffer[STRERROR_LEN]; + failf(data, "writing to socket: %s", + Curl_strerror(io_error, buffer, sizeof(buffer))); *err = CURLE_WRITE_ERROR; return -1; } @@ -253,7 +257,7 @@ cr_send(struct Curl_easy *data, int sockindex, *err = CURLE_WRITE_ERROR; return -1; } - infof(data, "cr_send wrote %ld bytes to network\n", tlswritten); + infof(data, "cr_send wrote %ld bytes to network", tlswritten); tlswritten_total += tlswritten; } @@ -304,10 +308,10 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn, config_builder = rustls_client_config_builder_new(); #ifdef USE_HTTP2 - infof(data, "offering ALPN for HTTP/1.1 and HTTP/2\n"); + infof(data, "offering ALPN for HTTP/1.1 and HTTP/2"); rustls_client_config_builder_set_protocols(config_builder, alpn, 2); #else - infof(data, "offering ALPN for HTTP/1.1 only\n"); + infof(data, "offering ALPN for HTTP/1.1 only"); rustls_client_config_builder_set_protocols(config_builder, alpn, 1); #endif if(!verifypeer) { @@ -332,15 +336,6 @@ cr_init_backend(struct Curl_easy *data, struct connectdata *conn, return CURLE_SSL_CACERT_BADFILE; } } - else { - result = rustls_client_config_builder_load_native_roots(config_builder); - if(result != RUSTLS_RESULT_OK) { - failf(data, "failed to load trusted certificates"); - rustls_client_config_free( - rustls_client_config_builder_build(config_builder)); - return CURLE_SSL_CACERT_BADFILE; - } - } backend->config = rustls_client_config_builder_build(config_builder); DEBUGASSERT(rconn == NULL); @@ -364,24 +359,24 @@ cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn, rustls_connection_get_alpn_protocol(rconn, &protocol, &len); if(NULL == protocol) { - infof(data, "ALPN, server did not agree to a protocol\n"); + infof(data, "ALPN, server did not agree to a protocol"); return; } #ifdef USE_HTTP2 if(len == ALPN_H2_LENGTH && 0 == memcmp(ALPN_H2, protocol, len)) { - infof(data, "ALPN, negotiated h2\n"); + infof(data, "ALPN, negotiated h2"); conn->negnpn = CURL_HTTP_VERSION_2; } else #endif if(len == ALPN_HTTP_1_1_LENGTH && 0 == memcmp(ALPN_HTTP_1_1, protocol, len)) { - infof(data, "ALPN, negotiated http/1.1\n"); + infof(data, "ALPN, negotiated http/1.1"); conn->negnpn = CURL_HTTP_VERSION_1_1; } else { - infof(data, "ALPN, negotiated an unrecognized protocol\n"); + infof(data, "ALPN, negotiated an unrecognized protocol"); } Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? @@ -424,7 +419,7 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn, * once the handshake is done. */ if(!rustls_connection_is_handshaking(rconn)) { - infof(data, "Done handshaking\n"); + infof(data, "Done handshaking"); /* Done with the handshake. Set up callbacks to send/receive data. */ connssl->state = ssl_connection_complete; @@ -449,22 +444,19 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } if(0 == what) { - infof(data, "Curl_socket_check: %s would block\n", - wants_read&&wants_write ? - "writing and reading" : - wants_write ? - "writing" : - "reading"); + infof(data, "Curl_socket_check: %s would block", + wants_read&&wants_write ? "writing and reading" : + wants_write ? "writing" : "reading"); *done = FALSE; return CURLE_OK; } /* socket is readable or writable */ if(wants_write) { - infof(data, "rustls_connection wants us to write_tls.\n"); + infof(data, "rustls_connection wants us to write_tls."); cr_send(data, sockindex, NULL, 0, &tmperr); if(tmperr == CURLE_AGAIN) { - infof(data, "writing would block\n"); + infof(data, "writing would block"); /* fall through */ } else if(tmperr != CURLE_OK) { @@ -473,11 +465,11 @@ cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn, } if(wants_read) { - infof(data, "rustls_connection wants us to read_tls.\n"); + infof(data, "rustls_connection wants us to read_tls."); cr_recv(data, sockindex, NULL, 0, &tmperr); if(tmperr == CURLE_AGAIN) { - infof(data, "reading would block\n"); + infof(data, "reading would block"); /* fall through */ } else if(tmperr != CURLE_OK) { diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c index 3286a9e..722a937 100644 --- a/Utilities/cmcurl/lib/vtls/schannel.c +++ b/Utilities/cmcurl/lib/vtls/schannel.c @@ -141,6 +141,12 @@ # define CALG_SHA_256 0x0000800c #endif +/* Work around typo in classic MinGW's w32api up to version 5.0, + see https://osdn.net/projects/mingw/ticket/38391 */ +#if !defined(ALG_CLASS_DHASH) && defined(ALG_CLASS_HASH) +#define ALG_CLASS_DHASH ALG_CLASS_HASH +#endif + #define BACKEND connssl->backend static Curl_recv schannel_recv; @@ -279,13 +285,7 @@ get_alg_id_by_name(char *name) #ifdef CALG_HMAC CIPHEROPTION(CALG_HMAC); #endif -#if !defined(__W32API_MAJOR_VERSION) || \ - !defined(__W32API_MINOR_VERSION) || \ - defined(__MINGW64_VERSION_MAJOR) || \ - (__W32API_MAJOR_VERSION > 5) || \ - ((__W32API_MAJOR_VERSION == 5) && (__W32API_MINOR_VERSION > 0)) - /* CALG_TLS1PRF has a syntax error in MinGW's w32api up to version 5.0, - see https://osdn.net/projects/mingw/ticket/38391 */ +#ifdef CALG_TLS1PRF CIPHEROPTION(CALG_TLS1PRF); #endif #ifdef CALG_HASH_REPLACE_OWF @@ -372,23 +372,23 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path, store_name_len = sep - path; - if(_tcsnccmp(path, TEXT("CurrentUser"), store_name_len) == 0) + if(_tcsncmp(path, TEXT("CurrentUser"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_CURRENT_USER; - else if(_tcsnccmp(path, TEXT("LocalMachine"), store_name_len) == 0) + else if(_tcsncmp(path, TEXT("LocalMachine"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE; - else if(_tcsnccmp(path, TEXT("CurrentService"), store_name_len) == 0) + else if(_tcsncmp(path, TEXT("CurrentService"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_CURRENT_SERVICE; - else if(_tcsnccmp(path, TEXT("Services"), store_name_len) == 0) + else if(_tcsncmp(path, TEXT("Services"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_SERVICES; - else if(_tcsnccmp(path, TEXT("Users"), store_name_len) == 0) + else if(_tcsncmp(path, TEXT("Users"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_USERS; - else if(_tcsnccmp(path, TEXT("CurrentUserGroupPolicy"), + else if(_tcsncmp(path, TEXT("CurrentUserGroupPolicy"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY; - else if(_tcsnccmp(path, TEXT("LocalMachineGroupPolicy"), + else if(_tcsncmp(path, TEXT("LocalMachineGroupPolicy"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY; - else if(_tcsnccmp(path, TEXT("LocalMachineEnterprise"), + else if(_tcsncmp(path, TEXT("LocalMachineEnterprise"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE; else @@ -413,6 +413,341 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path, return CURLE_OK; } #endif +static CURLcode +schannel_acquire_credential_handle(struct Curl_easy *data, + struct connectdata *conn, + int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + SCHANNEL_CRED schannel_cred; + PCCERT_CONTEXT client_certs[1] = { NULL }; + SECURITY_STATUS sspi_status = SEC_E_OK; + CURLcode result; + + /* setup Schannel API options */ + memset(&schannel_cred, 0, sizeof(schannel_cred)); + schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; + + if(conn->ssl_config.verifypeer) { +#ifdef HAS_MANUAL_VERIFY_API + if(BACKEND->use_manual_cred_validation) + schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION; + else +#endif + schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION; + + if(SSL_SET_OPTION(no_revoke)) { + schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE; + + DEBUGF(infof(data, "schannel: disabled server certificate revocation " + "checks")); + } + else if(SSL_SET_OPTION(revoke_best_effort)) { + schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN; + + DEBUGF(infof(data, "schannel: ignore revocation offline errors")); + } + else { + schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN; + + DEBUGF(infof(data, + "schannel: checking server certificate revocation")); + } + } + else { + schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | + SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + SCH_CRED_IGNORE_REVOCATION_OFFLINE; + DEBUGF(infof(data, + "schannel: disabled server cert revocation checks")); + } + + if(!conn->ssl_config.verifyhost) { + schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK; + DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from " + "comparing the supplied target name with the subject " + "names in server certificates.")); + } + + if(!SSL_SET_OPTION(auto_client_cert)) { + schannel_cred.dwFlags &= ~SCH_CRED_USE_DEFAULT_CREDS; + schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS; + infof(data, "schannel: disabled automatic use of client certificate"); + } + else + infof(data, "schannel: enabled automatic use of client certificate"); + + switch(conn->ssl_config.version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: + case CURL_SSLVERSION_TLSv1_2: + case CURL_SSLVERSION_TLSv1_3: + { + result = set_ssl_version_min_max(&schannel_cred, data, conn); + if(result != CURLE_OK) + return result; + break; + } + case CURL_SSLVERSION_SSLv3: + case CURL_SSLVERSION_SSLv2: + failf(data, "SSL versions not supported"); + return CURLE_NOT_BUILT_IN; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(SSL_CONN_CONFIG(cipher_list)) { + result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list), + BACKEND->algIds); + if(CURLE_OK != result) { + failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG"); + return result; + } + } + + +#ifdef HAS_CLIENT_CERT_PATH + /* client certificate */ + if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) { + DWORD cert_store_name = 0; + TCHAR *cert_store_path = NULL; + TCHAR *cert_thumbprint_str = NULL; + CRYPT_HASH_BLOB cert_thumbprint; + BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN]; + HCERTSTORE cert_store = NULL; + FILE *fInCert = NULL; + void *certdata = NULL; + size_t certsize = 0; + bool blob = data->set.ssl.primary.cert_blob != NULL; + TCHAR *cert_path = NULL; + if(blob) { + certdata = data->set.ssl.primary.cert_blob->data; + certsize = data->set.ssl.primary.cert_blob->len; + } + else { + cert_path = curlx_convert_UTF8_to_tchar( + data->set.ssl.primary.clientcert); + if(!cert_path) + return CURLE_OUT_OF_MEMORY; + + result = get_cert_location(cert_path, &cert_store_name, + &cert_store_path, &cert_thumbprint_str); + + if(result && (data->set.ssl.primary.clientcert[0]!='\0')) + fInCert = fopen(data->set.ssl.primary.clientcert, "rb"); + + if(result && !fInCert) { + failf(data, "schannel: Failed to get certificate location" + " or file for %s", + data->set.ssl.primary.clientcert); + curlx_unicodefree(cert_path); + return result; + } + } + + if((fInCert || blob) && (data->set.ssl.cert_type) && + (!strcasecompare(data->set.ssl.cert_type, "P12"))) { + failf(data, "schannel: certificate format compatibility error " + " for %s", + blob ? "(memory blob)" : data->set.ssl.primary.clientcert); + curlx_unicodefree(cert_path); + return CURLE_SSL_CERTPROBLEM; + } + + if(fInCert || blob) { + /* Reading a .P12 or .pfx file, like the example at bottom of + https://social.msdn.microsoft.com/Forums/windowsdesktop/ + en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5 + */ + CRYPT_DATA_BLOB datablob; + WCHAR* pszPassword; + size_t pwd_len = 0; + int str_w_len = 0; + const char *cert_showfilename_error = blob ? + "(memory blob)" : data->set.ssl.primary.clientcert; + curlx_unicodefree(cert_path); + if(fInCert) { + long cert_tell = 0; + bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0; + if(continue_reading) + cert_tell = ftell(fInCert); + if(cert_tell < 0) + continue_reading = FALSE; + else + certsize = (size_t)cert_tell; + if(continue_reading) + continue_reading = fseek(fInCert, 0, SEEK_SET) == 0; + if(continue_reading) + certdata = malloc(certsize + 1); + if((!certdata) || + ((int) fread(certdata, certsize, 1, fInCert) != 1)) + continue_reading = FALSE; + fclose(fInCert); + if(!continue_reading) { + failf(data, "schannel: Failed to read cert file %s", + data->set.ssl.primary.clientcert); + free(certdata); + return CURLE_SSL_CERTPROBLEM; + } + } + + /* Convert key-pair data to the in-memory certificate store */ + datablob.pbData = (BYTE*)certdata; + datablob.cbData = (DWORD)certsize; + + if(data->set.ssl.key_passwd != NULL) + pwd_len = strlen(data->set.ssl.key_passwd); + pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1)); + if(pszPassword) { + if(pwd_len > 0) + str_w_len = MultiByteToWideChar(CP_UTF8, + MB_ERR_INVALID_CHARS, + data->set.ssl.key_passwd, (int)pwd_len, + pszPassword, (int)(pwd_len + 1)); + + if((str_w_len >= 0) && (str_w_len <= (int)pwd_len)) + pszPassword[str_w_len] = 0; + else + pszPassword[0] = 0; + + cert_store = PFXImportCertStore(&datablob, pszPassword, 0); + free(pszPassword); + } + if(!blob) + free(certdata); + if(!cert_store) { + DWORD errorcode = GetLastError(); + if(errorcode == ERROR_INVALID_PASSWORD) + failf(data, "schannel: Failed to import cert file %s, " + "password is bad", + cert_showfilename_error); + else + failf(data, "schannel: Failed to import cert file %s, " + "last error is 0x%x", + cert_showfilename_error, errorcode); + return CURLE_SSL_CERTPROBLEM; + } + + client_certs[0] = CertFindCertificateInStore( + cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, + CERT_FIND_ANY, NULL, NULL); + + if(!client_certs[0]) { + failf(data, "schannel: Failed to get certificate from file %s" + ", last error is 0x%x", + cert_showfilename_error, GetLastError()); + CertCloseStore(cert_store, 0); + return CURLE_SSL_CERTPROBLEM; + } + + schannel_cred.cCreds = 1; + schannel_cred.paCred = client_certs; + } + else { + cert_store = + CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0, + (HCRYPTPROV)NULL, + CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name, + cert_store_path); + if(!cert_store) { + failf(data, "schannel: Failed to open cert store %x %s, " + "last error is 0x%x", + cert_store_name, cert_store_path, GetLastError()); + free(cert_store_path); + curlx_unicodefree(cert_path); + return CURLE_SSL_CERTPROBLEM; + } + free(cert_store_path); + + cert_thumbprint.pbData = cert_thumbprint_data; + cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN; + + if(!CryptStringToBinary(cert_thumbprint_str, + CERT_THUMBPRINT_STR_LEN, + CRYPT_STRING_HEX, + cert_thumbprint_data, + &cert_thumbprint.cbData, + NULL, NULL)) { + curlx_unicodefree(cert_path); + CertCloseStore(cert_store, 0); + return CURLE_SSL_CERTPROBLEM; + } + + client_certs[0] = CertFindCertificateInStore( + cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, + CERT_FIND_HASH, &cert_thumbprint, NULL); + + curlx_unicodefree(cert_path); + + if(client_certs[0]) { + schannel_cred.cCreds = 1; + schannel_cred.paCred = client_certs; + } + else { + /* CRYPT_E_NOT_FOUND / E_INVALIDARG */ + CertCloseStore(cert_store, 0); + return CURLE_SSL_CERTPROBLEM; + } + } + CertCloseStore(cert_store, 0); + } +#else + if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) { + failf(data, "schannel: client cert support not built in"); + return CURLE_NOT_BUILT_IN; + } +#endif + + /* allocate memory for the re-usable credential handle */ + BACKEND->cred = (struct Curl_schannel_cred *) + calloc(1, sizeof(struct Curl_schannel_cred)); + if(!BACKEND->cred) { + failf(data, "schannel: unable to allocate memory"); + + if(client_certs[0]) + CertFreeCertificateContext(client_certs[0]); + + return CURLE_OUT_OF_MEMORY; + } + BACKEND->cred->refcount = 1; + + /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx + */ + sspi_status = + s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, + SECPKG_CRED_OUTBOUND, NULL, + &schannel_cred, NULL, NULL, + &BACKEND->cred->cred_handle, + &BACKEND->cred->time_stamp); + + if(client_certs[0]) + CertFreeCertificateContext(client_certs[0]); + + if(sspi_status != SEC_E_OK) { + char buffer[STRERROR_LEN]; + failf(data, "schannel: AcquireCredentialsHandle failed: %s", + Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); + Curl_safefree(BACKEND->cred); + switch(sspi_status) { + case SEC_E_INSUFFICIENT_MEMORY: + return CURLE_OUT_OF_MEMORY; + case SEC_E_NO_CREDENTIALS: + case SEC_E_SECPKG_NOT_FOUND: + case SEC_E_NOT_OWNER: + case SEC_E_UNKNOWN_CREDENTIALS: + case SEC_E_INTERNAL_ERROR: + default: + return CURLE_SSL_CONNECT_ERROR; + } + } + + return CURLE_OK; +} static CURLcode schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, @@ -427,8 +762,6 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, #ifdef HAS_ALPN unsigned char alpn_buffer[128]; #endif - SCHANNEL_CRED schannel_cred; - PCCERT_CONTEXT client_certs[1] = { NULL }; SECURITY_STATUS sspi_status = SEC_E_OK; struct Curl_schannel_cred *old_cred = NULL; struct in_addr addr; @@ -440,7 +773,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, char * const hostname = SSL_HOST_NAME(); DEBUGF(infof(data, - "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n", + "schannel: SSL/TLS connection with %s port %hu (step 1/3)", hostname, conn->remote_port)); if(curlx_verify_windows_version(5, 1, PLATFORM_WINNT, @@ -448,7 +781,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and algorithms that may not be supported by all servers. */ infof(data, "schannel: Windows version is old and may not be able to " - "connect to some servers due to lack of SNI, algorithms, etc.\n"); + "connect to some servers due to lack of SNI, algorithms, etc."); } #ifdef HAS_ALPN @@ -503,338 +836,21 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, SSL_IS_PROXY() ? TRUE : FALSE, (void **)&old_cred, NULL, sockindex)) { BACKEND->cred = old_cred; - DEBUGF(infof(data, "schannel: re-using existing credential handle\n")); + DEBUGF(infof(data, "schannel: re-using existing credential handle")); /* increment the reference counter of the credential/session handle */ BACKEND->cred->refcount++; DEBUGF(infof(data, - "schannel: incremented credential handle refcount = %d\n", + "schannel: incremented credential handle refcount = %d", BACKEND->cred->refcount)); } Curl_ssl_sessionid_unlock(data); } if(!BACKEND->cred) { - /* setup Schannel API options */ - memset(&schannel_cred, 0, sizeof(schannel_cred)); - schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; - - if(conn->ssl_config.verifypeer) { -#ifdef HAS_MANUAL_VERIFY_API - if(BACKEND->use_manual_cred_validation) - schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION; - else -#endif - schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION; - - if(SSL_SET_OPTION(no_revoke)) { - schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | - SCH_CRED_IGNORE_REVOCATION_OFFLINE; - - DEBUGF(infof(data, "schannel: disabled server certificate revocation " - "checks\n")); - } - else if(SSL_SET_OPTION(revoke_best_effort)) { - schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | - SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN; - - DEBUGF(infof(data, "schannel: ignore revocation offline errors")); - } - else { - schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN; - - DEBUGF(infof(data, - "schannel: checking server certificate revocation\n")); - } - } - else { - schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | - SCH_CRED_IGNORE_NO_REVOCATION_CHECK | - SCH_CRED_IGNORE_REVOCATION_OFFLINE; - DEBUGF(infof(data, - "schannel: disabled server cert revocation checks\n")); - } - - if(!conn->ssl_config.verifyhost) { - schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK; - DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from " - "comparing the supplied target name with the subject " - "names in server certificates.\n")); - } - - if(!SSL_SET_OPTION(auto_client_cert)) { - schannel_cred.dwFlags &= ~SCH_CRED_USE_DEFAULT_CREDS; - schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS; - infof(data, "schannel: disabled automatic use of client certificate\n"); - } - else - infof(data, "schannel: enabled automatic use of client certificate\n"); - - switch(conn->ssl_config.version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: - case CURL_SSLVERSION_TLSv1_3: - { - result = set_ssl_version_min_max(&schannel_cred, data, conn); - if(result != CURLE_OK) - return result; - break; - } - case CURL_SSLVERSION_SSLv3: - case CURL_SSLVERSION_SSLv2: - failf(data, "SSL versions not supported"); - return CURLE_NOT_BUILT_IN; - default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); - return CURLE_SSL_CONNECT_ERROR; - } - - if(SSL_CONN_CONFIG(cipher_list)) { - result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list), - BACKEND->algIds); - if(CURLE_OK != result) { - failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG"); - return result; - } - } - - -#ifdef HAS_CLIENT_CERT_PATH - /* client certificate */ - if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) { - DWORD cert_store_name = 0; - TCHAR *cert_store_path = NULL; - TCHAR *cert_thumbprint_str = NULL; - CRYPT_HASH_BLOB cert_thumbprint; - BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN]; - HCERTSTORE cert_store = NULL; - FILE *fInCert = NULL; - void *certdata = NULL; - size_t certsize = 0; - bool blob = data->set.ssl.primary.cert_blob != NULL; - TCHAR *cert_path = NULL; - if(blob) { - certdata = data->set.ssl.primary.cert_blob->data; - certsize = data->set.ssl.primary.cert_blob->len; - } - else { - cert_path = curlx_convert_UTF8_to_tchar( - data->set.ssl.primary.clientcert); - if(!cert_path) - return CURLE_OUT_OF_MEMORY; - - result = get_cert_location(cert_path, &cert_store_name, - &cert_store_path, &cert_thumbprint_str); - - if(result && (data->set.ssl.primary.clientcert[0]!='\0')) - fInCert = fopen(data->set.ssl.primary.clientcert, "rb"); - - if(result && !fInCert) { - failf(data, "schannel: Failed to get certificate location" - " or file for %s", - data->set.ssl.primary.clientcert); - curlx_unicodefree(cert_path); - return result; - } - } - - if((fInCert || blob) && (data->set.ssl.cert_type) && - (!strcasecompare(data->set.ssl.cert_type, "P12"))) { - failf(data, "schannel: certificate format compatibility error " - " for %s", - blob ? "(memory blob)" : data->set.ssl.primary.clientcert); - curlx_unicodefree(cert_path); - return CURLE_SSL_CERTPROBLEM; - } - - if(fInCert || blob) { - /* Reading a .P12 or .pfx file, like the example at bottom of - https://social.msdn.microsoft.com/Forums/windowsdesktop/ - en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5 - */ - CRYPT_DATA_BLOB datablob; - WCHAR* pszPassword; - size_t pwd_len = 0; - int str_w_len = 0; - const char *cert_showfilename_error = blob ? - "(memory blob)" : data->set.ssl.primary.clientcert; - curlx_unicodefree(cert_path); - if(fInCert) { - long cert_tell = 0; - bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0; - if(continue_reading) - cert_tell = ftell(fInCert); - if(cert_tell < 0) - continue_reading = FALSE; - else - certsize = (size_t)cert_tell; - if(continue_reading) - continue_reading = fseek(fInCert, 0, SEEK_SET) == 0; - if(continue_reading) - certdata = malloc(certsize + 1); - if((!certdata) || - ((int) fread(certdata, certsize, 1, fInCert) != 1)) - continue_reading = FALSE; - fclose(fInCert); - if(!continue_reading) { - failf(data, "schannel: Failed to read cert file %s", - data->set.ssl.primary.clientcert); - free(certdata); - return CURLE_SSL_CERTPROBLEM; - } - } - - /* Convert key-pair data to the in-memory certificate store */ - datablob.pbData = (BYTE*)certdata; - datablob.cbData = (DWORD)certsize; - - if(data->set.ssl.key_passwd != NULL) - pwd_len = strlen(data->set.ssl.key_passwd); - pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1)); - if(pszPassword) { - if(pwd_len > 0) - str_w_len = MultiByteToWideChar(CP_UTF8, - MB_ERR_INVALID_CHARS, - data->set.ssl.key_passwd, (int)pwd_len, - pszPassword, (int)(pwd_len + 1)); - - if((str_w_len >= 0) && (str_w_len <= (int)pwd_len)) - pszPassword[str_w_len] = 0; - else - pszPassword[0] = 0; - - cert_store = PFXImportCertStore(&datablob, pszPassword, 0); - free(pszPassword); - } - if(!blob) - free(certdata); - if(!cert_store) { - DWORD errorcode = GetLastError(); - if(errorcode == ERROR_INVALID_PASSWORD) - failf(data, "schannel: Failed to import cert file %s, " - "password is bad", - cert_showfilename_error); - else - failf(data, "schannel: Failed to import cert file %s, " - "last error is 0x%x", - cert_showfilename_error, errorcode); - return CURLE_SSL_CERTPROBLEM; - } - - client_certs[0] = CertFindCertificateInStore( - cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, - CERT_FIND_ANY, NULL, NULL); - - if(!client_certs[0]) { - failf(data, "schannel: Failed to get certificate from file %s" - ", last error is 0x%x", - cert_showfilename_error, GetLastError()); - CertCloseStore(cert_store, 0); - return CURLE_SSL_CERTPROBLEM; - } - - schannel_cred.cCreds = 1; - schannel_cred.paCred = client_certs; - } - else { - cert_store = - CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0, - (HCRYPTPROV)NULL, - CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name, - cert_store_path); - if(!cert_store) { - failf(data, "schannel: Failed to open cert store %x %s, " - "last error is 0x%x", - cert_store_name, cert_store_path, GetLastError()); - free(cert_store_path); - curlx_unicodefree(cert_path); - return CURLE_SSL_CERTPROBLEM; - } - free(cert_store_path); - - cert_thumbprint.pbData = cert_thumbprint_data; - cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN; - - if(!CryptStringToBinary(cert_thumbprint_str, - CERT_THUMBPRINT_STR_LEN, - CRYPT_STRING_HEX, - cert_thumbprint_data, - &cert_thumbprint.cbData, - NULL, NULL)) { - curlx_unicodefree(cert_path); - CertCloseStore(cert_store, 0); - return CURLE_SSL_CERTPROBLEM; - } - - client_certs[0] = CertFindCertificateInStore( - cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, - CERT_FIND_HASH, &cert_thumbprint, NULL); - - curlx_unicodefree(cert_path); - - if(client_certs[0]) { - schannel_cred.cCreds = 1; - schannel_cred.paCred = client_certs; - } - else { - /* CRYPT_E_NOT_FOUND / E_INVALIDARG */ - CertCloseStore(cert_store, 0); - return CURLE_SSL_CERTPROBLEM; - } - } - CertCloseStore(cert_store, 0); - } -#else - if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) { - failf(data, "schannel: client cert support not built in"); - return CURLE_NOT_BUILT_IN; - } -#endif - - /* allocate memory for the re-usable credential handle */ - BACKEND->cred = (struct Curl_schannel_cred *) - calloc(1, sizeof(struct Curl_schannel_cred)); - if(!BACKEND->cred) { - failf(data, "schannel: unable to allocate memory"); - - if(client_certs[0]) - CertFreeCertificateContext(client_certs[0]); - - return CURLE_OUT_OF_MEMORY; - } - BACKEND->cred->refcount = 1; - - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx - */ - sspi_status = - s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, - SECPKG_CRED_OUTBOUND, NULL, - &schannel_cred, NULL, NULL, - &BACKEND->cred->cred_handle, - &BACKEND->cred->time_stamp); - - if(client_certs[0]) - CertFreeCertificateContext(client_certs[0]); - - if(sspi_status != SEC_E_OK) { - char buffer[STRERROR_LEN]; - failf(data, "schannel: AcquireCredentialsHandle failed: %s", - Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); - Curl_safefree(BACKEND->cred); - switch(sspi_status) { - case SEC_E_INSUFFICIENT_MEMORY: - return CURLE_OUT_OF_MEMORY; - case SEC_E_NO_CREDENTIALS: - case SEC_E_SECPKG_NOT_FOUND: - case SEC_E_NOT_OWNER: - case SEC_E_UNKNOWN_CREDENTIALS: - case SEC_E_INTERNAL_ERROR: - default: - return CURLE_SSL_CONNECT_ERROR; - } + result = schannel_acquire_credential_handle(data, conn, sockindex); + if(result != CURLE_OK) { + return result; } } @@ -844,7 +860,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, || Curl_inet_pton(AF_INET6, hostname, &addr6) #endif ) { - infof(data, "schannel: using IP address, SNI is not supported by OS.\n"); + infof(data, "schannel: using IP address, SNI is not supported by OS."); } #ifdef HAS_ALPN @@ -877,14 +893,14 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, alpn_buffer[cur++] = ALPN_H2_LENGTH; memcpy(&alpn_buffer[cur], ALPN_H2, ALPN_H2_LENGTH); cur += ALPN_H2_LENGTH; - infof(data, "schannel: ALPN, offering %s\n", ALPN_H2); + infof(data, "schannel: ALPN, offering %s", ALPN_H2); } #endif alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH; memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); cur += ALPN_HTTP_1_1_LENGTH; - infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1); + infof(data, "schannel: ALPN, offering %s", ALPN_HTTP_1_1); *list_len = curlx_uitous(cur - list_start_index); *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short); @@ -972,7 +988,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, } DEBUGF(infof(data, "schannel: sending initial handshake data: " - "sending %lu bytes...\n", outbuf.cbBuffer)); + "sending %lu bytes.", outbuf.cbBuffer)); /* send initial handshake data which is now stored in output buffer */ result = Curl_write_plain(data, conn->sock[sockindex], outbuf.pvBuffer, @@ -985,7 +1001,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, } DEBUGF(infof(data, "schannel: sent initial handshake data: " - "sent %zd bytes\n", written)); + "sent %zd bytes", written)); BACKEND->recv_unrecoverable_err = CURLE_OK; BACKEND->recv_sspi_close_notify = false; @@ -1019,7 +1035,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE; DEBUGF(infof(data, - "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n", + "schannel: SSL/TLS connection with %s port %hu (step 2/3)", hostname, conn->remote_port)); if(!BACKEND->cred || !BACKEND->ctxt) @@ -1081,7 +1097,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, if(connssl->connecting_state != ssl_connect_2_writing) connssl->connecting_state = ssl_connect_2_reading; DEBUGF(infof(data, "schannel: failed to receive handshake, " - "need more data\n")); + "need more data")); return CURLE_OK; } else if((result != CURLE_OK) || (nread == 0)) { @@ -1093,11 +1109,11 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, /* increase encrypted data buffer offset */ BACKEND->encdata_offset += nread; BACKEND->encdata_is_incomplete = false; - DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread)); + DEBUGF(infof(data, "schannel: encrypted data got %zd", nread)); } DEBUGF(infof(data, - "schannel: encrypted data buffer: offset %zu length %zu\n", + "schannel: encrypted data buffer: offset %zu length %zu", BACKEND->encdata_offset, BACKEND->encdata_length)); /* setup input buffers */ @@ -1142,7 +1158,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, BACKEND->encdata_is_incomplete = true; connssl->connecting_state = ssl_connect_2_reading; DEBUGF(infof(data, - "schannel: received incomplete message, need more data\n")); + "schannel: received incomplete message, need more data")); return CURLE_OK; } @@ -1154,7 +1170,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; connssl->connecting_state = ssl_connect_2_writing; DEBUGF(infof(data, - "schannel: a client certificate has been requested\n")); + "schannel: a client certificate has been requested")); return CURLE_OK; } @@ -1164,7 +1180,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, /* search for handshake tokens that need to be send */ if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) { DEBUGF(infof(data, "schannel: sending next handshake data: " - "sending %lu bytes...\n", outbuf[i].cbBuffer)); + "sending %lu bytes.", outbuf[i].cbBuffer)); /* send handshake token to server */ result = Curl_write_plain(data, conn->sock[sockindex], @@ -1219,7 +1235,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, /* check if there was additional remaining encrypted data */ if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) { - DEBUGF(infof(data, "schannel: encrypted data length: %lu\n", + DEBUGF(infof(data, "schannel: encrypted data length: %lu", inbuf[1].cbBuffer)); /* There are two cases where we could be getting extra data here: @@ -1259,7 +1275,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, /* check if the handshake is complete */ if(sspi_status == SEC_E_OK) { connssl->connecting_state = ssl_connect_3; - DEBUGF(infof(data, "schannel: SSL/TLS handshake complete\n")); + DEBUGF(infof(data, "schannel: SSL/TLS handshake complete")); } pubkey_ptr = SSL_PINNED_PUB_KEY(); @@ -1348,7 +1364,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, SECURITY_STATUS sspi_status = SEC_E_OK; CERT_CONTEXT *ccert_context = NULL; bool isproxy = SSL_IS_PROXY(); -#ifdef DEBUGBUILD +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) const char * const hostname = SSL_HOST_NAME(); #endif #ifdef HAS_ALPN @@ -1358,7 +1374,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); DEBUGF(infof(data, - "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n", + "schannel: SSL/TLS connection with %s port %hu (step 3/3)", hostname, conn->remote_port)); if(!BACKEND->cred) @@ -1394,7 +1410,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, if(alpn_result.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) { - infof(data, "schannel: ALPN, server accepted to use %.*s\n", + infof(data, "schannel: ALPN, server accepted to use %.*s", alpn_result.ProtocolIdSize, alpn_result.ProtocolId); #ifdef USE_HTTP2 @@ -1411,7 +1427,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, } } else - infof(data, "ALPN, server did not agree to a protocol\n"); + infof(data, "ALPN, server did not agree to a protocol"); Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } @@ -1428,7 +1444,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, if(incache) { if(old_cred != BACKEND->cred) { DEBUGF(infof(data, - "schannel: old credential handle is stale, removing\n")); + "schannel: old credential handle is stale, removing")); /* we're not taking old_cred ownership here, no refcount++ is needed */ Curl_ssl_delsessionid(data, (void *)old_cred); incache = FALSE; @@ -1447,7 +1463,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, /* this cred session is now also referenced by sessionid cache */ BACKEND->cred->refcount++; DEBUGF(infof(data, - "schannel: stored credential handle in session cache\n")); + "schannel: stored credential handle in session cache")); } } Curl_ssl_sessionid_unlock(data); @@ -1778,21 +1794,21 @@ schannel_recv(struct Curl_easy *data, int sockindex, * handled in the cleanup. */ - DEBUGF(infof(data, "schannel: client wants to read %zu bytes\n", len)); + DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len)); *err = CURLE_OK; if(len && len <= BACKEND->decdata_offset) { - infof(data, "schannel: enough decrypted data is already available\n"); + infof(data, "schannel: enough decrypted data is already available"); goto cleanup; } else if(BACKEND->recv_unrecoverable_err) { *err = BACKEND->recv_unrecoverable_err; - infof(data, "schannel: an unrecoverable error occurred in a prior call\n"); + infof(data, "schannel: an unrecoverable error occurred in a prior call"); goto cleanup; } else if(BACKEND->recv_sspi_close_notify) { /* once a server has indicated shutdown there is no more encrypted data */ - infof(data, "schannel: server indicated shutdown in a prior call\n"); + infof(data, "schannel: server indicated shutdown in a prior call"); goto cleanup; } @@ -1821,12 +1837,12 @@ schannel_recv(struct Curl_easy *data, int sockindex, BACKEND->encdata_buffer = reallocated_buffer; BACKEND->encdata_length = reallocated_length; size = BACKEND->encdata_length - BACKEND->encdata_offset; - DEBUGF(infof(data, "schannel: encdata_buffer resized %zu\n", + DEBUGF(infof(data, "schannel: encdata_buffer resized %zu", BACKEND->encdata_length)); } DEBUGF(infof(data, - "schannel: encrypted data buffer: offset %zu length %zu\n", + "schannel: encrypted data buffer: offset %zu length %zu", BACKEND->encdata_offset, BACKEND->encdata_length)); /* read encrypted data from socket */ @@ -1838,25 +1854,25 @@ schannel_recv(struct Curl_easy *data, int sockindex, nread = -1; if(*err == CURLE_AGAIN) DEBUGF(infof(data, - "schannel: Curl_read_plain returned CURLE_AGAIN\n")); + "schannel: Curl_read_plain returned CURLE_AGAIN")); else if(*err == CURLE_RECV_ERROR) - infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n"); + infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR"); else - infof(data, "schannel: Curl_read_plain returned error %d\n", *err); + infof(data, "schannel: Curl_read_plain returned error %d", *err); } else if(nread == 0) { BACKEND->recv_connection_closed = true; - DEBUGF(infof(data, "schannel: server closed the connection\n")); + DEBUGF(infof(data, "schannel: server closed the connection")); } else if(nread > 0) { BACKEND->encdata_offset += (size_t)nread; BACKEND->encdata_is_incomplete = false; - DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread)); + DEBUGF(infof(data, "schannel: encrypted data got %zd", nread)); } } DEBUGF(infof(data, - "schannel: encrypted data buffer: offset %zu length %zu\n", + "schannel: encrypted data buffer: offset %zu length %zu", BACKEND->encdata_offset, BACKEND->encdata_length)); /* decrypt loop */ @@ -1885,7 +1901,7 @@ schannel_recv(struct Curl_easy *data, int sockindex, /* check for successfully decrypted data, even before actual renegotiation or shutdown of the connection context */ if(inbuf[1].BufferType == SECBUFFER_DATA) { - DEBUGF(infof(data, "schannel: decrypted data length: %lu\n", + DEBUGF(infof(data, "schannel: decrypted data length: %lu", inbuf[1].cbBuffer)); /* increase buffer in order to fit the received amount of data */ @@ -1918,15 +1934,15 @@ schannel_recv(struct Curl_easy *data, int sockindex, BACKEND->decdata_offset += size; } - DEBUGF(infof(data, "schannel: decrypted data added: %zu\n", size)); + DEBUGF(infof(data, "schannel: decrypted data added: %zu", size)); DEBUGF(infof(data, - "schannel: decrypted cached: offset %zu length %zu\n", + "schannel: decrypted cached: offset %zu length %zu", BACKEND->decdata_offset, BACKEND->decdata_length)); } /* check for remaining encrypted data */ if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) { - DEBUGF(infof(data, "schannel: encrypted data length: %lu\n", + DEBUGF(infof(data, "schannel: encrypted data length: %lu", inbuf[3].cbBuffer)); /* check if the remaining data is less than the total amount @@ -1942,7 +1958,7 @@ schannel_recv(struct Curl_easy *data, int sockindex, } DEBUGF(infof(data, - "schannel: encrypted cached: offset %zu length %zu\n", + "schannel: encrypted cached: offset %zu length %zu", BACKEND->encdata_offset, BACKEND->encdata_length)); } else { @@ -1952,29 +1968,29 @@ schannel_recv(struct Curl_easy *data, int sockindex, /* check if server wants to renegotiate the connection context */ if(sspi_status == SEC_I_RENEGOTIATE) { - infof(data, "schannel: remote party requests renegotiation\n"); + infof(data, "schannel: remote party requests renegotiation"); if(*err && *err != CURLE_AGAIN) { - infof(data, "schannel: can't renogotiate, an error is pending\n"); + infof(data, "schannel: can't renogotiate, an error is pending"); goto cleanup; } if(BACKEND->encdata_offset) { *err = CURLE_RECV_ERROR; infof(data, "schannel: can't renogotiate, " - "encrypted data available\n"); + "encrypted data available"); goto cleanup; } /* begin renegotiation */ - infof(data, "schannel: renegotiating SSL/TLS connection\n"); + infof(data, "schannel: renegotiating SSL/TLS connection"); connssl->state = ssl_connection_negotiating; connssl->connecting_state = ssl_connect_2_writing; *err = schannel_connect_common(data, conn, sockindex, FALSE, &done); if(*err) { - infof(data, "schannel: renegotiation failed\n"); + infof(data, "schannel: renegotiation failed"); goto cleanup; } /* now retry receiving data */ sspi_status = SEC_E_OK; - infof(data, "schannel: SSL/TLS connection renegotiated\n"); + infof(data, "schannel: SSL/TLS connection renegotiated"); continue; } /* check if the server closed the connection */ @@ -1984,7 +2000,7 @@ schannel_recv(struct Curl_easy *data, int sockindex, BACKEND->recv_sspi_close_notify = true; if(!BACKEND->recv_connection_closed) { BACKEND->recv_connection_closed = true; - infof(data, "schannel: server closed the connection\n"); + infof(data, "schannel: server closed the connection"); } goto cleanup; } @@ -1993,7 +2009,7 @@ schannel_recv(struct Curl_easy *data, int sockindex, BACKEND->encdata_is_incomplete = true; if(!*err) *err = CURLE_AGAIN; - infof(data, "schannel: failed to decrypt data, need more data\n"); + infof(data, "schannel: failed to decrypt data, need more data"); goto cleanup; } else { @@ -2001,23 +2017,23 @@ schannel_recv(struct Curl_easy *data, int sockindex, char buffer[STRERROR_LEN]; #endif *err = CURLE_RECV_ERROR; - infof(data, "schannel: failed to read data from server: %s\n", + infof(data, "schannel: failed to read data from server: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); goto cleanup; } } DEBUGF(infof(data, - "schannel: encrypted data buffer: offset %zu length %zu\n", + "schannel: encrypted data buffer: offset %zu length %zu", BACKEND->encdata_offset, BACKEND->encdata_length)); DEBUGF(infof(data, - "schannel: decrypted data buffer: offset %zu length %zu\n", + "schannel: decrypted data buffer: offset %zu length %zu", BACKEND->decdata_offset, BACKEND->decdata_length)); cleanup: /* Warning- there is no guarantee the encdata state is valid at this point */ - DEBUGF(infof(data, "schannel: schannel_recv cleanup\n")); + DEBUGF(infof(data, "schannel: schannel_recv cleanup")); /* Error if the connection has closed without a close_notify. @@ -2039,7 +2055,7 @@ schannel_recv(struct Curl_easy *data, int sockindex, BACKEND->recv_sspi_close_notify = true; else { *err = CURLE_RECV_ERROR; - infof(data, "schannel: server closed abruptly (missing close_notify)\n"); + infof(data, "schannel: server closed abruptly (missing close_notify)"); } } @@ -2053,9 +2069,9 @@ schannel_recv(struct Curl_easy *data, int sockindex, memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size, BACKEND->decdata_offset - size); BACKEND->decdata_offset -= size; - DEBUGF(infof(data, "schannel: decrypted data returned %zu\n", size)); + DEBUGF(infof(data, "schannel: decrypted data returned %zu", size)); DEBUGF(infof(data, - "schannel: decrypted data buffer: offset %zu length %zu\n", + "schannel: decrypted data buffer: offset %zu length %zu", BACKEND->decdata_offset, BACKEND->decdata_length)); *err = CURLE_OK; return (ssize_t)size; @@ -2139,7 +2155,7 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn, DEBUGASSERT(data); - infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n", + infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu", hostname, conn->remote_port); if(BACKEND->cred && BACKEND->ctxt) { @@ -2197,14 +2213,14 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn, s_pSecFn->FreeContextBuffer(outbuf.pvBuffer); if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) { infof(data, "schannel: failed to send close msg: %s" - " (bytes written: %zd)\n", curl_easy_strerror(result), written); + " (bytes written: %zd)", curl_easy_strerror(result), written); } } } /* free SSPI Schannel API security context handle */ if(BACKEND->ctxt) { - DEBUGF(infof(data, "schannel: clear security context handle\n")); + DEBUGF(infof(data, "schannel: clear security context handle")); s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle); Curl_safefree(BACKEND->ctxt); } diff --git a/Utilities/cmcurl/lib/vtls/schannel_verify.c b/Utilities/cmcurl/lib/vtls/schannel_verify.c index 25d47b8..1b283d0 100644 --- a/Utilities/cmcurl/lib/vtls/schannel_verify.c +++ b/Utilities/cmcurl/lib/vtls/schannel_verify.c @@ -80,7 +80,7 @@ static int is_cr_or_lf(char c) /* Search the substring needle,needlelen into string haystack,haystacklen * Strings don't need to be terminated by a '\0'. * Similar of OSX/Linux memmem (not available on Visual Studio). - * Return position of beginning of first occurence or NULL if not found + * Return position of beginning of first occurrence or NULL if not found */ static const char *c_memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) @@ -204,12 +204,12 @@ static CURLcode add_certs_data_to_store(HCERTSTORE trust_store, if(result == CURLE_OK) { if(!num_certs) { infof(data, - "schannel: did not add any certificates from CA file '%s'\n", + "schannel: did not add any certificates from CA file '%s'", ca_file_text); } else { infof(data, - "schannel: added %d certificate(s) from CA file '%s'\n", + "schannel: added %d certificate(s) from CA file '%s'", num_certs, ca_file_text); } } @@ -526,7 +526,7 @@ static CURLcode verify_host(struct Curl_easy *data, if(match_result == CURL_HOST_MATCH) { infof(data, "schannel: connection hostname (%s) validated " - "against certificate name (%s)\n", + "against certificate name (%s)", conn_hostname, cert_hostname); result = CURLE_OK; } @@ -535,7 +535,7 @@ static CURLcode verify_host(struct Curl_easy *data, infof(data, "schannel: connection hostname (%s) did not match " - "against certificate name (%s)\n", + "against certificate name (%s)", conn_hostname, cert_hostname); cert_hostname_len = diff --git a/Utilities/cmcurl/lib/vtls/sectransp.c b/Utilities/cmcurl/lib/vtls/sectransp.c index edd375e..1e6ed5f 100644 --- a/Utilities/cmcurl/lib/vtls/sectransp.c +++ b/Utilities/cmcurl/lib/vtls/sectransp.c @@ -32,6 +32,9 @@ #include "curl_base64.h" #include "strtok.h" #include "multiif.h" +#include "strcase.h" +#include "x509asn1.h" +#include "strerror.h" #ifdef USE_SECTRANSP @@ -1644,7 +1647,7 @@ static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data, } } /* All cipher suites in the list are found. Report to logs as-is */ - infof(data, "SSL: Setting cipher suites list \"%s\"\n", ciphers); + infof(data, "SSL: Setting cipher suites list \"%s\"", ciphers); err = SSLSetEnabledCiphers(ssl_ctx, selected_ciphers, ciphers_count); if(err != noErr) { @@ -1840,19 +1843,19 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, #endif ) { CFArrayAppendValue(alpnArr, CFSTR(ALPN_H2)); - infof(data, "ALPN, offering %s\n", ALPN_H2); + infof(data, "ALPN, offering %s", ALPN_H2); } #endif CFArrayAppendValue(alpnArr, CFSTR(ALPN_HTTP_1_1)); - infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + infof(data, "ALPN, offering %s", ALPN_HTTP_1_1); /* expects length prefixed preference ordered list of protocols in wire * format */ err = SSLSetALPNProtocols(backend->ssl_ctx, alpnArr); if(err != noErr) - infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d\n", + infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d", err); CFRelease(alpnArr); } @@ -1861,7 +1864,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, if(SSL_SET_OPTION(key)) { infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure " - "Transport. The private key must be in the Keychain.\n"); + "Transport. The private key must be in the Keychain."); } if(ssl_cert || ssl_cert_blob) { @@ -1869,24 +1872,28 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, bool is_cert_file = (!is_cert_data) && is_file(ssl_cert); SecIdentityRef cert_and_key = NULL; - /* User wants to authenticate with a client cert. Look for it: - If we detect that this is a file on disk, then let's load it. - Otherwise, assume that the user wants to use an identity loaded - from the Keychain. */ - if(is_cert_file || is_cert_data) { + /* User wants to authenticate with a client cert. Look for it. Assume that + the user wants to use an identity loaded from the Keychain. If not, try + it as a file on disk */ + + if(!is_cert_data) + err = CopyIdentityWithLabel(ssl_cert, &cert_and_key); + else + err = !noErr; + if((err != noErr) && (is_cert_file || is_cert_data)) { if(!SSL_SET_OPTION(cert_type)) - infof(data, "WARNING: SSL: Certificate type not set, assuming " - "PKCS#12 format.\n"); - else if(strncmp(SSL_SET_OPTION(cert_type), "P12", - strlen(SSL_SET_OPTION(cert_type))) != 0) - infof(data, "WARNING: SSL: The Security framework only supports " - "loading identities that are in PKCS#12 format.\n"); + infof(data, "SSL: Certificate type not set, assuming " + "PKCS#12 format."); + else if(!strcasecompare(SSL_SET_OPTION(cert_type), "P12")) { + failf(data, "SSL: The Security framework only supports " + "loading identities that are in PKCS#12 format."); + return CURLE_SSL_CERTPROBLEM; + } err = CopyIdentityFromPKCS12File(ssl_cert, ssl_cert_blob, - SSL_SET_OPTION(key_passwd), &cert_and_key); + SSL_SET_OPTION(key_passwd), + &cert_and_key); } - else - err = CopyIdentityWithLabel(ssl_cert, &cert_and_key); if(err == noErr && cert_and_key) { SecCertificateRef cert = NULL; @@ -1899,7 +1906,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, char *certp; CURLcode result = CopyCertSubject(data, cert, &certp); if(!result) { - infof(data, "Client certificate: %s\n", certp); + infof(data, "Client certificate: %s", certp); free(certp); } @@ -2025,7 +2032,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, strlen(hostname)); if(err != noErr) { - infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d\n", + infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d", err); } @@ -2035,11 +2042,11 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, #endif ) { infof(data, "WARNING: using IP address, SNI is being disabled by " - "the OS.\n"); + "the OS."); } } else { - infof(data, "WARNING: disabling hostname validation also disables SNI.\n"); + infof(data, "WARNING: disabling hostname validation also disables SNI."); } ciphers = SSL_CONN_CONFIG(cipher_list); @@ -2082,7 +2089,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, return CURLE_SSL_CONNECT_ERROR; } /* Informational message */ - infof(data, "SSL re-using session ID\n"); + infof(data, "SSL re-using session ID"); } /* If there isn't one, then let's make one up! This has to be done prior to starting the handshake. */ @@ -2487,7 +2494,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, spkiHeaderLength = 23; break; default: - infof(data, "SSL: unhandled public key length: %d\n", pubkeylen); + infof(data, "SSL: unhandled public key length: %d", pubkeylen); #elif SECTRANSP_PINNEDPUBKEY_V2 default: /* ecDSA secp256r1 pubkeylen == 91 header already included? @@ -2778,35 +2785,35 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn, (void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol); switch(protocol) { case kSSLProtocol2: - infof(data, "SSL 2.0 connection using %s\n", + infof(data, "SSL 2.0 connection using %s", TLSCipherNameForNumber(cipher)); break; case kSSLProtocol3: - infof(data, "SSL 3.0 connection using %s\n", + infof(data, "SSL 3.0 connection using %s", TLSCipherNameForNumber(cipher)); break; case kTLSProtocol1: - infof(data, "TLS 1.0 connection using %s\n", + infof(data, "TLS 1.0 connection using %s", TLSCipherNameForNumber(cipher)); break; #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS case kTLSProtocol11: - infof(data, "TLS 1.1 connection using %s\n", + infof(data, "TLS 1.1 connection using %s", TLSCipherNameForNumber(cipher)); break; case kTLSProtocol12: - infof(data, "TLS 1.2 connection using %s\n", + infof(data, "TLS 1.2 connection using %s", TLSCipherNameForNumber(cipher)); break; #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ #if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 case kTLSProtocol13: - infof(data, "TLS 1.3 connection using %s\n", + infof(data, "TLS 1.3 connection using %s", TLSCipherNameForNumber(cipher)); break; #endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */ default: - infof(data, "Unknown protocol connection\n"); + infof(data, "Unknown protocol connection"); break; } @@ -2832,7 +2839,7 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn, conn->negnpn = CURL_HTTP_VERSION_1_1; } else - infof(data, "ALPN, server did not agree to a protocol\n"); + infof(data, "ALPN, server did not agree to a protocol"); Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); @@ -2849,13 +2856,60 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn, } } +static CURLcode +add_cert_to_certinfo(struct Curl_easy *data, + SecCertificateRef server_cert, + int idx) +{ + CURLcode result = CURLE_OK; + const char *beg; + const char *end; + CFDataRef cert_data = SecCertificateCopyData(server_cert); + + if(!cert_data) + return CURLE_PEER_FAILED_VERIFICATION; + + beg = (const char *)CFDataGetBytePtr(cert_data); + end = beg + CFDataGetLength(cert_data); + result = Curl_extract_certinfo(data, idx, beg, end); + CFRelease(cert_data); + return result; +} + +static CURLcode +collect_server_cert_single(struct Curl_easy *data, + SecCertificateRef server_cert, + CFIndex idx) +{ + CURLcode result = CURLE_OK; #ifndef CURL_DISABLE_VERBOSE_STRINGS + if(data->set.verbose) { + char *certp; + result = CopyCertSubject(data, server_cert, &certp); + if(!result) { + infof(data, "Server certificate: %s", certp); + free(certp); + } + } +#endif + if(data->set.ssl.certinfo) + result = add_cert_to_certinfo(data, server_cert, (int)idx); + return result; +} + /* This should be called during step3 of the connection at the earliest */ -static void -show_verbose_server_cert(struct Curl_easy *data, - struct connectdata *conn, - int sockindex) +static CURLcode +collect_server_cert(struct Curl_easy *data, + struct connectdata *conn, + int sockindex) { +#ifndef CURL_DISABLE_VERBOSE_STRINGS + const bool show_verbose_server_cert = data->set.verbose; +#else + const bool show_verbose_server_cert = false; +#endif + CURLcode result = data->set.ssl.certinfo ? + CURLE_PEER_FAILED_VERIFICATION : CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_backend_data *backend = connssl->backend; CFArrayRef server_certs = NULL; @@ -2864,8 +2918,11 @@ show_verbose_server_cert(struct Curl_easy *data, CFIndex i, count; SecTrustRef trust = NULL; + if(!show_verbose_server_cert && !data->set.ssl.certinfo) + return CURLE_OK; + if(!backend->ssl_ctx) - return; + return result; #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS #if CURL_BUILD_IOS @@ -2875,15 +2932,11 @@ show_verbose_server_cert(struct Curl_easy *data, a null trust, so be on guard for that: */ if(err == noErr && trust) { count = SecTrustGetCertificateCount(trust); - for(i = 0L ; i < count ; i++) { - CURLcode result; - char *certp; + if(data->set.ssl.certinfo) + result = Curl_ssl_init_certinfo(data, (int)count); + for(i = 0L ; !result && (i < count) ; i++) { server_cert = SecTrustGetCertificateAtIndex(trust, i); - result = CopyCertSubject(data, server_cert, &certp); - if(!result) { - infof(data, "Server certificate: %s\n", certp); - free(certp); - } + result = collect_server_cert_single(data, server_cert, i); } CFRelease(trust); } @@ -2901,15 +2954,11 @@ show_verbose_server_cert(struct Curl_easy *data, a null trust, so be on guard for that: */ if(err == noErr && trust) { count = SecTrustGetCertificateCount(trust); - for(i = 0L ; i < count ; i++) { - char *certp; - CURLcode result; + if(data->set.ssl.certinfo) + result = Curl_ssl_init_certinfo(data, (int)count); + for(i = 0L ; !result && (i < count) ; i++) { server_cert = SecTrustGetCertificateAtIndex(trust, i); - result = CopyCertSubject(data, server_cert, &certp); - if(!result) { - infof(data, "Server certificate: %s\n", certp); - free(certp); - } + result = collect_server_cert_single(data, server_cert, i); } CFRelease(trust); } @@ -2920,16 +2969,12 @@ show_verbose_server_cert(struct Curl_easy *data, /* Just in case SSLCopyPeerCertificates() returns null too... */ if(err == noErr && server_certs) { count = CFArrayGetCount(server_certs); - for(i = 0L ; i < count ; i++) { - char *certp; - CURLcode result; + if(data->set.ssl.certinfo) + result = Curl_ssl_init_certinfo(data, (int)count); + for(i = 0L ; !result && (i < count) ; i++) { server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i); - result = CopyCertSubject(data, server_cert, &certp); - if(!result) { - infof(data, "Server certificate: %s\n", certp); - free(certp); - } + result = collect_server_cert_single(data, server_cert, i); } CFRelease(server_certs); } @@ -2941,21 +2986,17 @@ show_verbose_server_cert(struct Curl_easy *data, err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs); if(err == noErr) { count = CFArrayGetCount(server_certs); - for(i = 0L ; i < count ; i++) { - CURLcode result; - char *certp; + if(data->set.ssl.certinfo) + result = Curl_ssl_init_certinfo(data, (int)count); + for(i = 0L ; !result && (i < count) ; i++) { server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i); - result = CopyCertSubject(data, server_cert, &certp); - if(!result) { - infof(data, "Server certificate: %s\n", certp); - free(certp); - } + result = collect_server_cert_single(data, server_cert, i); } CFRelease(server_certs); } #endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ + return result; } -#endif /* !CURL_DISABLE_VERBOSE_STRINGS */ static CURLcode sectransp_connect_step3(struct Curl_easy *data, struct connectdata *conn, @@ -2964,12 +3005,11 @@ sectransp_connect_step3(struct Curl_easy *data, struct connectdata *conn, struct ssl_connect_data *connssl = &conn->ssl[sockindex]; /* There is no step 3! - * Well, okay, if verbose mode is on, let's print the details of the - * server certificates. */ -#ifndef CURL_DISABLE_VERBOSE_STRINGS - if(data->set.verbose) - show_verbose_server_cert(data, conn, sockindex); -#endif + * Well, okay, let's collect server certificates, and if verbose mode is on, + * let's print the details of the server certificates. */ + const CURLcode result = collect_server_cert(data, conn, sockindex); + if(result) + return result; connssl->connecting_state = ssl_connect_done; return CURLE_OK; @@ -3148,6 +3188,7 @@ static int sectransp_shutdown(struct Curl_easy *data, int what; int rc; char buf[120]; + int loop = 10; /* avoid getting stuck */ if(!backend->ssl_ctx) return 0; @@ -3163,7 +3204,7 @@ static int sectransp_shutdown(struct Curl_easy *data, what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); - for(;;) { + while(loop--) { if(what < 0) { /* anything that gets here is fatally bad */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -3182,7 +3223,9 @@ static int sectransp_shutdown(struct Curl_easy *data, nread = read(conn->sock[sockindex], buf, sizeof(buf)); if(nread < 0) { - failf(data, "read: %s", strerror(errno)); + char buffer[STRERROR_LEN]; + failf(data, "read: %s", + Curl_strerror(errno, buffer, sizeof(buffer))); rc = -1; } @@ -3427,6 +3470,7 @@ const struct Curl_ssl Curl_ssl_sectransp = { { CURLSSLBACKEND_SECURETRANSPORT, "secure-transport" }, /* info */ SSLSUPP_CAINFO_BLOB | + SSLSUPP_CERTINFO | #ifdef SECTRANSP_PINNEDPUBKEY SSLSUPP_PINNEDPUBKEY, #else diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c index 65f4f77..e5bbe1f 100644 --- a/Utilities/cmcurl/lib/vtls/vtls.c +++ b/Utilities/cmcurl/lib/vtls/vtls.c @@ -125,6 +125,16 @@ static bool blobcmp(struct curl_blob *first, struct curl_blob *second) return !memcmp(first->data, second->data, first->len); /* same data */ } +static bool safecmp(char *a, char *b) +{ + if(a && b) + return !strcmp(a, b); + else if(!a && !b) + return TRUE; /* match */ + return FALSE; /* no match */ +} + + bool Curl_ssl_config_matches(struct ssl_primary_config *data, struct ssl_primary_config *needle) @@ -136,11 +146,13 @@ Curl_ssl_config_matches(struct ssl_primary_config *data, (data->verifystatus == needle->verifystatus) && blobcmp(data->cert_blob, needle->cert_blob) && blobcmp(data->ca_info_blob, needle->ca_info_blob) && - Curl_safe_strcasecompare(data->CApath, needle->CApath) && - Curl_safe_strcasecompare(data->CAfile, needle->CAfile) && - Curl_safe_strcasecompare(data->clientcert, needle->clientcert) && - Curl_safe_strcasecompare(data->random_file, needle->random_file) && - Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) && + blobcmp(data->issuercert_blob, needle->issuercert_blob) && + safecmp(data->CApath, needle->CApath) && + safecmp(data->CAfile, needle->CAfile) && + safecmp(data->issuercert, needle->issuercert) && + safecmp(data->clientcert, needle->clientcert) && + safecmp(data->random_file, needle->random_file) && + safecmp(data->egdsocket, needle->egdsocket) && Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) && Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) && Curl_safe_strcasecompare(data->curves, needle->curves) && @@ -163,8 +175,10 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source, CLONE_BLOB(cert_blob); CLONE_BLOB(ca_info_blob); + CLONE_BLOB(issuercert_blob); CLONE_STRING(CApath); CLONE_STRING(CAfile); + CLONE_STRING(issuercert); CLONE_STRING(clientcert); CLONE_STRING(random_file); CLONE_STRING(egdsocket); @@ -180,6 +194,7 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc) { Curl_safefree(sslc->CApath); Curl_safefree(sslc->CAfile); + Curl_safefree(sslc->issuercert); Curl_safefree(sslc->clientcert); Curl_safefree(sslc->random_file); Curl_safefree(sslc->egdsocket); @@ -188,6 +203,7 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc) Curl_safefree(sslc->pinned_key); Curl_safefree(sslc->cert_blob); Curl_safefree(sslc->ca_info_blob); + Curl_safefree(sslc->issuercert_blob); Curl_safefree(sslc->curves); } @@ -326,7 +342,7 @@ Curl_ssl_connect(struct Curl_easy *data, struct connectdata *conn, CURLcode Curl_ssl_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn, - int sockindex, bool *done) + bool isproxy, int sockindex, bool *done) { CURLcode result; @@ -345,7 +361,7 @@ Curl_ssl_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn, result = Curl_ssl->connect_nonblocking(data, conn, sockindex, done); if(result) conn->ssl[sockindex].use = FALSE; - else if(*done) + else if(*done && !isproxy) Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSL is connected */ return result; } @@ -407,8 +423,9 @@ bool Curl_ssl_getsessionid(struct Curl_easy *data, DEBUGASSERT(SSL_SET_OPTION(primary.sessionid)); - if(!SSL_SET_OPTION(primary.sessionid)) - /* session ID re-use is disabled */ + if(!SSL_SET_OPTION(primary.sessionid) || !data->state.session) + /* session ID re-use is disabled or the session cache has not been + setup */ return TRUE; /* Lock if shared */ @@ -443,6 +460,10 @@ bool Curl_ssl_getsessionid(struct Curl_easy *data, } } + DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d", + no_match? "Didn't find": "Found", + isProxy ? "proxy" : "host", + conn->handler->scheme, name, port)); return no_match; } @@ -492,14 +513,14 @@ void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid) */ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data, struct connectdata *conn, - bool isProxy, + const bool isProxy, void *ssl_sessionid, size_t idsize, int sockindex) { size_t i; - struct Curl_ssl_session *store = &data->state.session[0]; - long oldest_age = data->state.session[0].age; /* zero if unused */ + struct Curl_ssl_session *store; + long oldest_age; char *clone_host; char *clone_conn_to_host; int conn_to_port; @@ -515,6 +536,11 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data, const char *hostname = conn->host.name; #endif (void)sockindex; + if(!data->state.session) + return CURLE_OK; + + store = &data->state.session[0]; + oldest_age = data->state.session[0].age; /* zero if unused */ DEBUGASSERT(SSL_SET_OPTION(primary.sessionid)); clone_host = strdup(hostname); @@ -583,6 +609,9 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } + DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]", + store->scheme, store->name, store->remote_port, + isProxy ? "PROXY" : "server")); return CURLE_OK; } @@ -708,12 +737,12 @@ CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount) static size_t multissl_version(char *buffer, size_t size); -size_t Curl_ssl_version(char *buffer, size_t size) +void Curl_ssl_version(char *buffer, size_t size) { #ifdef CURL_WITH_MULTI_SSL - return multissl_version(buffer, size); + (void)multissl_version(buffer, size); #else - return Curl_ssl->version(buffer, size); + (void)Curl_ssl->version(buffer, size); #endif } @@ -940,7 +969,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, if(encode) return encode; - infof(data, "\t public key hash: sha256//%s\n", encoded); + infof(data, " public key hash: sha256//%s", encoded); /* it starts with sha256//, copy so we can modify it */ pinkeylen = strlen(pinnedpubkey) + 1; @@ -1374,7 +1403,7 @@ static int multissl_setup(const struct Curl_ssl *backend) for(i = 0; available_backends[i]; i++) { if(strcasecompare(env, available_backends[i]->info.name)) { Curl_ssl = available_backends[i]; - curl_free(env_tmp); + free(env_tmp); return 0; } } @@ -1382,7 +1411,7 @@ static int multissl_setup(const struct Curl_ssl *backend) /* Fall back to first available backend */ Curl_ssl = available_backends[0]; - curl_free(env_tmp); + free(env_tmp); return 0; } diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h index 7f93e7a..beaa83d 100644 --- a/Utilities/cmcurl/lib/vtls/vtls.h +++ b/Utilities/cmcurl/lib/vtls/vtls.h @@ -193,6 +193,7 @@ CURLcode Curl_ssl_connect(struct Curl_easy *data, struct connectdata *conn, int sockindex); CURLcode Curl_ssl_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn, + bool isproxy, int sockindex, bool *done); /* tell the SSL stuff to close down all open information regarding @@ -209,7 +210,7 @@ struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data); /* init the SSL session ID cache */ CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t); -size_t Curl_ssl_version(char *buffer, size_t size); +void Curl_ssl_version(char *buffer, size_t size); bool Curl_ssl_data_pending(const struct connectdata *conn, int connindex); int Curl_ssl_check_cxn(struct connectdata *conn); @@ -246,7 +247,7 @@ void Curl_ssl_sessionid_unlock(struct Curl_easy *data); */ bool Curl_ssl_getsessionid(struct Curl_easy *data, struct connectdata *conn, - const bool isproxy, + const bool isProxy, void **ssl_sessionid, size_t *idsize, /* set 0 if unknown */ int sockindex); @@ -313,7 +314,7 @@ void Curl_ssl_detach_conn(struct Curl_easy *data, #define Curl_ssl_data_pending(x,y) 0 #define Curl_ssl_check_cxn(x) 0 #define Curl_ssl_free_certinfo(x) Curl_nop_stmt -#define Curl_ssl_connect_nonblocking(x,y,z,w) CURLE_NOT_BUILT_IN +#define Curl_ssl_connect_nonblocking(x,y,z,w,a) CURLE_NOT_BUILT_IN #define Curl_ssl_kill_session(x) Curl_nop_stmt #define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN) #define Curl_ssl_cert_status_request() FALSE diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.c b/Utilities/cmcurl/lib/vtls/wolfssl.c index 60e27e3..16fbb89 100644 --- a/Utilities/cmcurl/lib/vtls/wolfssl.c +++ b/Utilities/cmcurl/lib/vtls/wolfssl.c @@ -239,7 +239,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, req_method = SSLv23_client_method(); #else infof(data, "wolfSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, " - "TLS 1.0 is used exclusively\n"); + "TLS 1.0 is used exclusively"); req_method = TLSv1_client_method(); #endif use_sni(TRUE); @@ -324,7 +324,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, failf(data, "failed setting cipher list: %s", ciphers); return CURLE_SSL_CIPHER; } - infof(data, "Cipher selection: %s\n", ciphers); + infof(data, "Cipher selection: %s", ciphers); } #ifndef NO_FILESYSTEM @@ -347,16 +347,16 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, /* Just continue with a warning if no strict certificate verification is required. */ infof(data, "error setting certificate verify locations," - " continuing anyway:\n"); + " continuing anyway:"); } } else { /* Everything is fine. */ - infof(data, "successfully set certificate verify locations:\n"); + infof(data, "successfully set certificate verify locations:"); } - infof(data, " CAfile: %s\n", + infof(data, " CAfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile) : "none"); - infof(data, " CApath: %s\n", + infof(data, " CApath: %s", SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath) : "none"); } @@ -406,7 +406,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, (wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, hostname, (unsigned short)hostname_len) != 1)) { infof(data, "WARNING: failed to configure server name indication (SNI) " - "TLS extension\n"); + "TLS extension"); } } #endif @@ -450,12 +450,12 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, #ifdef USE_HTTP2 if(data->state.httpwant >= CURL_HTTP_VERSION_2) { strcpy(protocols + strlen(protocols), ALPN_H2 ","); - infof(data, "ALPN, offering %s\n", ALPN_H2); + infof(data, "ALPN, offering %s", ALPN_H2); } #endif strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1); - infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + infof(data, "ALPN, offering %s", ALPN_HTTP_1_1); if(wolfSSL_UseALPN(backend->handle, protocols, (unsigned)strlen(protocols), @@ -494,15 +494,11 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, &ssl_sessionid, NULL, sockindex)) { /* we got a session id, use it! */ if(!SSL_set_session(backend->handle, ssl_sessionid)) { - char error_buffer[WOLFSSL_MAX_ERROR_SZ]; - Curl_ssl_sessionid_unlock(data); - failf(data, "SSL: SSL_set_session failed: %s", - ERR_error_string(SSL_get_error(backend->handle, 0), - error_buffer)); - return CURLE_SSL_CONNECT_ERROR; + Curl_ssl_delsessionid(data, ssl_sessionid); + infof(data, "Can't use session ID, going on without\n"); } - /* Informational message */ - infof(data, "SSL re-using session ID\n"); + else + infof(data, "SSL re-using session ID"); } Curl_ssl_sessionid_unlock(data); } @@ -529,6 +525,8 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, const char * const dispname = SSL_HOST_DISPNAME(); const char * const pinnedpubkey = SSL_PINNED_PUB_KEY(); + ERR_clear_error(); + conn->recv[sockindex] = wolfssl_recv; conn->send[sockindex] = wolfssl_send; @@ -582,7 +580,7 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, * as also mismatching CN fields */ else if(DOMAIN_NAME_MISMATCH == detail) { #if 1 - failf(data, "\tsubject alt name(s) or common name do not match \"%s\"", + failf(data, " subject alt name(s) or common name do not match \"%s\"", dispname); return CURLE_PEER_FAILED_VERIFICATION; #else @@ -594,13 +592,13 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, * 'conn->ssl_config.verifyhost' value. */ if(SSL_CONN_CONFIG(verifyhost)) { failf(data, - "\tsubject alt name(s) or common name do not match \"%s\"\n", + " subject alt name(s) or common name do not match \"%s\"\n", dispname); return CURLE_PEER_FAILED_VERIFICATION; } else { infof(data, - "\tsubject alt name(s) and/or common name do not match \"%s\"\n", + " subject alt name(s) and/or common name do not match \"%s\"", dispname); return CURLE_OK; } @@ -609,14 +607,14 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, #if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */ else if(ASN_NO_SIGNER_E == detail) { if(SSL_CONN_CONFIG(verifypeer)) { - failf(data, "\tCA signer not available for verification"); + failf(data, " CA signer not available for verification"); return CURLE_SSL_CACERT_BADFILE; } else { /* Just continue with a warning if no strict certificate verification is required. */ infof(data, "CA signer not available for verification, " - "continuing anyway\n"); + "continuing anyway"); } } #endif @@ -681,7 +679,7 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len); if(rc == SSL_SUCCESS) { - infof(data, "ALPN, server accepted to use %.*s\n", protocol_len, + infof(data, "ALPN, server accepted to use %.*s", protocol_len, protocol); if(protocol_len == ALPN_HTTP_1_1_LENGTH && @@ -694,13 +692,13 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, conn->negnpn = CURL_HTTP_VERSION_2; #endif else - infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len, + infof(data, "ALPN, unrecognized protocol %.*s", protocol_len, protocol); Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } else if(rc == SSL_ALPN_NOT_FOUND) - infof(data, "ALPN, server did not agree to a protocol\n"); + infof(data, "ALPN, server did not agree to a protocol"); else { failf(data, "ALPN, failure getting protocol, error %d", rc); return CURLE_SSL_CONNECT_ERROR; @@ -710,11 +708,11 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, connssl->connecting_state = ssl_connect_3; #if (LIBWOLFSSL_VERSION_HEX >= 0x03009010) - infof(data, "SSL connection using %s / %s\n", + infof(data, "SSL connection using %s / %s", wolfSSL_get_version(backend->handle), wolfSSL_get_cipher_name(backend->handle)); #else - infof(data, "SSL connected\n"); + infof(data, "SSL connected"); #endif return CURLE_OK; @@ -743,7 +741,7 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn, &old_ssl_sessionid, NULL, sockindex)); if(incache) { if(old_ssl_sessionid != our_ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); + infof(data, "old SSL session ID is stale, removing"); Curl_ssl_delsessionid(data, old_ssl_sessionid); incache = FALSE; } @@ -779,7 +777,11 @@ static ssize_t wolfssl_send(struct Curl_easy *data, struct ssl_backend_data *backend = connssl->backend; char error_buffer[WOLFSSL_MAX_ERROR_SZ]; int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; - int rc = SSL_write(backend->handle, mem, memlen); + int rc; + + ERR_clear_error(); + + rc = SSL_write(backend->handle, mem, memlen); if(rc <= 0) { int err = SSL_get_error(backend->handle, rc); @@ -810,6 +812,10 @@ static void wolfssl_close(struct Curl_easy *data, struct connectdata *conn, (void) data; if(backend->handle) { + char buf[32]; + /* Maybe the server has already sent a close notify alert. + Read it to avoid an RST on the TCP connection. */ + (void)SSL_read(backend->handle, buf, (int)sizeof(buf)); (void)SSL_shutdown(backend->handle); SSL_free(backend->handle); backend->handle = NULL; @@ -831,7 +837,11 @@ static ssize_t wolfssl_recv(struct Curl_easy *data, struct ssl_backend_data *backend = connssl->backend; char error_buffer[WOLFSSL_MAX_ERROR_SZ]; int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - int nread = SSL_read(backend->handle, buf, buffsize); + int nread; + + ERR_clear_error(); + + nread = SSL_read(backend->handle, buf, buffsize); if(nread < 0) { int err = SSL_get_error(backend->handle, nread); @@ -916,6 +926,7 @@ static int wolfssl_shutdown(struct Curl_easy *data, struct connectdata *conn, (void) data; if(backend->handle) { + ERR_clear_error(); SSL_free(backend->handle); backend->handle = NULL; } @@ -1089,7 +1100,7 @@ static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */ } static void *wolfssl_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) + CURLINFO info UNUSED_PARAM) { struct ssl_backend_data *backend = connssl->backend; (void)info; |