]> granicus.if.org Git - curl/commitdiff
NSS: support for CERTINFO feature
authorPatrick Monnerat <pm@datasphere.ch>
Wed, 30 Oct 2013 10:12:06 +0000 (11:12 +0100)
committerPatrick Monnerat <pm@datasphere.ch>
Wed, 30 Oct 2013 10:12:06 +0000 (11:12 +0100)
docs/libcurl/curl_easy_getinfo.3
docs/libcurl/curl_easy_setopt.3
lib/hostcheck.c
lib/nss.c
lib/url.c
lib/x509asn1.c
lib/x509asn1.h

index 62d8ae4826c5d2accf4fe21d617f09ed0a6eeae2..db0f4d62a97b70ebc89492f936ab0a169d3a6a56 100644 (file)
@@ -5,7 +5,7 @@
 .\" *                            | (__| |_| |  _ <| |___
 .\" *                             \___|\___/|_| \_\_____|
 .\" *
-.\" * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+.\" * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
 .\" *
 .\" * This software is licensed as described in the file COPYING, which
 .\" * you should have received as part of this distribution. The terms
@@ -219,8 +219,8 @@ done. The struct reports how many certs it found and then you can extract info
 for each of those certs by following the linked lists. The info chain is
 provided in a series of data in the format "name:content" where the content is
 for the specific named data. See also the certinfo.c example. NOTE: this
-option is only available in libcurl built with OpenSSL support. (Added in
-7.19.1)
+option is only available in libcurl built with OpenSSL, NSS, GSKit or QsoSSL
+support. (Added in 7.19.1)
 .IP CURLINFO_CONDITION_UNMET
 Pass a pointer to a long to receive the number 1 if the condition provided in
 the previous request didn't match (see \fICURLOPT_TIMECONDITION\fP). Alas, if
index f58c8fbfe1012df0ee4854b8e8bb8214a7dba140..2887483afde3d4b661529d8211e1c26623288a80 100644 (file)
@@ -2549,9 +2549,10 @@ is ignored.
 
 .IP CURLOPT_CERTINFO
 Pass a long set to 1 to enable libcurl's certificate chain info gatherer. With
-this enabled, libcurl (if built with OpenSSL) will extract lots of information
+this enabled, libcurl (if built with OpenSSL, NSS, GSKit or QsoSSL) will
+extract lots of information
 and data about the certificates in the certificate chain used in the SSL
-connection. This data is then possible to extract after a transfer using
+connection. This data may then be retrieved after a transfer using
 \fIcurl_easy_getinfo(3)\fP and its option \fICURLINFO_CERTINFO\fP. (Added in
 7.19.1)
 .IP CURLOPT_RANDOM_FILE
index abd1fa0c3c771510b93475184ab93000e16f3ec3..4be5baa9238a674566caad19e7c279153b0d41fd 100644 (file)
@@ -23,7 +23,7 @@
 #include "curl_setup.h"
 
 #if defined(USE_SSLEAY) || defined(USE_AXTLS) || defined(USE_QSOSSL) || \
-    defined(USE_GSKIT)
+    defined(USE_GSKIT) || defined(USE_NSS)
 /* these backends use functions from this file */
 
 #include "hostcheck.h"
@@ -94,4 +94,4 @@ int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
   return 0;
 }
 
-#endif /* SSLEAY or AXTLS or QSOSSL or GSKIT */
+#endif /* SSLEAY or AXTLS or QSOSSL or GSKIT or NSS */
index 43576e6d5e00cb8de5ab6dd47a3c06f560335dbb..2562fcfdbe6a80cb2ed284e577429cee24017fa1 100644 (file)
--- a/lib/nss.c
+++ b/lib/nss.c
@@ -653,6 +653,10 @@ static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
   SSLChannelInfo channel;
   SSLCipherSuiteInfo suite;
   CERTCertificate *cert;
+  CERTCertificate *cert2;
+  CERTCertificate *cert3;
+  PRTime now;
+  int i;
 
   if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
      SECSuccess && channel.length == sizeof channel &&
@@ -663,11 +667,45 @@ static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
     }
   }
 
-  infof(conn->data, "Server certificate:\n");
-
   cert = SSL_PeerCertificate(sock);
-  display_cert_info(conn->data, cert);
-  CERT_DestroyCertificate(cert);
+
+  if(cert) {
+    infof(conn->data, "Server certificate:\n");
+
+    if(!conn->data->set.ssl.certinfo) {
+      display_cert_info(conn->data, cert);
+      CERT_DestroyCertificate(cert);
+    }
+    else {
+      /* Count certificates in chain. */
+      now = PR_Now();
+      i = 1;
+      if(!cert->isRoot) {
+        cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
+        while(cert2) {
+          i++;
+          if(cert2->isRoot) {
+            CERT_DestroyCertificate(cert2);
+            break;
+          }
+          cert3 = CERT_FindCertIssuer(cert2, now, certUsageSSLCA);
+          CERT_DestroyCertificate(cert2);
+          cert2 = cert3;
+        }
+      }
+      Curl_ssl_init_certinfo(conn->data, i);
+      for(i = 0; cert; cert = cert2) {
+        Curl_extract_certinfo(conn, i++, cert->derCert.data,
+                              cert->derCert.data + cert->derCert.len);
+        if(cert->isRoot) {
+          CERT_DestroyCertificate(cert);
+          break;
+        }
+        cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
+        CERT_DestroyCertificate(cert);
+      }
+    }
+  }
 
   return;
 }
index e86fbc2523d8d8a3b927947f869875bcc0800680..03c76078b9f4b880f148af7c0542ac5ca2cede2b 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -1926,7 +1926,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     data->set.ssl.fsslctxp = va_arg(param, void *);
     break;
 #endif
-#if defined(USE_SSLEAY) || defined(USE_QSOSSL) || defined(USE_GSKIT)
+#if defined(USE_SSLEAY) || defined(USE_QSOSSL) || defined(USE_GSKIT) || \
+    defined(USE_NSS)
   case CURLOPT_CERTINFO:
     data->set.ssl.certinfo = (0 != va_arg(param, long))?TRUE:FALSE;
     break;
index 94b89b2be0e53a72e1683ab3ad030f5c2275917b..d6aa04596745c74ea15a6772fa01a9ef6dd8c46a 100644 (file)
@@ -22,7 +22,7 @@
 
 #include "curl_setup.h"
 
-#if defined(USE_QSOSSL) || defined(USE_GSKIT)
+#if defined(USE_QSOSSL) || defined(USE_GSKIT) || defined(USE_NSS)
 
 #include <curl/curl.h>
 #include "urldata.h"
@@ -803,7 +803,7 @@ static const char * dumpAlgo(curl_asn1Element * param,
   return OID2str(oid.beg, oid.end, TRUE);
 }
 
-static void do_pubkey_field(struct SessionHandle *data, int certnum,
+static void do_pubkey_field(struct SessionHandle * data, int certnum,
                             const char * label, curl_asn1Element * elem)
 {
   const char * output;
@@ -812,8 +812,10 @@ static void do_pubkey_field(struct SessionHandle *data, int certnum,
 
   output = Curl_ASN1tostr(elem, 0);
   if(output) {
-    Curl_ssl_push_certinfo(data, certnum, label, output);
-    infof(data, "   %s: %s\n", label, output);
+    if(data->set.ssl.certinfo)
+      Curl_ssl_push_certinfo(data, certnum, label, output);
+    if(!certnum)
+      infof(data, "   %s: %s\n", label, output);
     free((char *) output);
   }
 }
@@ -845,11 +847,14 @@ static void do_pubkey(struct SessionHandle * data, int certnum,
         len--;
     if(len > 32)
       elem.beg = q;     /* Strip leading zero bytes. */
-    infof(data, "   RSA Public Key (%lu bits)\n", len);
-    q = curl_maprintf("%lu", len);
-    if(q) {
-      Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q);
-      free((char *) q);
+    if(!certnum)
+      infof(data, "   RSA Public Key (%lu bits)\n", len);
+    if(data->set.ssl.certinfo) {
+      q = curl_maprintf("%lu", len);
+      if(q) {
+        Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q);
+        free((char *) q);
+      }
     }
     /* Generate coefficients. */
     do_pubkey_field(data, certnum, "rsa(n)", &elem);
@@ -896,6 +901,10 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
   size_t i;
   size_t j;
 
+  if(!data->set.ssl.certinfo)
+    if(certnum)
+      return CURLE_OK;
+
   /* Prepare the certificate information for curl_easy_getinfo(). */
 
   /* Extract the certificate ASN.1 elements. */
@@ -905,35 +914,44 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
   ccp = Curl_DNtostr(&cert.subject);
   if(!ccp)
     return CURLE_OUT_OF_MEMORY;
-  Curl_ssl_push_certinfo(data, certnum, "Subject", ccp);
-  infof(data, "%2d Subject: %s\n", certnum, ccp);
+  if(data->set.ssl.certinfo)
+    Curl_ssl_push_certinfo(data, certnum, "Subject", ccp);
+  if(!certnum)
+    infof(data, "%2d Subject: %s\n", certnum, ccp);
   free((char *) ccp);
 
   /* Issuer. */
   ccp = Curl_DNtostr(&cert.issuer);
   if(!ccp)
     return CURLE_OUT_OF_MEMORY;
-  Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp);
-  infof(data, "   Issuer: %s\n", ccp);
+  if(data->set.ssl.certinfo)
+    Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp);
+  if(!certnum)
+    infof(data, "   Issuer: %s\n", ccp);
   free((char *) ccp);
 
   /* Version (always fits in less than 32 bits). */
   version = 0;
   for(ccp = cert.version.beg; ccp < cert.version.end; ccp++)
     version = (version << 8) | *(const unsigned char *) ccp;
-  ccp = curl_maprintf("%lx", version);
-  if(!ccp)
-    return CURLE_OUT_OF_MEMORY;
-  Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
-  free((char *) ccp);
-  infof(data, "   Version: %lu (0x%lx)\n", version + 1, version);
+  if(data->set.ssl.certinfo) {
+    ccp = curl_maprintf("%lx", version);
+    if(!ccp)
+      return CURLE_OUT_OF_MEMORY;
+    Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
+    free((char *) ccp);
+  }
+  if(!certnum)
+    infof(data, "   Version: %lu (0x%lx)\n", version + 1, version);
 
   /* Serial number. */
   ccp = Curl_ASN1tostr(&cert.serialNumber, 0);
   if(!ccp)
     return CURLE_OUT_OF_MEMORY;
-  Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp);
-  infof(data, "   Serial Number: %s\n", ccp);
+  if(data->set.ssl.certinfo)
+    Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp);
+  if(!certnum)
+    infof(data, "   Serial Number: %s\n", ccp);
   free((char *) ccp);
 
   /* Signature algorithm .*/
@@ -941,24 +959,30 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
                  cert.signatureAlgorithm.end);
   if(!ccp)
     return CURLE_OUT_OF_MEMORY;
-  Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
-  infof(data, "   Signature Algorithm: %s\n", ccp);
+  if(data->set.ssl.certinfo)
+    Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
+  if(!certnum)
+    infof(data, "   Signature Algorithm: %s\n", ccp);
   free((char *) ccp);
 
   /* Start Date. */
   ccp = Curl_ASN1tostr(&cert.notBefore, 0);
   if(!ccp)
     return CURLE_OUT_OF_MEMORY;
-  Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp);
-  infof(data, "   Start Date: %s\n", ccp);
+  if(data->set.ssl.certinfo)
+    Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp);
+  if(!certnum)
+    infof(data, "   Start Date: %s\n", ccp);
   free((char *) ccp);
 
   /* Expire Date. */
   ccp = Curl_ASN1tostr(&cert.notAfter, 0);
   if(!ccp)
     return CURLE_OUT_OF_MEMORY;
-  Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp);
-  infof(data, "   Expire Date: %s\n", ccp);
+  if(data->set.ssl.certinfo)
+    Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp);
+  if(!certnum)
+    infof(data, "   Expire Date: %s\n", ccp);
   free((char *) ccp);
 
   /* Public Key Algorithm. */
@@ -966,8 +990,10 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
                  cert.subjectPublicKeyAlgorithm.end);
   if(!ccp)
     return CURLE_OUT_OF_MEMORY;
-  Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp);
-  infof(data, "   Public Key Algorithm: %s\n", ccp);
+  if(data->set.ssl.certinfo)
+    Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp);
+  if(!certnum)
+    infof(data, "   Public Key Algorithm: %s\n", ccp);
   do_pubkey(data, certnum, ccp, &param, &cert.subjectPublicKey);
   free((char *) ccp);
 
@@ -977,8 +1003,10 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
   ccp = Curl_ASN1tostr(&cert.signature, 0);
   if(!ccp)
     return CURLE_OUT_OF_MEMORY;
-  Curl_ssl_push_certinfo(data, certnum, "Signature", ccp);
-  infof(data, "   Signature: %s\n", ccp);
+  if(data->set.ssl.certinfo)
+    Curl_ssl_push_certinfo(data, certnum, "Signature", ccp);
+  if(!certnum)
+    infof(data, "   Signature: %s\n", ccp);
   free((char *) ccp);
 
   /* Generate PEM certificate. */
@@ -987,7 +1015,7 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
                           &cp1, &cl1);
   if(cc != CURLE_OK)
     return cc;
-  /* Compute the number of charaters in final certificate string. Format is:
+  /* Compute the number of characters in final certificate string. Format is:
      -----BEGIN CERTIFICATE-----\n
      <max 64 base64 characters>\n
      .
@@ -1008,8 +1036,10 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
   i += copySubstring(cp2 + i, "-----END CERTIFICATE-----");
   cp2[i] = '\0';
   free(cp1);
-  Curl_ssl_push_certinfo(data, certnum, "Cert", cp2);
-  infof(data, "%s\n", cp2);
+  if(data->set.ssl.certinfo)
+    Curl_ssl_push_certinfo(data, certnum, "Cert", cp2);
+  if(!certnum)
+    infof(data, "%s\n", cp2);
   free(cp2);
   return CURLE_OK;
 }
@@ -1148,4 +1178,4 @@ CURLcode Curl_verifyhost(struct connectdata * conn,
   return CURLE_PEER_FAILED_VERIFICATION;
 }
 
-#endif /* USE_QSOSSL or USE_GSKIT */
+#endif /* USE_QSOSSL or USE_GSKIT or USE_NSS */
index 2276b5b64145d0fa7055417370f0adbca6801b5a..1741d6dcaeeac0fbbb771c9bc663ef40caa7ce07 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "curl_setup.h"
 
-#if defined(USE_QSOSSL) || defined(USE_GSKIT)
+#if defined(USE_QSOSSL) || defined(USE_GSKIT) || defined(USE_NSS)
 
 #include "urldata.h"
 
@@ -125,5 +125,5 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn, int certnum,
 CURLcode Curl_verifyhost(struct connectdata * conn,
                          const char * beg, const char * end);
 
-#endif /* USE_QSOSSL or USE_GSKIT */
+#endif /* USE_QSOSSL or USE_GSKIT or USE_NSS */
 #endif /* HEADER_CURL_X509ASN1_H */