From 42d8d9a7e816f14226819cdc2440e11ef004230e Mon Sep 17 00:00:00 2001 From: Emil Engler Date: Thu, 23 Apr 2020 21:36:35 +0200 Subject: GnuTLS: Backend support for CURLINFO_SSL_VERIFYRESULT Closes #5287 --- docs/KNOWN_BUGS | 4 ++-- docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.3 | 2 +- lib/vtls/gtls.c | 23 +++++++++++++++++++++-- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS index 93cb36902..7bb276566 100644 --- a/docs/KNOWN_BUGS +++ b/docs/KNOWN_BUGS @@ -200,8 +200,8 @@ problems may have been fixed or changed somewhat since this was written! 2.1 CURLINFO_SSL_VERIFYRESULT has limited support - CURLINFO_SSL_VERIFYRESULT is only implemented for the OpenSSL and NSS - backends, so relying on this information in a generic app is flaky. + CURLINFO_SSL_VERIFYRESULT is only implemented for the OpenSSL, NSS and + GnuTLS backends, so relying on this information in a generic app is flaky. 2.2 DER in keychain diff --git a/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.3 b/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.3 index b0bd54cd8..d0957ae55 100644 --- a/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.3 +++ b/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.3 @@ -50,7 +50,7 @@ if(curl) { } .fi .SH AVAILABILITY -Added in 7.5. Only set by the OpenSSL/libressl/boringssl and NSS backends. +Added in 7.5. Only set by the OpenSSL/libressl/boringssl, NSS and GnuTLS backends. .SH RETURN VALUE Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. .SH "SEE ALSO" diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 4ed3ea5cf..85cd4dc22 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -401,6 +401,8 @@ gtls_connect_step1(struct connectdata *conn, const char *err = NULL; const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; + long * const certverifyresult = SSL_IS_PROXY() ? + &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; if(connssl->state == ssl_connection_complete) /* to make us tolerant against being called more than once for the @@ -410,6 +412,9 @@ gtls_connect_step1(struct connectdata *conn, if(!gtls_inited) Curl_gtls_init(); + /* Initalize certverifyresult to OK */ + *certverifyresult = 0; + if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; @@ -458,8 +463,10 @@ gtls_connect_step1(struct connectdata *conn, if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc)); - if(SSL_CONN_CONFIG(verifypeer)) + if(SSL_CONN_CONFIG(verifypeer)) { + *certverifyresult = rc; return CURLE_SSL_CACERT_BADFILE; + } } else infof(data, "found %d certificates in %s\n", rc, @@ -474,8 +481,10 @@ gtls_connect_step1(struct connectdata *conn, if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", SSL_CONN_CONFIG(CApath), gnutls_strerror(rc)); - if(SSL_CONN_CONFIG(verifypeer)) + if(SSL_CONN_CONFIG(verifypeer)) { + *certverifyresult = rc; return CURLE_SSL_CACERT_BADFILE; + } } else infof(data, "found %d certificates in %s\n", @@ -821,6 +830,8 @@ gtls_connect_step3(struct connectdata *conn, #endif const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; + long * const certverifyresult = SSL_IS_PROXY() ? + &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */ ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session), @@ -852,6 +863,7 @@ gtls_connect_step3(struct connectdata *conn, else { #endif failf(data, "failed to get server cert"); + *certverifyresult = GNUTLS_E_NO_CERTIFICATE_FOUND; return CURLE_PEER_FAILED_VERIFICATION; #ifdef USE_TLS_SRP } @@ -888,9 +900,12 @@ gtls_connect_step3(struct connectdata *conn, rc = gnutls_certificate_verify_peers2(session, &verify_status); if(rc < 0) { failf(data, "server cert verify failed: %d", rc); + *certverifyresult = rc; return CURLE_SSL_CONNECT_ERROR; } + *certverifyresult = verify_status; + /* verify_status is a bitmask of gnutls_certificate_status bits */ if(verify_status & GNUTLS_CERT_INVALID) { if(SSL_CONN_CONFIG(verifypeer)) { @@ -1119,6 +1134,7 @@ gtls_connect_step3(struct connectdata *conn, if(certclock == (time_t)-1) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server cert expiration date verify failed"); + *certverifyresult = GNUTLS_CERT_EXPIRED; gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_CONNECT_ERROR; } @@ -1129,6 +1145,7 @@ gtls_connect_step3(struct connectdata *conn, if(certclock < time(NULL)) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server certificate expiration date has passed."); + *certverifyresult = GNUTLS_CERT_EXPIRED; gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; } @@ -1144,6 +1161,7 @@ gtls_connect_step3(struct connectdata *conn, if(certclock == (time_t)-1) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server cert activation date verify failed"); + *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED; gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_CONNECT_ERROR; } @@ -1154,6 +1172,7 @@ gtls_connect_step3(struct connectdata *conn, if(certclock > time(NULL)) { if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server certificate not activated yet."); + *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED; gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; } -- cgit v1.2.1