[OpenVPN home] [Date Prev] [Date Index] [Date Next]
[OpenVPN mailing lists] [Thread Prev] [Thread Index] [Thread Next]
Google
 
Web openvpn.net

[Openvpn-devel] Multiple CRLs : a patch for a "crl-verify-path" option


  • Subject: [Openvpn-devel] Multiple CRLs : a patch for a "crl-verify-path" option
  • From: Thomas NOEL <thomas.noel@xxxxxxx>
  • Date: Tue, 10 May 2005 17:18:47 +0200

Hi,

As I said on "openvpn-users", OpenVPN can't handle multiple CRL. It's an issue when the PKI have multiple CAs, typically an offline root CA and intermediate CAs.

Attached is a patch for a "--crl-verify-path" option.

The idea is to follow the "openssl way of life" : each CRL is named "0a1b2c3d.r0" where 0a1b2c3d is the hash of the CA DN. Typically, on Unix systems, we builds symlinks to CRLs files with "c_rehash /path/to/crls/".

When OpenVPN must validate a certificate issued by "0a1b2c3d", "--crl-verify-path /etc/openvpn/crls/" will check for any 0a1b2c3d.r{0,1,..,9} CRL file in the /etc/openvpn/crls/ directory.

If the CRL file and the certificate issuers are the same, then
OpenVPN normally check the CRL (as with --crl-file ...).

If no CRL file is found or no CRL file match the cert issuer, an error occured.

Thanks,
--
Thomas
diff -Nru --exclude=debian --exclude='*win32*' --exclude=plugin openvpn-2.0.orig/init.c openvpn-2.0/init.c
--- openvpn-2.0.orig/init.c	2005-04-11 05:43:56.000000000 +0200
+++ openvpn-2.0/init.c	2005-05-10 16:23:11.000000000 +0200
@@ -1307,6 +1307,7 @@
   to.verify_command = options->tls_verify;
   to.verify_x509name = options->tls_remote;
   to.crl_file = options->crl_file;
+  to.crl_path = options->crl_path;
   to.ns_cert_type = options->ns_cert_type;
   to.es = c->c2.es;
 
diff -Nru --exclude=debian --exclude='*win32*' --exclude=plugin openvpn-2.0.orig/options.c openvpn-2.0/options.c
--- openvpn-2.0.orig/options.c	2005-04-17 00:03:15.000000000 +0200
+++ openvpn-2.0/options.c	2005-05-10 16:25:55.000000000 +0200
@@ -421,6 +421,9 @@
   "--askpass [file]: Get PEM password from controlling tty before we daemonize.\n"
   "--auth-nocache  : Don't cache --askpass or --auth-user-pass passwords.\n"
   "--crl-verify crl: Check peer certificate against a CRL.\n"
+  "--crl-verify-path path: Check peer certificate against a CRL directory.\n"
+  "                  This directory must contain all CRLs with their 'hashed'\n"
+  "                  name. path must have a trailing slash (/) on Unix system.\n"
   "--tls-verify cmd: Execute shell command cmd to verify the X509 name of a\n"
   "                  pending TLS connection that has otherwise passed all other\n"
   "                  tests of certification.  cmd should return 0 to allow\n"
@@ -1107,6 +1110,7 @@
   SHOW_STR (tls_verify);
   SHOW_STR (tls_remote);
   SHOW_STR (crl_file);
+  SHOW_STR (crl_path);
   SHOW_INT (ns_cert_type);
 
   SHOW_INT (tls_timeout);
@@ -1636,6 +1640,7 @@
       MUST_BE_UNDEF (single_session);
       MUST_BE_UNDEF (tls_exit);
       MUST_BE_UNDEF (crl_file);
+      MUST_BE_UNDEF (crl_path);
       MUST_BE_UNDEF (key_method);
       MUST_BE_UNDEF (ns_cert_type);
 
@@ -4348,6 +4353,12 @@
       VERIFY_PERMISSION (OPT_P_GENERAL);
       options->crl_file = p[1];
     }
+  else if (streq (p[0], "crl-verify-path") && p[1])
+    {
+      ++i;
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      options->crl_path = p[1];
+    }
   else if (streq (p[0], "tls-verify") && p[1])
     {
       ++i;
diff -Nru --exclude=debian --exclude='*win32*' --exclude=plugin openvpn-2.0.orig/options.h openvpn-2.0/options.h
--- openvpn-2.0.orig/options.h	2005-04-11 05:43:57.000000000 +0200
+++ openvpn-2.0/options.h	2005-05-10 16:22:44.000000000 +0200
@@ -364,6 +364,7 @@
   const char *tls_verify;
   const char *tls_remote;
   const char *crl_file;
+  const char *crl_path;
   int ns_cert_type; /* set to 0, NS_SSL_SERVER, or NS_SSL_CLIENT */
 #ifdef WIN32
   const char *cryptoapi_cert;
diff -Nru --exclude=debian --exclude='*win32*' --exclude=plugin openvpn-2.0.orig/ssl.c openvpn-2.0/ssl.c
--- openvpn-2.0.orig/ssl.c	2005-04-11 05:43:55.000000000 +0200
+++ openvpn-2.0/ssl.c	2005-05-10 16:55:33.000000000 +0200
@@ -620,6 +620,78 @@
 	goto err;
     }
 
+  if (opt->crl_path) {
+    unsigned long hash;
+    int r;
+    char crl_filename[256];
+    int is_revoked = 0;
+
+    hash = X509_NAME_hash(X509_get_issuer_name(ctx->current_cert));
+
+    for (r = 0 ; r < 10 /* FIXME: how many... ? */; r++) {
+      X509_CRL *crl=NULL;
+      X509_REVOKED *revoked;
+      BIO *in=NULL;
+      int n,i;
+
+      openvpn_snprintf(crl_filename, sizeof(crl_filename), "%s%8x.r%d", opt->crl_path, hash, r );
+      /* msg (D_HANDSHAKE, "VERIFY CRL: %s", crl_filename); // DEBUG */
+
+      in=BIO_new(BIO_s_file());
+
+      if (in == NULL) {
+	msg (M_WARN, "CRL: BIO err");
+	goto next;
+      }
+      if (BIO_read_filename(in, crl_filename) <= 0) {
+	msg (M_WARN, "CRL: cannot read: %s", crl_filename);
+	goto next;
+      }
+      crl=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL);
+      if (crl == NULL) {
+	msg (M_WARN, "CRL: cannot read CRL from file %s", crl_filename);
+	goto next;
+      }
+
+      if (X509_NAME_cmp(X509_CRL_get_issuer(crl), X509_get_issuer_name(ctx->current_cert)) != 0) {
+	/* msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of certificate %s", crl_filename, subject); */
+	goto next;
+      }
+
+      n = sk_num(X509_CRL_get_REVOKED(crl));
+
+      for (i = 0; i < n; i++) {
+	revoked = (X509_REVOKED *)sk_value(X509_CRL_get_REVOKED(crl), i);
+	if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(ctx->current_cert)) == 0) {
+	  msg (D_HANDSHAKE, "CRL CHECK FAILED (%s): %s is REVOKED", crl_filename, subject);
+	  is_revoked = 1;
+	  goto err;
+	}
+      }
+
+      is_revoked = -1; 
+
+    next:
+
+      BIO_free(in);
+      if (crl)
+        X509_CRL_free (crl);
+      if (is_revoked == 1)
+        goto err;
+      else if (is_revoked == -1) {
+        msg (D_HANDSHAKE, "CRL CHECK OK (%s): %s", crl_filename, subject);
+	break;
+      }
+
+    } /* for */
+
+    if (is_revoked == 0) {
+      msg (D_HANDSHAKE, "CRL CHECK FAILED: no valid CRL found in %s for %s", opt->crl_path, subject);
+      goto err;
+    } 
+
+  }
+
   msg (D_HANDSHAKE, "VERIFY OK: depth=%d, %s", ctx->error_depth, subject);
 
   session->verified = true;
diff -Nru --exclude=debian --exclude='*win32*' --exclude=plugin openvpn-2.0.orig/ssl.h openvpn-2.0/ssl.h
--- openvpn-2.0.orig/ssl.h	2005-04-11 05:43:56.000000000 +0200
+++ openvpn-2.0/ssl.h	2005-05-10 16:22:57.000000000 +0200
@@ -409,6 +409,7 @@
   const char *verify_command;
   const char *verify_x509name;
   const char *crl_file;
+  const char *crl_path;
   int ns_cert_type;
 
   /* allow openvpn config info to be