]> granicus.if.org Git - curl/commitdiff
- Axel Tillequin and Arnaud Ebalard added support for CURLOPT_CRLFILE, for
authorDaniel Stenberg <daniel@haxx.se>
Fri, 6 Jun 2008 18:40:21 +0000 (18:40 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 6 Jun 2008 18:40:21 +0000 (18:40 +0000)
  OpenSSL, NSS and GnuTLS-built libcurls.

12 files changed:
CHANGES
RELEASE-NOTES
TODO-RELEASE
docs/libcurl/curl_easy_setopt.3
docs/libcurl/libcurl-errors.3
include/curl/curl.h
lib/gtls.c
lib/nss.c
lib/ssluse.c
lib/strerror.c
lib/url.c
lib/urldata.h

diff --git a/CHANGES b/CHANGES
index 3726effe3280aa66e9bd1cb8bea190cc88a3a7b2..4145bbe0b9628fe63171c41123867ccf1c7751d8 100644 (file)
--- 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
index 573acce9bab446f1c3b3b933ed0e5d426eff8a64..9f7157e268632516f5ed965e50c21333b07e5366 100644 (file)
@@ -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)
index 7edbc48e75716a16aaa4ef27f48a15c51d2dda4c..661894c3dc59933d3d69d5d5318b63f8b3542c6e 100644 (file)
@@ -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 -
index d378edb4d23bae28ad3fd5dc331dfd6916587e58..ee425a268a01dd9ca40b4f037ebc74cf09a18964 100644 (file)
@@ -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,
index 28e6f82c9b5b990f7f0e558bd04eb2b17a8b054a..994489b71ffec19b16fc901ea09798ccd4fe0918 100644 (file)
@@ -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.
index b42f0b31b11637f03f316a35ed80a0027922d3e8..a67fd22103a2aabc51bc5d4e067951186a4018da 100644 (file)
@@ -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;
 
index 80100b4ed59a352e6cfec97a51b106605041d8d5..e9e410243d0a92e99dcf75b1fad937f02d84ffcf 100644 (file)
@@ -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) {
index 20f8770d2884a0ac2a8e2a6c2325370fdfd2dbce..a5fc795f8a0c8388b34f7e93bd1b41db5a523217 100644 (file)
--- 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;
index b0d7fd038bf116df27a420c0955a8b1204089a62..f14ad344e8d4b7273018e9bdd6d076fe7f1b4f18 100644 (file)
@@ -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
index fe5a76df5d04c9b7f1784c943f3ec49f5bdd3167..03b01582c56823deb2033cfaea2a0b3199c4e147 100644 (file)
@@ -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";
 
index 906792332d3b8403477095e6980f4f9132eebf0b..0e71cede0d8bb6c2d0070fee788239d21ebe65ec 100644 (file)
--- 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];
index 1f9d3ebd28245496d24672c4c68a5e32bc1efe33..def598b41f3940be8665d643c607a665c9a4ede1 100644 (file)
@@ -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 */