aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--RELEASE-NOTES1
-rw-r--r--docs/curl.110
-rw-r--r--docs/libcurl/curl_easy_setopt.316
-rw-r--r--lib/nss.c108
4 files changed, 67 insertions, 68 deletions
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index aa67721ab..926b201d2 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -27,6 +27,7 @@ This release includes the following bugfixes:
o Curl_do: avoid using stale conn pointer
o tftpd test server: avoid buffer overflow report from glibc
o nss: avoid CURLE_OUT_OF_MEMORY given a file name without any slash
+ o nss: fix a bug in handling of CURLOPT_CAPATH
This release includes the following known bugs:
diff --git a/docs/curl.1 b/docs/curl.1
index 0ff183245..33b5e0269 100644
--- a/docs/curl.1
+++ b/docs/curl.1
@@ -394,11 +394,11 @@ may be loaded.
If this option is used several times, the last one will be used.
.IP "--capath <CA certificate directory>"
(SSL) Tells curl to use the specified certificate directory to verify the
-peer. The certificates must be in PEM format, and the directory must have been
-processed using the c_rehash utility supplied with openssl. Using
-\fI--capath\fP can allow curl to make SSL-connections much more efficiently
-than using \fI--cacert\fP if the \fI--cacert\fP file contains many CA
-certificates.
+peer. The certificates must be in PEM format, and if curl is built against
+OpenSSL, the directory must have been processed using the c_rehash utility
+supplied with OpenSSL. Using \fI--capath\fP can allow OpenSSL-powered curl to
+make SSL-connections much more efficiently than using \fI--cacert\fP if the
+\fI--cacert\fP file contains many CA certificates.
If this option is used several times, the last one will be used.
.IP "-f/--fail"
diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3
index 8c14c7dcc..bd342a125 100644
--- a/docs/libcurl/curl_easy_setopt.3
+++ b/docs/libcurl/curl_easy_setopt.3
@@ -1924,13 +1924,15 @@ mismatch with the issuer of peer certificate (\fICURLOPT_SSL_VERIFYPEER\fP has
to be set too for the check to fail). (Added in 7.19.0)
.IP CURLOPT_CAPATH
Pass a char * to a zero terminated string naming a directory holding multiple
-CA certificates to verify the peer with. The certificate directory must be
-prepared using the openssl c_rehash utility. This makes sense only when used
-in combination with the \fICURLOPT_SSL_VERIFYPEER\fP option. If
-\fICURLOPT_SSL_VERIFYPEER\fP is zero, \fICURLOPT_CAPATH\fP need not even
-indicate an accessible path. The \fICURLOPT_CAPATH\fP function apparently
-does not work in Windows due to some limitation in openssl. This option is
-OpenSSL-specific and does nothing if libcurl is built to use GnuTLS.
+CA certificates to verify the peer with. If libcurl is built against OpenSSL,
+the certificate directory must be prepared using the openssl c_rehash utility.
+This makes sense only when used in combination with the
+\fICURLOPT_SSL_VERIFYPEER\fP option. If \fICURLOPT_SSL_VERIFYPEER\fP is zero,
+\fICURLOPT_CAPATH\fP need not even indicate an accessible path. The
+\fICURLOPT_CAPATH\fP function apparently does not work in Windows due to some
+limitation in openssl. This option is OpenSSL-specific and does nothing if
+libcurl is built to use GnuTLS. NSS-powered libcurl provides the option only
+for backward compatibility.
.IP CURLOPT_CRLFILE
Pass a char * to a zero terminated string naming a file with the concatenation
of CRL (in PEM format) to use in the certificate validation that occurs during
diff --git a/lib/nss.c b/lib/nss.c
index a5e11e2fc..3d3e1c92c 100644
--- a/lib/nss.c
+++ b/lib/nss.c
@@ -1108,6 +1108,55 @@ static bool handle_cc_error(PRInt32 err, struct SessionHandle *data)
static Curl_recv nss_recv;
static Curl_send nss_send;
+static CURLcode nss_load_ca_certificates(struct connectdata *conn,
+ int sockindex)
+{
+ struct SessionHandle *data = conn->data;
+ const char *cafile = data->set.ssl.CAfile;
+ const char *capath = data->set.ssl.CApath;
+
+ if(cafile && !nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE))
+ return CURLE_SSL_CACERT_BADFILE;
+
+ if(capath) {
+ struct_stat st;
+ if(stat(capath, &st) == -1)
+ return CURLE_SSL_CACERT_BADFILE;
+
+ if(S_ISDIR(st.st_mode)) {
+ PRDirEntry *entry;
+ PRDir *dir = PR_OpenDir(capath);
+ if(!dir)
+ return CURLE_SSL_CACERT_BADFILE;
+
+ while((entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN))) {
+ char *fullpath = aprintf("%s/%s", capath, entry->name);
+ if(!fullpath) {
+ PR_CloseDir(dir);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
+ /* This is purposefully tolerant of errors so non-PEM files can
+ * be in the same directory */
+ infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath);
+
+ free(fullpath);
+ }
+
+ PR_CloseDir(dir);
+ }
+ else
+ infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath);
+ }
+
+ infof(data, " CAfile: %s\n CApath: %s\n",
+ cafile ? cafile : "none",
+ capath ? capath : "none");
+
+ return CURLE_OK;
+}
+
CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
{
PRInt32 err;
@@ -1249,62 +1298,9 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
NULL) != SECSuccess)
goto error;
- if(!data->set.ssl.verifypeer)
- /* skip the verifying of the peer */
- ;
- else if(data->set.ssl.CAfile) {
- int rc = nss_load_cert(&conn->ssl[sockindex], data->set.ssl.CAfile,
- PR_TRUE);
- if(!rc) {
- curlerr = CURLE_SSL_CACERT_BADFILE;
- goto error;
- }
- }
- else if(data->set.ssl.CApath) {
- struct_stat st;
- PRDir *dir;
- PRDirEntry *entry;
-
- if(stat(data->set.ssl.CApath, &st) == -1) {
- curlerr = CURLE_SSL_CACERT_BADFILE;
- goto error;
- }
-
- if(S_ISDIR(st.st_mode)) {
- int rc;
-
- dir = PR_OpenDir(data->set.ssl.CApath);
- do {
- entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN);
-
- if(entry) {
- char *fullpath;
- size_t pathlen = strlen(data->set.ssl.CApath) +
- strlen(entry->name) + 2; /* add two, for slash and trailing zero */
- fullpath = malloc(pathlen);
- if(!fullpath) {
- PR_CloseDir(dir);
- curlerr = CURLE_OUT_OF_MEMORY;
- goto error;
- }
-
- snprintf(fullpath, pathlen, "%s/%s", data->set.ssl.CApath,
- entry->name);
- rc = nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE);
- /* FIXME: check this return value! */
- free(fullpath);
- }
- /* This is purposefully tolerant of errors so non-PEM files
- * can be in the same directory */
- } while(entry != NULL);
- PR_CloseDir(dir);
- }
- }
- infof(data,
- " CAfile: %s\n"
- " CApath: %s\n",
- data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
- data->set.ssl.CApath ? data->set.ssl.CApath : "none");
+ if(data->set.ssl.verifypeer && (CURLE_OK !=
+ (curlerr = nss_load_ca_certificates(conn, sockindex))))
+ goto error;
if (data->set.ssl.CRLfile) {
if(SECSuccess != nss_load_crl(data->set.ssl.CRLfile)) {