1 From f6c335d63f2da025a0a3efde1fe59e3bb7189b70 Mon Sep 17 00:00:00 2001
2 From: Patrick Monnerat <pm@datasphere.ch>
3 Date: Wed, 30 Oct 2013 11:12:06 +0100
4 Subject: [PATCH] NSS: support for CERTINFO feature
7 docs/libcurl/curl_easy_getinfo.3 | 6 +--
8 docs/libcurl/curl_easy_setopt.3 | 5 +-
10 lib/nss.c | 46 ++++++++++++++++--
12 lib/x509asn1.c | 100 +++++++++++++++++++++++++--------------
14 7 files changed, 119 insertions(+), 49 deletions(-)
16 diff --git a/docs/libcurl/curl_easy_getinfo.3 b/docs/libcurl/curl_easy_getinfo.3
17 index 62d8ae4..db0f4d6 100644
18 --- a/docs/libcurl/curl_easy_getinfo.3
19 +++ b/docs/libcurl/curl_easy_getinfo.3
21 .\" * | (__| |_| | _ <| |___
22 .\" * \___|\___/|_| \_\_____|
24 -.\" * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
25 +.\" * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
27 .\" * This software is licensed as described in the file COPYING, which
28 .\" * you should have received as part of this distribution. The terms
29 @@ -219,8 +219,8 @@ done. The struct reports how many certs it found and then you can extract info
30 for each of those certs by following the linked lists. The info chain is
31 provided in a series of data in the format "name:content" where the content is
32 for the specific named data. See also the certinfo.c example. NOTE: this
33 -option is only available in libcurl built with OpenSSL support. (Added in
35 +option is only available in libcurl built with OpenSSL, NSS, GSKit or QsoSSL
36 +support. (Added in 7.19.1)
37 .IP CURLINFO_CONDITION_UNMET
38 Pass a pointer to a long to receive the number 1 if the condition provided in
39 the previous request didn't match (see \fICURLOPT_TIMECONDITION\fP). Alas, if
40 diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3
41 index f58c8fb..2887483 100644
42 --- a/docs/libcurl/curl_easy_setopt.3
43 +++ b/docs/libcurl/curl_easy_setopt.3
44 @@ -2549,9 +2549,10 @@ is ignored.
47 Pass a long set to 1 to enable libcurl's certificate chain info gatherer. With
48 -this enabled, libcurl (if built with OpenSSL) will extract lots of information
49 +this enabled, libcurl (if built with OpenSSL, NSS, GSKit or QsoSSL) will
50 +extract lots of information
51 and data about the certificates in the certificate chain used in the SSL
52 -connection. This data is then possible to extract after a transfer using
53 +connection. This data may then be retrieved after a transfer using
54 \fIcurl_easy_getinfo(3)\fP and its option \fICURLINFO_CERTINFO\fP. (Added in
56 .IP CURLOPT_RANDOM_FILE
57 diff --git a/lib/hostcheck.c b/lib/hostcheck.c
58 index abd1fa0..4be5baa 100644
62 #include "curl_setup.h"
64 #if defined(USE_SSLEAY) || defined(USE_AXTLS) || defined(USE_QSOSSL) || \
66 + defined(USE_GSKIT) || defined(USE_NSS)
67 /* these backends use functions from this file */
69 #include "hostcheck.h"
70 @@ -94,4 +94,4 @@ int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
74 -#endif /* SSLEAY or AXTLS or QSOSSL or GSKIT */
75 +#endif /* SSLEAY or AXTLS or QSOSSL or GSKIT or NSS */
76 diff --git a/lib/nss.c b/lib/nss.c
77 index 43576e6..2562fcf 100644
80 @@ -653,6 +653,10 @@ static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
81 SSLChannelInfo channel;
82 SSLCipherSuiteInfo suite;
83 CERTCertificate *cert;
84 + CERTCertificate *cert2;
85 + CERTCertificate *cert3;
89 if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
90 SECSuccess && channel.length == sizeof channel &&
91 @@ -663,11 +667,45 @@ static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
95 - infof(conn->data, "Server certificate:\n");
97 cert = SSL_PeerCertificate(sock);
98 - display_cert_info(conn->data, cert);
99 - CERT_DestroyCertificate(cert);
102 + infof(conn->data, "Server certificate:\n");
104 + if(!conn->data->set.ssl.certinfo) {
105 + display_cert_info(conn->data, cert);
106 + CERT_DestroyCertificate(cert);
109 + /* Count certificates in chain. */
112 + if(!cert->isRoot) {
113 + cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
116 + if(cert2->isRoot) {
117 + CERT_DestroyCertificate(cert2);
120 + cert3 = CERT_FindCertIssuer(cert2, now, certUsageSSLCA);
121 + CERT_DestroyCertificate(cert2);
125 + Curl_ssl_init_certinfo(conn->data, i);
126 + for(i = 0; cert; cert = cert2) {
127 + Curl_extract_certinfo(conn, i++, cert->derCert.data,
128 + cert->derCert.data + cert->derCert.len);
130 + CERT_DestroyCertificate(cert);
133 + cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
134 + CERT_DestroyCertificate(cert);
141 diff --git a/lib/url.c b/lib/url.c
142 index e86fbc2..03c7607 100644
145 @@ -1926,7 +1926,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
146 data->set.ssl.fsslctxp = va_arg(param, void *);
149 -#if defined(USE_SSLEAY) || defined(USE_QSOSSL) || defined(USE_GSKIT)
150 +#if defined(USE_SSLEAY) || defined(USE_QSOSSL) || defined(USE_GSKIT) || \
152 case CURLOPT_CERTINFO:
153 data->set.ssl.certinfo = (0 != va_arg(param, long))?TRUE:FALSE;
155 diff --git a/lib/x509asn1.c b/lib/x509asn1.c
156 index 94b89b2..d6aa045 100644
161 #include "curl_setup.h"
163 -#if defined(USE_QSOSSL) || defined(USE_GSKIT)
164 +#if defined(USE_QSOSSL) || defined(USE_GSKIT) || defined(USE_NSS)
166 #include <curl/curl.h>
168 @@ -803,7 +803,7 @@ static const char * dumpAlgo(curl_asn1Element * param,
169 return OID2str(oid.beg, oid.end, TRUE);
172 -static void do_pubkey_field(struct SessionHandle *data, int certnum,
173 +static void do_pubkey_field(struct SessionHandle * data, int certnum,
174 const char * label, curl_asn1Element * elem)
177 @@ -812,8 +812,10 @@ static void do_pubkey_field(struct SessionHandle *data, int certnum,
179 output = Curl_ASN1tostr(elem, 0);
181 - Curl_ssl_push_certinfo(data, certnum, label, output);
182 - infof(data, " %s: %s\n", label, output);
183 + if(data->set.ssl.certinfo)
184 + Curl_ssl_push_certinfo(data, certnum, label, output);
186 + infof(data, " %s: %s\n", label, output);
187 free((char *) output);
190 @@ -845,11 +847,14 @@ static void do_pubkey(struct SessionHandle * data, int certnum,
193 elem.beg = q; /* Strip leading zero bytes. */
194 - infof(data, " RSA Public Key (%lu bits)\n", len);
195 - q = curl_maprintf("%lu", len);
197 - Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q);
200 + infof(data, " RSA Public Key (%lu bits)\n", len);
201 + if(data->set.ssl.certinfo) {
202 + q = curl_maprintf("%lu", len);
204 + Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q);
208 /* Generate coefficients. */
209 do_pubkey_field(data, certnum, "rsa(n)", &elem);
210 @@ -896,6 +901,10 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
214 + if(!data->set.ssl.certinfo)
218 /* Prepare the certificate information for curl_easy_getinfo(). */
220 /* Extract the certificate ASN.1 elements. */
221 @@ -905,35 +914,44 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
222 ccp = Curl_DNtostr(&cert.subject);
224 return CURLE_OUT_OF_MEMORY;
225 - Curl_ssl_push_certinfo(data, certnum, "Subject", ccp);
226 - infof(data, "%2d Subject: %s\n", certnum, ccp);
227 + if(data->set.ssl.certinfo)
228 + Curl_ssl_push_certinfo(data, certnum, "Subject", ccp);
230 + infof(data, "%2d Subject: %s\n", certnum, ccp);
234 ccp = Curl_DNtostr(&cert.issuer);
236 return CURLE_OUT_OF_MEMORY;
237 - Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp);
238 - infof(data, " Issuer: %s\n", ccp);
239 + if(data->set.ssl.certinfo)
240 + Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp);
242 + infof(data, " Issuer: %s\n", ccp);
245 /* Version (always fits in less than 32 bits). */
247 for(ccp = cert.version.beg; ccp < cert.version.end; ccp++)
248 version = (version << 8) | *(const unsigned char *) ccp;
249 - ccp = curl_maprintf("%lx", version);
251 - return CURLE_OUT_OF_MEMORY;
252 - Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
253 - free((char *) ccp);
254 - infof(data, " Version: %lu (0x%lx)\n", version + 1, version);
255 + if(data->set.ssl.certinfo) {
256 + ccp = curl_maprintf("%lx", version);
258 + return CURLE_OUT_OF_MEMORY;
259 + Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
260 + free((char *) ccp);
263 + infof(data, " Version: %lu (0x%lx)\n", version + 1, version);
266 ccp = Curl_ASN1tostr(&cert.serialNumber, 0);
268 return CURLE_OUT_OF_MEMORY;
269 - Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp);
270 - infof(data, " Serial Number: %s\n", ccp);
271 + if(data->set.ssl.certinfo)
272 + Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp);
274 + infof(data, " Serial Number: %s\n", ccp);
277 /* Signature algorithm .*/
278 @@ -941,24 +959,30 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
279 cert.signatureAlgorithm.end);
281 return CURLE_OUT_OF_MEMORY;
282 - Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
283 - infof(data, " Signature Algorithm: %s\n", ccp);
284 + if(data->set.ssl.certinfo)
285 + Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
287 + infof(data, " Signature Algorithm: %s\n", ccp);
291 ccp = Curl_ASN1tostr(&cert.notBefore, 0);
293 return CURLE_OUT_OF_MEMORY;
294 - Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp);
295 - infof(data, " Start Date: %s\n", ccp);
296 + if(data->set.ssl.certinfo)
297 + Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp);
299 + infof(data, " Start Date: %s\n", ccp);
303 ccp = Curl_ASN1tostr(&cert.notAfter, 0);
305 return CURLE_OUT_OF_MEMORY;
306 - Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp);
307 - infof(data, " Expire Date: %s\n", ccp);
308 + if(data->set.ssl.certinfo)
309 + Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp);
311 + infof(data, " Expire Date: %s\n", ccp);
314 /* Public Key Algorithm. */
315 @@ -966,8 +990,10 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
316 cert.subjectPublicKeyAlgorithm.end);
318 return CURLE_OUT_OF_MEMORY;
319 - Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp);
320 - infof(data, " Public Key Algorithm: %s\n", ccp);
321 + if(data->set.ssl.certinfo)
322 + Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp);
324 + infof(data, " Public Key Algorithm: %s\n", ccp);
325 do_pubkey(data, certnum, ccp, ¶m, &cert.subjectPublicKey);
328 @@ -977,8 +1003,10 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
329 ccp = Curl_ASN1tostr(&cert.signature, 0);
331 return CURLE_OUT_OF_MEMORY;
332 - Curl_ssl_push_certinfo(data, certnum, "Signature", ccp);
333 - infof(data, " Signature: %s\n", ccp);
334 + if(data->set.ssl.certinfo)
335 + Curl_ssl_push_certinfo(data, certnum, "Signature", ccp);
337 + infof(data, " Signature: %s\n", ccp);
340 /* Generate PEM certificate. */
341 @@ -987,7 +1015,7 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
345 - /* Compute the number of charaters in final certificate string. Format is:
346 + /* Compute the number of characters in final certificate string. Format is:
347 -----BEGIN CERTIFICATE-----\n
348 <max 64 base64 characters>\n
350 @@ -1008,8 +1036,10 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
351 i += copySubstring(cp2 + i, "-----END CERTIFICATE-----");
354 - Curl_ssl_push_certinfo(data, certnum, "Cert", cp2);
355 - infof(data, "%s\n", cp2);
356 + if(data->set.ssl.certinfo)
357 + Curl_ssl_push_certinfo(data, certnum, "Cert", cp2);
359 + infof(data, "%s\n", cp2);
363 @@ -1148,4 +1178,4 @@ CURLcode Curl_verifyhost(struct connectdata * conn,
364 return CURLE_PEER_FAILED_VERIFICATION;
367 -#endif /* USE_QSOSSL or USE_GSKIT */
368 +#endif /* USE_QSOSSL or USE_GSKIT or USE_NSS */
369 diff --git a/lib/x509asn1.h b/lib/x509asn1.h
370 index 2276b5b..1741d6d 100644
375 #include "curl_setup.h"
377 -#if defined(USE_QSOSSL) || defined(USE_GSKIT)
378 +#if defined(USE_QSOSSL) || defined(USE_GSKIT) || defined(USE_NSS)
382 @@ -125,5 +125,5 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn, int certnum,
383 CURLcode Curl_verifyhost(struct connectdata * conn,
384 const char * beg, const char * end);
386 -#endif /* USE_QSOSSL or USE_GSKIT */
387 +#endif /* USE_QSOSSL or USE_GSKIT or USE_NSS */
388 #endif /* HEADER_CURL_X509ASN1_H */