NSS: support for CERTINFO feature
This commit is contained in:
Родитель
2bd72fa61c
Коммит
f6c335d63f
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
46
lib/nss.c
46
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
100
lib/x509asn1.c
100
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, ¶m, &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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Загрузка…
Ссылка в новой задаче