]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
sectransp: support CURLINFO_CERTINFO
authorSergey Markelov <sergey@solidstatenetworks.com>
Sat, 10 Jul 2021 00:30:38 +0000 (17:30 -0700)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 17 Aug 2021 06:40:44 +0000 (08:40 +0200)
Fixes #4130
Closes #7372

docs/libcurl/opts/CURLINFO_CERTINFO.3
docs/libcurl/opts/CURLOPT_CERTINFO.3
lib/vtls/sectransp.c
lib/x509asn1.c
lib/x509asn1.h

index 8f5be245e41d231f612153668fb974dada6e426d..164e88a045031e11820956f0efa37808f5d6d721 100644 (file)
@@ -71,8 +71,9 @@ if(curl) {
 }
 .fi
 .SH AVAILABILITY
-This option is only working in libcurl built with OpenSSL, NSS, Schannel or
-GSKit support. Schannel support added in 7.50.0
+This option is only working in libcurl built with OpenSSL, NSS, Schannel, GSKit
+or Secure Transport support. Schannel support added in 7.50.0. Secure Transport
+support added in 7.79.0.
 
 Added in 7.19.1
 .SH RETURN VALUE
index 1cd541e830196a1024c047e5244aa7d535b78799..cc280c498e4f36b0608034a7a2224bfbcb2354c6 100644 (file)
@@ -70,8 +70,9 @@ if(curl) {
 }
 .fi
 .SH AVAILABILITY
-This option is supported by the OpenSSL, GnuTLS, Schannel, NSS and GSKit
-backends.
+This option is supported by the OpenSSL, GnuTLS, Schannel, NSS, GSKit and
+Secure Transport backends. Schannel support added in 7.50.0. Secure Transport
+support added in 7.79.0.
 .SH RETURN VALUE
 Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
 .SH "SEE ALSO"
index 26b833dd2ac7badf9e36a2d392e3792be0a6ec83..23b9fad94f00d71bc6604e022dda50c5c17f1bc0 100644 (file)
@@ -33,6 +33,7 @@
 #include "strtok.h"
 #include "multiif.h"
 #include "strcase.h"
+#include "x509asn1.h"
 
 #ifdef USE_SECTRANSP
 
@@ -2854,13 +2855,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;
@@ -2869,8 +2917,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
@@ -2880,15 +2931,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", certp);
-        free(certp);
-      }
+      result = collect_server_cert_single(data, server_cert, i);
     }
     CFRelease(trust);
   }
@@ -2906,15 +2953,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", certp);
-          free(certp);
-        }
+        result = collect_server_cert_single(data, server_cert, i);
       }
       CFRelease(trust);
     }
@@ -2925,16 +2968,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", certp);
-          free(certp);
-        }
+        result = collect_server_cert_single(data, server_cert, i);
       }
       CFRelease(server_certs);
     }
@@ -2946,21 +2985,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", 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,
@@ -2969,12 +3004,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;
@@ -3433,6 +3467,7 @@ const struct Curl_ssl Curl_ssl_sectransp = {
   { CURLSSLBACKEND_SECURETRANSPORT, "secure-transport" }, /* info */
 
   SSLSUPP_CAINFO_BLOB |
+  SSLSUPP_CERTINFO |
 #ifdef SECTRANSP_PINNEDPUBKEY
   SSLSUPP_PINNEDPUBKEY,
 #else
index 9c3342dfcdaf04b519434a8b2aa72048ea3a488c..1bdaeadc80983d331ac3f32ed99874d9d55318a0 100644 (file)
@@ -23,7 +23,7 @@
 #include "curl_setup.h"
 
 #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \
-    defined(USE_WOLFSSL) || defined(USE_SCHANNEL)
+    defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
 
 #include <curl/curl.h>
 #include "urldata.h"
@@ -1104,7 +1104,8 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
   return CURLE_OK;
 }
 
-#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL */
+#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL
+        * or USE_SECTRANSP */
 
 #if defined(USE_GSKIT)
 
index 326e32d58819fde6620bb4f82266f0436b90fc4f..3b51eeef8dee2a637c499bb583904cf14debf7f0 100644 (file)
@@ -26,7 +26,7 @@
 #include "curl_setup.h"
 
 #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \
-    defined(USE_WOLFSSL) || defined(USE_SCHANNEL)
+    defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
 
 #include "urldata.h"
 
@@ -129,5 +129,6 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, int certnum,
                                const char *beg, const char *end);
 CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
                          const char *beg, const char *end);
-#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL */
+#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL
+        * or USE_SECTRANSP */
 #endif /* HEADER_CURL_X509ASN1_H */