]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
GnuTLS: Backend support for CURLINFO_SSL_VERIFYRESULT
authorEmil Engler <me@emilengler.com>
Thu, 23 Apr 2020 19:36:35 +0000 (21:36 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 30 Apr 2020 12:40:54 +0000 (14:40 +0200)
Closes #5287

docs/KNOWN_BUGS
docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.3
lib/vtls/gtls.c

index 93cb36902645d3737b645e70900096d253d1b9da..7bb27656608550c8d44f6b8d143443c00e1446b3 100644 (file)
@@ -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
 
index b0bd54cd8f0bf1d727b9f01f9b985fa0c0804ed7..d0957ae55e43dd961d1b1272292aba47e1f01d0d 100644 (file)
@@ -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"
index 4ed3ea5cfa2d37a28d04343ba81d212e4c7b12cf..85cd4dc224d7c890c630490164caa8c865a9e532 100644 (file)
@@ -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;
       }