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

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