nss: fix a bug in handling of CURLOPT_CAPATH

... and update the curl.1 and curl_easy_setopt.3 man pages such that
they do not suggest to use an OpenSSL utility if curl is not built
against OpenSSL.

Bug: https://bugzilla.redhat.com/669702
This commit is contained in:
Kamil Dudka 2011-01-18 13:53:43 +01:00
parent ef46fcdd90
commit fc77790bcd
4 changed files with 67 additions and 68 deletions

View File

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

View File

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

View File

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

106
lib/nss.c
View File

@ -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;
if(data->set.ssl.verifypeer && (CURLE_OK !=
(curlerr = nss_load_ca_certificates(conn, sockindex))))
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.CRLfile) {
if(SECSuccess != nss_load_crl(data->set.ssl.CRLfile)) {