aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2008-06-06 18:40:21 +0000
committerDaniel Stenberg <daniel@haxx.se>2008-06-06 18:40:21 +0000
commit3fe8251dfbb533803e25cc38365114b28c5a1c85 (patch)
treef6023109232d4fd990d5c2a4bcc4479e55367ee3
parent930a45e7a93c964ec224bdddb59f97479b7e4a5d (diff)
- Axel Tillequin and Arnaud Ebalard added support for CURLOPT_CRLFILE, for
OpenSSL, NSS and GnuTLS-built libcurls.
-rw-r--r--CHANGES3
-rw-r--r--RELEASE-NOTES5
-rw-r--r--TODO-RELEASE3
-rw-r--r--docs/libcurl/curl_easy_setopt.318
-rw-r--r--docs/libcurl/libcurl-errors.32
-rw-r--r--include/curl/curl.h8
-rw-r--r--lib/gtls.c15
-rw-r--r--lib/nss.c77
-rw-r--r--lib/ssluse.c26
-rw-r--r--lib/strerror.c3
-rw-r--r--lib/url.c9
-rw-r--r--lib/urldata.h2
12 files changed, 165 insertions, 6 deletions
diff --git a/CHANGES b/CHANGES
index 3726effe3..4145bbe0b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -8,6 +8,9 @@
Daniel Stenberg (6 Jun 2008)
+- Axel Tillequin and Arnaud Ebalard added support for CURLOPT_CRLFILE, for
+ OpenSSL, NSS and GnuTLS-built libcurls.
+
- Added CURLINFO_PRIMARY_IP as a new information retrievable with
curl_easy_getinfo. It returns a pointer to a string with the most recently
used IP address. Modified test case 500 to also verify this feature. The
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 573acce9b..9f7157e26 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -2,7 +2,7 @@ Curl and libcurl 7.18.3
Public curl releases: 106
Command line options: 126
- curl_easy_setopt() options: 150
+ curl_easy_setopt() options: 151
Public functions in libcurl: 58
Public web site mirrors: 37
Known libcurl bindings: 36
@@ -11,6 +11,7 @@ Curl and libcurl 7.18.3
This release includes the following changes:
o Added CURLINFO_PRIMARY_IP
+ o Added CURLOPT_CRLFILE
This release includes the following bugfixes:
@@ -31,6 +32,6 @@ New curl mirrors:
This release would not have looked like this without help, code, reports and
advice from friends like these:
- Lenny Rachitsky
+ Lenny Rachitsky, Axel Tillequin, Arnaud Ebalard
Thanks! (and sorry if I forgot to mention someone)
diff --git a/TODO-RELEASE b/TODO-RELEASE
index 7edbc48e7..661894c3d 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -5,9 +5,6 @@ To be addressed before 7.18.3 (planned release: August 2008)
140 - Arnaud Ebalard and Axel Tillequin's CRL support and issuer check patches
-141 - The sponsored feature CURLINFO_PRIMARY_IP that returns the IP address
- as a string for the most recently used connection.
-
144 - Help apps use 64bit/LFS libcurl!
145 -
diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3
index d378edb4d..ee425a268 100644
--- a/docs/libcurl/curl_easy_setopt.3
+++ b/docs/libcurl/curl_easy_setopt.3
@@ -1452,6 +1452,24 @@ in combination with the \fICURLOPT_SSL_VERIFYPEER\fP option. If
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.
+.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
+the SSL exchange.
+
+When curl is built to use NSS or GnuTLS, there is no way to influence the use
+of CRL passed to help in the verification process. When libcurl is built with
+OpenSSL support, X509_V_FLAG_CRL_CHECK and X509_V_FLAG_CRL_CHECK_ALL are both
+set, requiring CRL check against all the elements of the certificate chain if
+a CRL file is passed.
+
+This option makes sense only when used in combination with the
+\fICURLOPT_SSL_VERIFYPEER\fP option.
+
+A specific error code (CURLE_SSL_CRL_BADFILE) is defined with the option. It
+is returned when the SSL exchange fails because the CRL file cannot be loaded.
+Note that a failure in certificate verification due to a revocation information
+found in the CRL does not trigger this specific error.
.IP CURLOPT_RANDOM_FILE
Pass a char * to a zero terminated file name. The file will be used to read
from to seed the random engine for SSL. The more random the specified file is,
diff --git a/docs/libcurl/libcurl-errors.3 b/docs/libcurl/libcurl-errors.3
index 28e6f82c9..994489b71 100644
--- a/docs/libcurl/libcurl-errors.3
+++ b/docs/libcurl/libcurl-errors.3
@@ -212,6 +212,8 @@ Failed to shut down the SSL connection
Socket is not ready for send/recv wait till it's ready and try again. This
return code is only returned from \fIcurl_easy_recv(3)\fP and
\fIcurl_easy_send(3)\fP (Added in 7.18.2)
+.IP "CURLE_SSL_CRL_BADFILE (82)"
+Failed to load CRL file (Added in 7.18.3)
.IP "CURLE_OBSOLETE*"
These error codes will never be returned. They used to be used in an old libcurl
version and are currently unused.
diff --git a/include/curl/curl.h b/include/curl/curl.h
index b42f0b31b..a67fd2210 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -452,7 +452,10 @@ typedef enum {
CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL
connection */
CURLE_AGAIN, /* 81 - socket is not ready for send/recv,
- wait till it's ready and try again */
+ wait till it's ready and try again (Added
+ in 7.18.2) */
+ CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or
+ wrong format (Added in 7.18.3) */
CURL_LAST /* never use! */
} CURLcode;
@@ -1200,6 +1203,9 @@ typedef enum {
CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167),
CINIT(SEEKDATA, OBJECTPOINT, 168),
+ /* CRL file */
+ CINIT(CRLFILE, OBJECTPOINT, 169),
+
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
diff --git a/lib/gtls.c b/lib/gtls.c
index 80100b4ed..e9e410243 100644
--- a/lib/gtls.c
+++ b/lib/gtls.c
@@ -271,6 +271,21 @@ Curl_gtls_connect(struct connectdata *conn,
rc, data->set.ssl.CAfile);
}
+ if(data->set.ssl.CRLfile) {
+ /* set the CRL list file */
+ rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
+ data->set.ssl.CRLfile,
+ GNUTLS_X509_FMT_PEM);
+ if(rc < 0) {
+ failf(data, "error reading crl file %s (%s)\n",
+ data->set.ssl.CRLfile, gnutls_strerror(rc));
+ return CURLE_SSL_CRL_BADFILE;
+ }
+ else
+ infof(data, "found %d CRL in %s\n",
+ rc, data->set.ssl.CRLfile);
+ }
+
/* Initialize TLS session as a client */
rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT);
if(rc) {
diff --git a/lib/nss.c b/lib/nss.c
index 20f8770d2..a5fc795f8 100644
--- a/lib/nss.c
+++ b/lib/nss.c
@@ -59,6 +59,9 @@
#include <sslproto.h>
#include <prtypes.h>
#include <pk11pub.h>
+#include <prio.h>
+#include <secitem.h>
+#include <secport.h>
#include "memory.h"
#include "easyif.h" /* for Curl_convert_from_utf8 prototype */
@@ -362,6 +365,69 @@ done:
return 1;
}
+static int nss_load_crl(char* crlfilename, PRBool ascii)
+{
+ PRFileDesc *infile;
+ PRStatus prstat;
+ PRFileInfo info;
+ PRInt32 nb;
+ int rv;
+ SECItem crlDER;
+ CERTSignedCrl *crl=NULL;
+ PK11SlotInfo *slot=NULL;
+
+ infile = PR_Open(crlfilename,PR_RDONLY,0);
+ if (!infile) {
+ return 0;
+ }
+ crlDER.data = NULL;
+ prstat = PR_GetOpenFileInfo(infile,&info);
+ if (prstat!=PR_SUCCESS) return 0;
+ if (ascii) {
+ SECItem filedata;
+ char *asc,*body;
+ filedata.data = NULL;
+ if (!SECITEM_AllocItem(NULL,&filedata,info.size)) return 0;
+ nb = PR_Read(infile,filedata.data,info.size);
+ if (nb!=info.size) return 0;
+ asc = (char*)filedata.data;
+ if (!asc) {
+ return 0;
+ }
+ if ((body=strstr(asc,"-----BEGIN")) != NULL) {
+ char *trailer=NULL;
+ asc = body;
+ body = PORT_Strchr(asc,'\n');
+ if (!body) body = PORT_Strchr(asc,'\r');
+ if (body) trailer = strstr(++body,"-----END");
+ if (trailer!=NULL) *trailer='\0';
+ else return 0;
+ }
+ else {
+ body = asc;
+ }
+ rv = ATOB_ConvertAsciiToItem(&crlDER,body);
+ PORT_Free(filedata.data);
+ if (rv) return 0;
+ }
+ else {
+ if (!SECITEM_AllocItem(NULL,&crlDER,info.size)) return 0;
+ nb = PR_Read(infile,crlDER.data,info.size);
+ if (nb!=info.size) return 0;
+ }
+
+ slot = PK11_GetInternalKeySlot();
+ crl = PK11_ImportCRL(slot,&crlDER,
+ NULL,SEC_CRL_TYPE,
+ NULL,CRL_IMPORT_DEFAULT_OPTIONS,
+ NULL,(CRL_DECODE_DEFAULT_OPTIONS|
+ CRL_DECODE_DONT_COPY_DER));
+ if (slot) PK11_FreeSlot(slot);
+ if (!crl) return 0;
+ SEC_DestroyCrl(crl);
+ return 1;
+}
+
static int nss_load_key(struct connectdata *conn, char *key_file)
{
#ifdef HAVE_PK11_CREATEGENERICOBJECT
@@ -955,6 +1021,17 @@ CURLcode Curl_nss_connect(struct connectdata * conn, int sockindex)
data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
data->set.ssl.CApath ? data->set.ssl.CApath : "none");
+ if (data->set.ssl.CRLfile) {
+ int rc = nss_load_crl(data->set.ssl.CRLfile, PR_FALSE);
+ if (!rc) {
+ curlerr = CURLE_SSL_CRL_BADFILE;
+ goto error;
+ }
+ infof(data,
+ " CRLfile: %s\n",
+ data->set.ssl.CRLfile ? data->set.ssl.CRLfile : "none");
+ }
+
if(data->set.str[STRING_CERT]) {
char *n;
char *nickname;
diff --git a/lib/ssluse.c b/lib/ssluse.c
index b0d7fd038..f14ad344e 100644
--- a/lib/ssluse.c
+++ b/lib/ssluse.c
@@ -1293,6 +1293,7 @@ ossl_connect_step1(struct connectdata *conn,
struct SessionHandle *data = conn->data;
SSL_METHOD_QUAL SSL_METHOD *req_method=NULL;
void *ssl_sessionid=NULL;
+ X509_LOOKUP *lookup=NULL;
curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
@@ -1429,6 +1430,31 @@ ossl_connect_step1(struct connectdata *conn,
data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]:
"none");
}
+
+ if (data->set.str[STRING_SSL_CRLFILE]) {
+ /* tell SSL where to find CRL file that is used to check certificate
+ * revocation */
+ lookup=X509_STORE_add_lookup(connssl->ctx->cert_store,X509_LOOKUP_file());
+ if ( !lookup ||
+ (X509_load_crl_file(lookup,data->set.str[STRING_SSL_CRLFILE],
+ X509_FILETYPE_PEM)!=1) ) {
+ failf(data,"error loading CRL file :\n"
+ " CRLfile: %s\n",
+ data->set.str[STRING_SSL_CRLFILE]?
+ data->set.str[STRING_SSL_CRLFILE]: "none");
+ return CURLE_SSL_CRL_BADFILE;
+ }
+ else {
+ /* Everything is fine. */
+ infof(data, "successfully load CRL file:\n");
+ X509_STORE_set_flags(connssl->ctx->cert_store,
+ X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
+ }
+ infof(data,
+ " CRLfile: %s\n", data->set.str[STRING_SSL_CRLFILE] ?
+ data->set.str[STRING_SSL_CRLFILE]: "none");
+ }
+
/* SSL always tries to verify the peer, this only says whether it should
* fail to connect if the verification fails, or if it should continue
* anyway. In the latter case the result of the verification is checked with
diff --git a/lib/strerror.c b/lib/strerror.c
index fe5a76df5..03b01582c 100644
--- a/lib/strerror.c
+++ b/lib/strerror.c
@@ -222,6 +222,9 @@ curl_easy_strerror(CURLcode error)
case CURLE_SSL_SHUTDOWN_FAILED:
return "Failed to shut down the SSL connection";
+ case CURLE_SSL_CRL_BADFILE:
+ return "Failed to load CRL file (path? access rights?, format?)";
+
case CURLE_SEND_FAIL_REWIND:
return "Send failed since rewinding of the data stream failed";
diff --git a/lib/url.c b/lib/url.c
index 906792332..0e71cede0 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -1811,6 +1811,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
result = setstropt(&data->set.str[STRING_SSL_CAPATH],
va_arg(param, char *));
break;
+ case CURLOPT_CRLFILE:
+ /*
+ * Set CRL file info for SSL connection. Specify file name of the CRL
+ * to check certificates revocation
+ */
+ result = setstropt(&data->set.str[STRING_SSL_CRLFILE],
+ va_arg(param, char *));
+ break;
case CURLOPT_TELNETOPTIONS:
/*
* Set a linked list of telnet options
@@ -3951,6 +3959,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
*/
data->set.ssl.CApath = data->set.str[STRING_SSL_CAPATH];
data->set.ssl.CAfile = data->set.str[STRING_SSL_CAFILE];
+ data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE];
data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST];
diff --git a/lib/urldata.h b/lib/urldata.h
index 1f9d3ebd2..def598b41 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -212,6 +212,7 @@ struct ssl_config_data {
2: CN must match hostname */
char *CApath; /* certificate dir (doesn't work on windows) */
char *CAfile; /* cerficate to verify peer against */
+ char *CRLfile; /* CRL to check cerficate revocation */
char *random_file; /* path to file containing "random" data */
char *egdsocket; /* path to file containing the EGD daemon socket */
char *cipher_list; /* list of ciphers to use */
@@ -1317,6 +1318,7 @@ enum dupstring {
STRING_USERAGENT, /* User-Agent string */
STRING_USERPWD, /* <user:password>, if used */
STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
+ STRING_SSL_CRLFILE, /* crl file to check certificate */
/* -- end of strings -- */
STRING_LAST /* not used, just an end-of-list marker */