View Issue Details

IDProjectCategoryView StatusLast Update
0000289bareos-coreGeneralpublic2015-03-25 19:19
Reportermvwieringen Assigned To 
PrioritynormalSeverityfeatureReproducibilityN/A
Status closedResolutionfixed 
PlatformOpenIndianaOSOpenIndianaOS Versionb151a
Product Version14.2.0 
Fixed in Version14.2.1 
Summary0000289: Add openssl CRL reload logic.
DescriptionThe Bareos daemons neither try to reread configured X.509
CRLs from file system if they expire nor if the daemon receives a SIGHUP.
TagsNo tags attached.

Activities

mvwieringen

mvwieringen

2014-04-29 11:14

developer  

0001-Add-openssl-CRL-reload-logic.patch (8,902 bytes)   
From 8cab0ab29fc80d227b143698884e0265472098cf Mon Sep 17 00:00:00 2001
From: Marco van Wieringen <marco.van.wieringen@bareos.com>
Date: Mon, 28 Apr 2014 22:33:00 +0200
Subject: [PATCH] Add openssl CRL reload logic.

The Bareos daemons neither try to reread configured X.509
CRLs from file system if they expire nor if the daemon receives a
SIGHUP.
---
 src/lib/tls_openssl.c |  293 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 288 insertions(+), 5 deletions(-)

diff --git a/src/lib/tls_openssl.c b/src/lib/tls_openssl.c
index a8c50d3..ffa8f94 100644
--- a/src/lib/tls_openssl.c
+++ b/src/lib/tls_openssl.c
@@ -2,6 +2,7 @@
    BAREOSĀ® - Backup Archiving REcovery Open Sourced
 
    Copyright (C) 2005-2010 Free Software Foundation Europe e.V.
+   Copyright (C) 2014-2014 Bareos GmbH & Co. KG
 
    This program is Free Software; you can redistribute it and/or
    modify it under the terms of version three of the GNU Affero General Public
@@ -35,10 +36,16 @@
 #include <openssl/asn1.h>
 #include <openssl/asn1t.h>
 
-/* No anonymous ciphers, no <128 bit ciphers, no export ciphers, no MD5 ciphers */
+/*
+ * No anonymous ciphers, no <128 bit ciphers, no export ciphers, no MD5 ciphers
+ */
 #define TLS_DEFAULT_CIPHERS "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
 
-/* TLS Context Structure */
+#define MAX_CRLS 16
+
+/*
+ * TLS Context Structures
+ */
 struct TLS_Context {
    SSL_CTX *openssl;
    CRYPTO_PEM_PASSWD_CB *pem_callback;
@@ -53,6 +60,278 @@ struct TLS_Connection {
    SSL *openssl;
 };
 
+#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+struct TLS_CRL_Reload_Context {
+   time_t mtime;
+   char *crl_file_name;
+   X509_CRL *crls[MAX_CRLS];
+};
+
+/*
+ * Automatic Certificate Revocation List reload logic.
+ */
+static int crl_reloader_new(X509_LOOKUP *ctx)
+{
+   TLS_CRL_Reload_Context *data;
+
+   data = (TLS_CRL_Reload_Context *)malloc(sizeof(TLS_CRL_Reload_Context));
+   memset(data, 0, sizeof(TLS_CRL_Reload_Context));
+
+   ctx->method_data = (char *)data;
+   return 1;
+}
+
+static void crl_reloader_free(X509_LOOKUP *ctx)
+{
+   int cnt;
+   TLS_CRL_Reload_Context *data;
+
+   if (ctx->method_data) {
+      data = (TLS_CRL_Reload_Context *)ctx->method_data;
+
+      if (data->crl_file_name) {
+         free(data->crl_file_name);
+      }
+
+      for (cnt = 0; cnt < MAX_CRLS; cnt++) {
+         if (data->crls[cnt]) {
+            X509_CRL_free(data->crls[cnt]);
+         }
+      }
+
+      free(data);
+      ctx->method_data = NULL;
+   }
+}
+
+/*
+ * Load the new content from a Certificate Revocation List (CRL).
+ */
+static int crl_reloader_reload_file(X509_LOOKUP *ctx)
+{
+   int cnt, ok = 0;
+   struct stat st;
+   BIO *in = NULL;
+   TLS_CRL_Reload_Context *data;
+
+   data = (TLS_CRL_Reload_Context *)ctx->method_data;
+   if (!data->crl_file_name) {
+      goto bail_out;
+   }
+
+   if (stat(data->crl_file_name, &st) != 0) {
+      goto bail_out;
+   }
+
+   in = BIO_new_file(data->crl_file_name, "r");
+   if (!in) {
+      goto bail_out;
+   }
+
+   /*
+    * Load a maximum of MAX_CRLS Certificate Revocation Lists.
+    */
+   data->mtime = st.st_mtime;
+   for (cnt = 0; cnt < MAX_CRLS; cnt++) {
+      X509_CRL *crl;
+
+      if ((crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL)) == NULL) {
+         if (cnt == 0) {
+            /*
+             * We try to read multiple times only the first is fatal.
+             */
+            goto bail_out;
+         } else {
+            break;
+         }
+      }
+
+      if (data->crls[cnt]) {
+         X509_CRL_free(data->crls[cnt]);
+      }
+      data->crls[cnt] = crl;
+   }
+
+   /*
+    * Clear the other slots.
+    */
+   while (++cnt < MAX_CRLS) {
+      if (data->crls[cnt]) {
+         X509_CRL_free(data->crls[cnt]);
+         data->crls[cnt] = NULL;
+      }
+   }
+
+   ok = 1;
+
+bail_out:
+   if (in) {
+      BIO_free(in);
+   }
+   return ok;
+}
+
+/*
+ * See if the data in the Certificate Revocation List (CRL) is newer then we loaded before.
+ */
+static int crl_reloader_reload_if_newer(X509_LOOKUP *ctx)
+{
+   int ok = 0;
+   TLS_CRL_Reload_Context *data;
+   struct stat st;
+
+   data = (TLS_CRL_Reload_Context *)ctx->method_data;
+   if (!data->crl_file_name) {
+      return ok;
+   }
+
+   if (stat(data->crl_file_name, &st) != 0) {
+      return ok;
+   }
+
+   if (st.st_mtime > data->mtime) {
+      ok = crl_reloader_reload_file(ctx);
+      if (!ok) {
+         goto bail_out;
+      }
+   }
+   ok = 1;
+
+bail_out:
+   return ok;
+}
+
+/*
+ * Load the data from a Certificate Revocation List (CRL) into memory.
+ */
+static int crl_reloader_file_load(X509_LOOKUP *ctx, const char *argp)
+{
+   int ok = 0;
+   TLS_CRL_Reload_Context *data;
+
+   data = (TLS_CRL_Reload_Context *)ctx->method_data;
+   if (data->crl_file_name) {
+      free(data->crl_file_name);
+   }
+   data->crl_file_name = bstrdup(argp);
+
+   ok = crl_reloader_reload_file(ctx);
+   if (!ok) {
+      goto bail_out;
+   }
+   ok = 1;
+
+bail_out:
+   return ok;
+}
+
+static int crl_reloader_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, char **ret)
+{
+   int ok = 0;
+
+   switch (cmd) {
+   case X509_L_FILE_LOAD:
+      ok = crl_reloader_file_load(ctx, argp);
+      break;
+   default:
+      break;
+   }
+
+   return ok;
+}
+
+/*
+ * Check if a CRL entry is expired.
+ */
+static int crl_entry_expired(X509_CRL *crl)
+{
+   int lastUpdate, nextUpdate;
+
+   if (!crl) {
+      return 0;
+   }
+
+   lastUpdate = X509_cmp_current_time(X509_CRL_get_lastUpdate(crl));
+   nextUpdate = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl));
+
+   if (lastUpdate < 0 && nextUpdate > 0) {
+      return 0;
+   }
+
+   return 1;
+}
+
+/*
+ * Retrieve a CRL entry by Subject.
+ */
+static int crl_reloader_get_by_subject(X509_LOOKUP *ctx, int type, X509_NAME *name, X509_OBJECT *ret)
+{
+   int cnt, ok = 0;
+   TLS_CRL_Reload_Context *data = NULL;
+
+   if (type != X509_LU_CRL) {
+      return ok;
+   }
+
+   data = (TLS_CRL_Reload_Context *)ctx->method_data;
+   if (!data->crls[0]) {
+      return ok;
+   }
+
+   ret->type = 0;
+   ret->data.crl = NULL;
+   for (cnt = 0; cnt < MAX_CRLS; cnt++) {
+      if (crl_entry_expired(data->crls[cnt]) && !crl_reloader_reload_if_newer(ctx)) {
+         goto bail_out;
+      }
+
+      if (X509_NAME_cmp(data->crls[cnt]->crl->issuer, name)) {
+         continue;
+      }
+
+      ret->type = type;
+      ret->data.crl = data->crls[cnt];
+      ok = 1;
+      break;
+   }
+
+   return ok;
+
+bail_out:
+   return ok;
+}
+
+static int load_new_crl_file(X509_LOOKUP *lu, const char *fname)
+{
+   int ok = 0;
+
+   if (!fname) {
+      return ok;
+   }
+   ok = X509_LOOKUP_ctrl(lu, X509_L_FILE_LOAD, fname, 0, NULL);
+
+   return ok;
+}
+
+static X509_LOOKUP_METHOD x509_crl_reloader = {
+   "CRL file reloader",
+   crl_reloader_new,            /* new */
+   crl_reloader_free,           /* free */
+   NULL,                        /* init */
+   NULL,                        /* shutdown */
+   crl_reloader_ctrl,           /* ctrl */
+   crl_reloader_get_by_subject, /* get_by_subject */
+   NULL,                        /* get_by_issuer_serial */
+   NULL,                        /* get_by_fingerprint */
+   NULL                         /* get_by_alias */
+};
+
+static X509_LOOKUP_METHOD *X509_LOOKUP_crl_reloader(void)
+{
+   return (&x509_crl_reloader);
+}
+#endif /* (OPENSSL_VERSION_NUMBER > 0x00907000L) */
+
 /*
  * OpenSSL certificate verification callback.
  * OpenSSL has already performed internal certificate verification.
@@ -79,7 +358,9 @@ static int openssl_verify_peer(int ok, X509_STORE_CTX *store)
    return ok;
 }
 
-/* Dispatch user PEM encryption callbacks */
+/*
+ * Dispatch user PEM encryption callbacks
+ */
 static int tls_pem_callback_dispatch (char *buf, int size, int rwflag, void *userdata)
 {
    TLS_CONTEXT *ctx = (TLS_CONTEXT *)userdata;
@@ -148,6 +429,7 @@ TLS_CONTEXT *new_tls_context(const char *ca_certfile,
       goto err;
    }
 
+#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
    /*
     * Set certificate revocation list.
     */
@@ -161,19 +443,20 @@ TLS_CONTEXT *new_tls_context(const char *ca_certfile,
          goto err;
       }
 
-      lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
+      lookup = X509_STORE_add_lookup(store, X509_LOOKUP_crl_reloader());
       if (!lookup) {
          openssl_post_errors(M_FATAL, _("Error loading revocation list file"));
          goto err;
       }
 
-      if (!X509_LOOKUP_load_file(lookup, (char *)crlfile, X509_FILETYPE_PEM)) {
+      if (!load_new_crl_file(lookup, (char *)crlfile)) {
          openssl_post_errors(M_FATAL, _("Error loading revocation list file"));
          goto err;
       }
 
       X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
    }
+#endif
 
    /*
     * Load our certificate file, if available. This file may also contain a
-- 
1.7.3.2

mvwieringen

mvwieringen

2014-04-29 11:17

developer   ~0000841

Added some example code based on some examples found on the internet.
Adapted to the bareos coding standard and using our low level API.
Only tested to compile nothing else. Number of CRLs is currently arbitrary.
mvwieringen

mvwieringen

2014-05-08 12:43

developer   ~0000849

Fix committed to bareos master branch with changesetid 1745.
mvwieringen

mvwieringen

2015-03-25 16:51

developer   ~0001473

Fix committed to bareos2015 bareos-14.2 branch with changesetid 4794.
joergs

joergs

2015-03-25 19:19

developer   ~0001622

Due to the reimport of the Github repository to bugs.bareos.org, the status of some tickets have been changed. These tickets will be closed again.
Sorry for the noise.

Related Changesets

bareos: master b589fbfc

2014-04-28 22:33

mvwieringen

Ported: N/A

Details Diff
Add openssl CRL reload logic.

The Bareos daemons neither try to reread configured X.509
CRLs from file system if they expire nor if the daemon receives a
SIGHUP.

Fixes 0000289: Add openssl CRL reload logic.
Affected Issues
0000289
mod - src/lib/tls_openssl.c Diff File

bareos2015: bareos-14.2 148800b5

2014-04-29 00:33

mvwieringen

Ported: N/A

Details Diff
Add openssl CRL reload logic.

The Bareos daemons neither try to reread configured X.509
CRLs from file system if they expire nor if the daemon receives a
SIGHUP.

Fixes 0000289: Add openssl CRL reload logic.
Affected Issues
0000289
mod - src/lib/tls_openssl.c Diff File

Issue History

Date Modified Username Field Change
2014-04-29 11:08 mvwieringen New Issue
2014-04-29 11:08 mvwieringen Status new => assigned
2014-04-29 11:08 mvwieringen Assigned To => mvwieringen
2014-04-29 11:14 mvwieringen File Added: 0001-Add-openssl-CRL-reload-logic.patch
2014-04-29 11:17 mvwieringen Note Added: 0000841
2014-05-08 12:43 mvwieringen Changeset attached => bareos master b589fbfc
2014-05-08 12:43 mvwieringen Note Added: 0000849
2014-05-08 12:43 mvwieringen Status assigned => resolved
2014-05-08 12:43 mvwieringen Resolution open => fixed
2014-12-01 11:52 joergs Status resolved => closed
2014-12-01 11:52 joergs Assigned To mvwieringen =>
2014-12-01 11:52 joergs Fixed in Version => 14.2.1
2015-03-25 16:51 mvwieringen Changeset attached => bareos2015 bareos-14.2 148800b5
2015-03-25 16:51 mvwieringen Note Added: 0001473
2015-03-25 16:51 mvwieringen Status closed => resolved
2015-03-25 19:19 joergs Note Added: 0001622
2015-03-25 19:19 joergs Status resolved => closed