aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Monnerat <pm@datasphere.ch>2013-10-30 11:12:06 +0100
committerPatrick Monnerat <pm@datasphere.ch>2013-10-30 11:12:06 +0100
commitf6c335d63f2da025a0a3efde1fe59e3bb7189b70 (patch)
tree76fafce3ea32f251118b686fabf288f604b6ef88
parent2bd72fa61ca21c2072e09cc6808db0371847bb2c (diff)
NSS: support for CERTINFO feature
-rw-r--r--docs/libcurl/curl_easy_getinfo.36
-rw-r--r--docs/libcurl/curl_easy_setopt.35
-rw-r--r--lib/hostcheck.c4
-rw-r--r--lib/nss.c46
-rw-r--r--lib/url.c3
-rw-r--r--lib/x509asn1.c100
-rw-r--r--lib/x509asn1.h4
7 files changed, 119 insertions, 49 deletions
diff --git a/docs/libcurl/curl_easy_getinfo.3 b/docs/libcurl/curl_easy_getinfo.3
index 62d8ae482..db0f4d62a 100644
--- a/docs/libcurl/curl_easy_getinfo.3
+++ b/docs/libcurl/curl_easy_getinfo.3
@@ -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
diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3
index f58c8fbfe..2887483af 100644
--- a/docs/libcurl/curl_easy_setopt.3
+++ b/docs/libcurl/curl_easy_setopt.3
@@ -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
diff --git a/lib/hostcheck.c b/lib/hostcheck.c
index abd1fa0c3..4be5baa92 100644
--- a/lib/hostcheck.c
+++ b/lib/hostcheck.c
@@ -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 */
diff --git a/lib/nss.c b/lib/nss.c
index 43576e6d5..2562fcfdb 100644
--- 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;
}
diff --git a/lib/url.c b/lib/url.c
index e86fbc252..03c76078b 100644
--- 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;
diff --git a/lib/x509asn1.c b/lib/x509asn1.c
index 94b89b2be..d6aa04596 100644
--- a/lib/x509asn1.c
+++ b/lib/x509asn1.c
@@ -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 */
diff --git a/lib/x509asn1.h b/lib/x509asn1.h
index 2276b5b64..1741d6dca 100644
--- a/lib/x509asn1.h
+++ b/lib/x509asn1.h
@@ -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 */