support cachecrls=yes
authorAndreas Steffen <andreas.steffen@strongswan.org>
Thu, 5 Apr 2007 17:07:14 +0000 (17:07 -0000)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Thu, 5 Apr 2007 17:07:14 +0000 (17:07 -0000)
src/charon/config/credentials/local_credential_store.c
src/charon/daemon.c
src/libstrongswan/chunk.c
src/libstrongswan/chunk.h
src/libstrongswan/crypto/ca.c
src/libstrongswan/crypto/ca.h
src/libstrongswan/crypto/crl.c
src/libstrongswan/crypto/crl.h
src/starter/invokecharon.c

index ed6a760..3a03f20 100644 (file)
@@ -665,7 +665,7 @@ static bool verify(private_local_credential_store_t *this, x509_t *cert, bool *f
                        /* if ocsp service is not available then fall back to crl */
                        if ((status == CERT_UNDEFINED) || (status == CERT_UNKNOWN && this->strict))
                        {
-                               status = issuer->verify_by_crl(issuer, certinfo);
+                               status = issuer->verify_by_crl(issuer, certinfo, CRL_DIR);
                        }
                        
                        nextUpdate = certinfo->get_nextUpdate(certinfo);
@@ -1038,7 +1038,7 @@ static void load_ocsp_certificates(private_local_credential_store_t *this)
 /**
  * Add the latest crl to the issuing ca
  */
-static void add_crl(private_local_credential_store_t *this, crl_t *crl)
+static void add_crl(private_local_credential_store_t *this, crl_t *crl, const char *path)
 {
        iterator_t *iterator = this->ca_infos->create_iterator(this->ca_infos, TRUE);
        ca_info_t *ca_info;
@@ -1048,8 +1048,16 @@ static void add_crl(private_local_credential_store_t *this, crl_t *crl)
        {
                if (ca_info->is_crl_issuer(ca_info, crl))
                {
-                       found = TRUE;
+                       char buffer[BUF_LEN];
+                       chunk_t uri = { buffer, 7 + strlen(path) };
+
                        ca_info->add_crl(ca_info, crl);
+                       if (uri.len < BUF_LEN)
+                       {
+                               snprintf(buffer, BUF_LEN, "file://%s", path);
+                               ca_info->add_crluri(ca_info, uri);
+                       }
+                       found = TRUE;
                        break;
                }
        }
@@ -1097,8 +1105,8 @@ static void load_crls(private_local_credential_store_t *this)
                        crl = crl_create_from_file(file);
                        if (crl)
                        {
-                               DBG1(DBG_CFG, "crl is %s", crl->is_valid(crl)? "valid":"stale");
-                               add_crl(this, crl);
+                               DBG1(DBG_CFG, "  crl is %s", crl->is_valid(crl)? "valid":"stale");
+                               add_crl(this, crl, file);
                        }
                }
        }
index 6d91587..7671aea 100644 (file)
@@ -380,6 +380,7 @@ static void usage(const char *msg)
                                        "         [--help]\n"
                                        "         [--version]\n"
                                        "         [--strictcrlpolicy]\n"
+                                       "         [--cachecrls]\n"
                                        "         [--crlcheckinterval <interval>]\n"
                                        "         [--eapdir <dir>]\n"
                                        "         [--use-syslog]\n"
@@ -399,6 +400,7 @@ int main(int argc, char *argv[])
 {
        u_int crl_check_interval = 0;
        bool strict_crl_policy = FALSE;
+       bool cache_crls = FALSE;
        bool use_syslog = FALSE;
        char *eapdir = IPSEC_EAPDIR;
 
@@ -424,6 +426,7 @@ int main(int argc, char *argv[])
                        { "version", no_argument, NULL, 'v' },
                        { "use-syslog", no_argument, NULL, 'l' },
                        { "strictcrlpolicy", no_argument, NULL, 'r' },
+                       { "cachecrls", no_argument, NULL, 'C' },
                        { "crlcheckinterval", required_argument, NULL, 'x' },
                        { "eapdir", required_argument, NULL, 'e' },
                        /* TODO: handle "debug-all" */
@@ -457,6 +460,9 @@ int main(int argc, char *argv[])
                        case 'r':
                                strict_crl_policy = TRUE;
                                continue;
+                       case 'C':
+                               cache_crls = TRUE;
+                               continue;
                        case 'x':
                                crl_check_interval = atoi(optarg);
                                continue;
@@ -483,8 +489,8 @@ int main(int argc, char *argv[])
        /* load pluggable EAP modules */
        eap_method_load(eapdir);
        
-       /* set crl_check_interval */
-       ca_info_set_crlcheckinterval(crl_check_interval);
+       /* set cache_crls and crl_check_interval options */
+       ca_info_set_options(cache_crls, crl_check_interval);
 
        /* check/setup PID file */
        if (stat(PID_FILE, &stb) == 0)
index 1967b35..cba823c 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "chunk.h"
 
+#include <debug.h>
 #include <printf_hook.h>
 
 /**
@@ -205,6 +206,45 @@ void chunk_split(chunk_t chunk, const char *mode, ...)
        va_end(chunks);
 }
 
+/**
+ * Described in header.
+ */
+bool chunk_write(chunk_t chunk, const char *path, const char *label, mode_t mask, bool force)
+{
+       mode_t oldmask;
+       FILE *fd;
+
+       if (!force)
+       {
+               fd = fopen(path, "r");
+               if (fd)
+               {
+                       fclose(fd);
+                       DBG1("  %s file '%s' already exists", label, path);
+                       return FALSE;
+               }
+       }
+
+       /* set umask */
+       oldmask = umask(mask);
+
+       fd = fopen(path, "w");
+
+       if (fd)
+       {
+               fwrite(chunk.ptr, sizeof(u_char), chunk.len, fd);
+               fclose(fd);
+               DBG1("  written %s file '%s' (%u bytes)", label, path, chunk.len);
+               umask(oldmask);
+               return TRUE;
+       }
+       else
+       {
+               DBG1("  could not open %s file '%s' for writing", label, path);
+               umask(oldmask);
+               return FALSE;
+       }
+}
 
 /**
  * Described in header.
index e4e816f..a13ccfc 100644 (file)
@@ -79,6 +79,11 @@ chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...);
 void chunk_split(chunk_t chunk, const char *mode, ...);
 
 /**
+  * Write the binary contents of a chunk_t to a file
+  */
+bool chunk_write(chunk_t chunk, const char *path, const char *label, mode_t mask, bool force);
+
+/**
  * Free contents of a chunk
  */
 void chunk_free(chunk_t *chunk);
index cf3d0ee..4ec8c84 100644 (file)
@@ -92,9 +92,10 @@ struct private_ca_info_t {
 };
 
 /**
- * static value set by ca_info_set_crl()
+ * static options set by ca_info_set_options()
  */
-static crl_check_interval = 0;
+static bool cache_crls = FALSE;
+static u_int crl_check_interval = 0;
 
 /**
  * Implements ca_info_t.equals
@@ -379,10 +380,62 @@ static x509_t* get_certificate(private_ca_info_t* this)
 }
 
 /**
+ * caches a crl by saving it to a given crl directory
+ */
+void cache_crl(private_ca_info_t* this, const char *crl_dir, crl_t *crl)
+{
+       char buffer[BUF_LEN];
+       char *path;
+       char *pos = buffer;
+       int len = BUF_LEN;
+       int n;
+
+       chunk_t authKeyID = this->cacert->get_subjectKeyID(this->cacert);
+       chunk_t uri;
+
+       uri.ptr = buffer;
+       uri.len = 7 + strlen(crl_dir) + 1 + 2*authKeyID.len + 4;
+
+       if (uri.len >= BUF_LEN) 
+       {
+               DBG1("file uri exceeds buffer length of %d bytes - crl not saved", BUF_LEN);
+               return;
+       }
+
+       /* print the file uri prefix */
+       n = snprintf(pos, len, "file://");
+       pos += n;  len -= n;
+
+       /* remember the start of the path string */
+       path = pos;
+
+       /* print the default crl directory path */
+       n = snprintf(pos, len, "%s/", crl_dir);
+       pos += n;  len -= n;
+
+       /* create and print a unique crl filename derived from the authKeyID */
+       while (authKeyID.len-- > 0)
+       {
+               n = snprintf(pos, len, "%02x", *authKeyID.ptr++);
+               pos += n; len -= n;
+       }
+
+       /* add the file suffix */
+       n = snprintf(pos, len, ".crl");
+
+       if (crl->write_to_file(crl, path, 0022, TRUE))
+       {
+               identification_t *crluri = identification_create_from_encoding(ID_DER_ASN1_GN_URI, uri);
+
+               add_identification(this->crluris, crluri);
+       }
+}
+
+/**
  *  Implements ca_info_t.verify_by_crl.
  */
-static cert_status_t verify_by_crl(private_ca_info_t* this,
-                                                                  certinfo_t *certinfo)
+static cert_status_t verify_by_crl(private_ca_info_t* this, certinfo_t *certinfo,
+                                                                  const char *crl_dir)
 {
        rsa_public_key_t *issuer_public_key = this->cacert->get_public_key(this->cacert);
        bool stale;
@@ -448,20 +501,25 @@ static cert_status_t verify_by_crl(private_ca_info_t* this,
                                        this->crl->destroy(this->crl);
                                        this->crl = crl;
                                        DBG1(" thisUpdate is newer - existing crl replaced");
-                                       if (this->crl->is_valid(this->crl))
-                                       {
-                                               /* we found a valid crl and exit the fetch loop */
-                                               break;
-                                       }
-                                       else
-                                       {
-                                               DBG1("fetched crl is stale");
-                                       }
                                }
                                else
                                {
                                        crl->destroy(crl);
                                        DBG1("thisUpdate is not newer - existing crl retained");
+                                       continue;
+                               }
+                               if (crl->is_valid(crl))
+                               {
+                                       if (cache_crls && strncasecmp(uri_string, "file", 4) != 0)
+                                       {
+                                               cache_crl(this, crl_dir, crl);
+                                       }
+                                       /* we found a valid crl and therefore exit the fetch loop */
+                                       break;
+                               }
+                               else
+                               {
+                                       DBG1("fetched crl is stale");
                                }
                        }
                }
@@ -682,8 +740,9 @@ static void __attribute__ ((constructor))print_register()
 /*
  * Described in header.
  */
-void ca_info_set_crlcheckinterval(u_int interval)
+void ca_info_set_options(bool cache, u_int interval)
 {
+       cache_crls = cache;
        crl_check_interval = interval;
 }
 
@@ -720,7 +779,7 @@ ca_info_t *ca_info_create(const char *name, x509_t *cacert)
        this->public.add_crluri = (void (*) (ca_info_t*,chunk_t))add_crluri;
        this->public.add_ocspuri = (void (*) (ca_info_t*,chunk_t))add_ocspuri;
        this->public.get_certificate = (x509_t* (*) (ca_info_t*))get_certificate;
-       this->public.verify_by_crl = (cert_status_t (*) (ca_info_t*,certinfo_t*))verify_by_crl;
+       this->public.verify_by_crl = (cert_status_t (*) (ca_info_t*,certinfo_t*, const char*))verify_by_crl;
        this->public.verify_by_ocsp = (cert_status_t (*) (ca_info_t*,certinfo_t*,credential_store_t*))verify_by_ocsp;
        this->public.purge_ocsp = (void (*) (ca_info_t*))purge_ocsp;
        this->public.destroy = (void (*) (ca_info_t*))destroy;
index 832fa98..c494a44 100644 (file)
@@ -161,9 +161,10 @@ struct ca_info_t {
         * 
         * @param this                  ca info object
         * @param certinfo              detailed certificate status information
+        * @param crl_dir               directory where fetched crls should be stored
         * @return                              certificate status
         */
-       cert_status_t (*verify_by_crl) (ca_info_t* this, certinfo_t* certinfo);
+       cert_status_t (*verify_by_crl) (ca_info_t *this, certinfo_t *certinfo, const char *crl_dir);
 
        /**
         * @brief Verify the status of a certificate by OCSP
@@ -191,13 +192,14 @@ struct ca_info_t {
 };
 
 /**
- * @brief Create a ca info record
+ * @brief Set ca info options
  * 
+ * @param cache                TRUE if crls shall be cached by storing them
  * @param interval     crl_check_interval to be set in seconds
  * 
  * @ingroup crypto
  */
-void ca_info_set_crlcheckinterval(u_int interval);
+void ca_info_set_options(bool cache, u_int interval);
 
 /**
  * @brief Create a ca info record
index 0b9fdaf..00d6a3a 100755 (executable)
@@ -395,6 +395,14 @@ static void get_status(const private_crl_t *this, certinfo_t *certinfo)
 }
 
 /**
+ * Implements crl_t.write_to_file.
+ */
+static bool write_to_file(private_crl_t *this, const char *path, mode_t mask, bool force)
+{
+       return chunk_write(this->certificateList, path, "crl", mask, force);
+}
+
+/**
  * Implements crl_t.destroy
  */
 static void destroy(private_crl_t *this)
@@ -493,6 +501,7 @@ crl_t *crl_create_from_chunk(chunk_t chunk)
        this->public.is_newer = (bool (*) (const crl_t*,const crl_t*))is_newer;
        this->public.verify = (bool (*) (const crl_t*,const rsa_public_key_t*))verify;
        this->public.get_status = (void (*) (const crl_t*,certinfo_t*))get_status;
+       this->public.write_to_file = (bool (*) (const crl_t*,const char*,mode_t,bool))write_to_file;
        this->public.destroy = (void (*) (crl_t*))destroy;
        
        if (!parse_x509crl(chunk, 0, this))
index 48953ba..8a11fc3 100755 (executable)
@@ -106,6 +106,17 @@ struct crl_t {
        void (*get_status) (const crl_t *this, certinfo_t *certinfo);
 
        /**
+        * @brief Write a der-encoded crl to a file
+        * 
+        * @param this                  calling object
+        * @param path                  path where the file is to be stored
+        * @param mask                  file access control rights
+        * @param force                 overwrite the file if it already exists
+        * @return                              TRUE if successfully written
+        */
+       bool (*write_to_file) (const crl_t *this, const char *path, mode_t mask, bool force);
+
+       /**
         * @brief Destroys the crl.
         * 
         * @param this                  crl to destroy
index a490882..e97c838 100644 (file)
@@ -116,6 +116,10 @@ starter_start_charon (starter_config_t *cfg, bool debug)
     {
        arg[argc++] = "--strictcrlpolicy";
     }
+    if (cfg->setup.cachecrls)
+    {
+       arg[argc++] = "--cachecrls";
+    }
     if (cfg->setup.crlcheckinterval > 0)
     {
        char buffer[BUF_LEN];