NSS: support for CERTINFO feature

This commit is contained in:
Patrick Monnerat 2013-10-30 11:12:06 +01:00
parent 2bd72fa61c
commit f6c335d63f
7 changed files with 119 additions and 49 deletions

View 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

View 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

View 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 */

View File

@ -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;
}

View File

@ -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;

View 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 */

View 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 */