]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Refactored: separated environment setup during verification
authorAdriaan de Jong <dejong@fox-it.com>
Thu, 30 Jun 2011 11:43:46 +0000 (13:43 +0200)
committerDavid Sommerseth <davids@redhat.com>
Fri, 21 Oct 2011 12:51:45 +0000 (14:51 +0200)
Signed-off-by: Adriaan de Jong <dejong@fox-it.com>
Acked-by: James Yonan <james@openvpn.net>
Signed-off-by: David Sommerseth <davids@redhat.com>
ssl.c
ssl.h
ssl_verify.c
ssl_verify.h
ssl_verify_backend.h
ssl_verify_openssl.c

diff --git a/ssl.c b/ssl.c
index ef0678286a3126f9056e363147ebdc6725ea3e32..ac337e0828bd881534fd482bbf15cfcd2acf061c 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -296,150 +296,6 @@ ssl_put_auth_challenge (const char *cr_str)
 
 #endif
 
-#ifdef ENABLE_X509_TRACK
-/*
- * setenv_x509_track function -- save X509 fields to environment,
- * using the naming convention:
- *
- *  X509_{cert_depth}_{name}={value}
- *
- * This function differs from setenv_x509 below in the following ways:
- *
- * (1) Only explicitly named attributes in xt are saved, per usage
- *     of --x509-track program options.
- * (2) Only the level 0 cert info is saved unless the XT_FULL_CHAIN
- *     flag is set in xt->flags (corresponds with prepending a '+'
- *     to the name when specified by --x509-track program option).
- * (3) This function supports both X509 subject name fields as
- *     well as X509 V3 extensions.
- */
-
-/* worker method for setenv_x509_track */
-static void
-do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth)
-{
-  char *name_expand;
-  size_t name_expand_size;
-
-  string_mod (value, CC_ANY, CC_CRLF, '?');
-  msg (D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth);
-  name_expand_size = 64 + strlen (name);
-  name_expand = (char *) malloc (name_expand_size);
-  check_malloc_return (name_expand);
-  openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", depth, name);
-  setenv_str (es, name_expand, value);
-  free (name_expand);
-}
-
-static void
-setenv_x509_track (const struct x509_track *xt, struct env_set *es, const int depth, X509 *x509)
-{
-  X509_NAME *x509_name = X509_get_subject_name (x509);
-  const char nullc = '\0';
-  int i;
-
-  while (xt)
-    {
-      if (depth == 0 || (xt->flags & XT_FULL_CHAIN))
-       {
-         i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1);
-         if (i >= 0)
-           {
-             X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i);
-             if (ent)
-               {
-                 ASN1_STRING *val = X509_NAME_ENTRY_get_data (ent);
-                 unsigned char *buf;
-                 buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
-                 if (ASN1_STRING_to_UTF8 (&buf, val) > 0)
-                   {
-                     do_setenv_x509(es, xt->name, (char *)buf, depth);
-                     OPENSSL_free (buf);
-                   }
-               }
-           }
-         else
-           {
-             i = X509_get_ext_by_NID(x509, xt->nid, -1);
-             if (i >= 0)
-               {
-                 X509_EXTENSION *ext = X509_get_ext(x509, i);
-                 if (ext)
-                   {
-                     BIO *bio = BIO_new(BIO_s_mem());
-                     if (bio)
-                       {
-                         if (X509V3_EXT_print(bio, ext, 0, 0))
-                           {
-                             if (BIO_write(bio, &nullc, 1) == 1)
-                               {
-                                 char *str;
-                                 BIO_get_mem_data(bio, &str);
-                                 do_setenv_x509(es, xt->name, str, depth);
-                               }
-                           }
-                         BIO_free(bio);
-                       }
-                   }
-               }
-           }
-       }
-      xt = xt->next;
-    }
-}
-#endif
-
-/*
- * Save X509 fields to environment, using the naming convention:
- *
- *  X509_{cert_depth}_{name}={value}
- */
-static void
-setenv_x509 (struct env_set *es, const int error_depth, X509_NAME *x509)
-{
-  int i, n;
-  int fn_nid;
-  ASN1_OBJECT *fn;
-  ASN1_STRING *val;
-  X509_NAME_ENTRY *ent;
-  const char *objbuf;
-  unsigned char *buf;
-  char *name_expand;
-  size_t name_expand_size;
-
-  n = X509_NAME_entry_count (x509);
-  for (i = 0; i < n; ++i)
-    {
-      ent = X509_NAME_get_entry (x509, i);
-      if (!ent)
-       continue;
-      fn = X509_NAME_ENTRY_get_object (ent);
-      if (!fn)
-       continue;
-      val = X509_NAME_ENTRY_get_data (ent);
-      if (!val)
-       continue;
-      fn_nid = OBJ_obj2nid (fn);
-      if (fn_nid == NID_undef)
-       continue;
-      objbuf = OBJ_nid2sn (fn_nid);
-      if (!objbuf)
-       continue;
-      buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
-      if (ASN1_STRING_to_UTF8 (&buf, val) <= 0)
-       continue;
-      name_expand_size = 64 + strlen (objbuf);
-      name_expand = (char *) malloc (name_expand_size);
-      check_malloc_return (name_expand);
-      openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", error_depth, objbuf);
-      string_mod (name_expand, CC_PRINT, CC_CRLF, '_');
-      string_mod ((char*)buf, CC_PRINT, CC_CRLF, '_');
-      setenv_str (es, name_expand, (char*)buf);
-      free (name_expand);
-      OPENSSL_free (buf);
-    }
-}
-
 static void
 setenv_untrusted (struct tls_session *session)
 {
@@ -602,7 +458,6 @@ verify_cert(struct tls_session *session, x509_cert_t *cert, int cert_depth)
   char common_name[TLS_USERNAME_LEN] = {0};
   const struct tls_options *opt;
   struct argv argv = argv_new ();
-  char *serial = NULL;
 
   opt = session->opt;
   ASSERT (opt);
@@ -617,14 +472,6 @@ verify_cert(struct tls_session *session, x509_cert_t *cert, int cert_depth)
         goto err;
     }
 
-  /* Save X509 fields in environment */
-#ifdef ENABLE_X509_TRACK
-  if (opt->x509_track)
-    setenv_x509_track (opt->x509_track, opt->es, cert_depth, cert);
-  else
-#endif
-    setenv_x509 (opt->es, cert_depth, X509_get_subject_name (cert));
-
   /* enforce character class restrictions in X509 name */
   string_mod_sslname (subject, X509_NAME_CHAR_CLASS, opt->ssl_flags);
   string_replace_leading (subject, '-', '_');
@@ -677,39 +524,10 @@ verify_cert(struct tls_session *session, x509_cert_t *cert, int cert_depth)
   if (cert_depth == 0)
     set_common_name (session, common_name);
 
-  /* export subject name string as environmental variable */
   session->verify_maxlevel = max_int (session->verify_maxlevel, cert_depth);
-  openvpn_snprintf (envname, sizeof(envname), "tls_id_%d", cert_depth);
-  setenv_str (opt->es, envname, subject);
-
-#ifdef ENABLE_EUREPHIA
-  /* export X509 cert SHA1 fingerprint */
-  {
-    struct gc_arena gc = gc_new ();
-    openvpn_snprintf (envname, sizeof(envname), "tls_digest_%d", cert_depth);
-    setenv_str (opt->es, envname,
-               format_hex_ex(cert->sha1_hash, SHA_DIGEST_LENGTH, 0, 1, ":", &gc));
-    gc_free(&gc);
-  }
-#endif
-#if 0
-  /* export common name string as environmental variable */
-  openvpn_snprintf (envname, sizeof(envname), "tls_common_name_%d", cert_depth);
-  setenv_str (opt->es, envname, common_name);
-#endif
 
-  /* export serial number as environmental variable,
-     use bignum in case serial number is large */
-  {
-    ASN1_INTEGER *asn1_i;
-    BIGNUM *bignum;
-    asn1_i = X509_get_serialNumber(cert);
-    bignum = ASN1_INTEGER_to_BN(asn1_i, NULL);
-    serial = BN_bn2dec(bignum);
-    openvpn_snprintf (envname, sizeof(envname), "tls_serial_%d", cert_depth);
-    setenv_str (opt->es, envname, serial);
-    BN_free(bignum);
-  }
+  /* export certificate values to the environment */
+  verify_cert_set_env(opt->es, cert, cert_depth, subject, common_name, opt->x509_track);
 
   /* export current untrusted IP */
   setenv_untrusted (session);
@@ -852,18 +670,22 @@ verify_cert(struct tls_session *session, x509_cert_t *cert, int cert_depth)
        {
          char fn[256];
          int fd;
+         char *serial = verify_get_serial(cert);
          if (!openvpn_snprintf(fn, sizeof(fn), "%s%c%s", opt->crl_file, OS_SPECIFIC_DIRSEP, serial))
            {
              msg (D_HANDSHAKE, "VERIFY CRL: filename overflow");
+             verify_free_serial(serial);
              goto err;
            }
          fd = open (fn, O_RDONLY);
          if (fd >= 0)
            {
              msg (D_HANDSHAKE, "VERIFY CRL: certificate serial number %s is revoked", serial);
+             verify_free_serial(serial);
              close(fd);
              goto err;
            }
+         verify_free_serial(serial);
        }
       else
        {
@@ -922,8 +744,6 @@ verify_cert(struct tls_session *session, x509_cert_t *cert, int cert_depth)
 
  done:
   OPENSSL_free (subject);
-  if (serial)
-    OPENSSL_free(serial);
   argv_reset (&argv);
   return (session->verified == true) ? 1 : 0;
 
@@ -935,32 +755,6 @@ verify_cert(struct tls_session *session, x509_cert_t *cert, int cert_depth)
 
 /** @} name Function for authenticating a new connection from a remote OpenVPN peer */
 
-#ifdef ENABLE_X509_TRACK
-
-void
-x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc)
-{
-  struct x509_track *xt;
-  ALLOC_OBJ_CLEAR_GC (xt, struct x509_track, gc);
-  if (*name == '+')
-    {
-      xt->flags |= XT_FULL_CHAIN;
-      ++name;
-    }
-  xt->name = name;
-  xt->nid = OBJ_txt2nid(name);
-  if (xt->nid != NID_undef)
-    {
-      xt->next = *ll_head;
-      *ll_head = xt;
-    }
-  else
-    msg(msglevel, "x509_track: no such attribute '%s'", name);
-}
-
-#endif
-
-
 /*
  * Initialize SSL context.
  * All files are in PEM format.
diff --git a/ssl.h b/ssl.h
index 0963c37a58ef3f092b66220698ed32b5e963d95d..3bad848fe386086f9f237063d2cb720066458d1a 100644 (file)
--- a/ssl.h
+++ b/ssl.h
  */
 /* #define MEASURE_TLS_HANDSHAKE_STATS */
 
-#ifdef ENABLE_X509_TRACK
-
-struct x509_track
-{
-  const struct x509_track *next;
-  const char *name;
-# define XT_FULL_CHAIN (1<<0)
-  unsigned int flags;
-  int nid;
-};
-
-void x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc);
-
-#endif
-
 /*
  * Used in --mode server mode to check tls-auth signature on initial
  * packets received from new clients.
index 928344c81ff0904392104d607581dcf22c9c4765..5f743dadb00d5e49e150f32c8491c05c770a8dc8 100644 (file)
@@ -281,6 +281,81 @@ tls_lock_cert_hash_set (struct tls_multi *multi)
     multi->locked_cert_hash_set = cert_hash_copy (chs);
 }
 
+#ifdef ENABLE_X509_TRACK
+
+void
+x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc)
+{
+  struct x509_track *xt;
+  ALLOC_OBJ_CLEAR_GC (xt, struct x509_track, gc);
+  if (*name == '+')
+    {
+      xt->flags |= XT_FULL_CHAIN;
+      ++name;
+    }
+  xt->name = name;
+  xt->nid = OBJ_txt2nid(name);
+  if (xt->nid != NID_undef)
+    {
+      xt->next = *ll_head;
+      *ll_head = xt;
+    }
+  else
+    msg(msglevel, "x509_track: no such attribute '%s'", name);
+}
+
+#endif
+
+/*
+ * Export the subject, common_name, and raw certificate fields to the
+ * environment for later verification by scripts and plugins.
+ */
+void
+verify_cert_set_env(struct env_set *es, x509_cert_t *peer_cert, int cert_depth,
+    const char *subject, const char *common_name,
+    const struct x509_track *x509_track)
+{
+  char envname[64];
+
+  /* Save X509 fields in environment */
+#ifdef ENABLE_X509_TRACK
+  if (x509_track)
+    setenv_x509_track (x509_track, es, cert_depth, peer_cert);
+  else
+#endif
+    setenv_x509 (es, cert_depth, peer_cert);
+
+  /* export subject name string as environmental variable */
+  openvpn_snprintf (envname, sizeof(envname), "tls_id_%d", cert_depth);
+  setenv_str (es, envname, subject);
+
+#if 0
+  /* export common name string as environmental variable */
+  openvpn_snprintf (envname, sizeof(envname), "tls_common_name_%d", cert_depth);
+  setenv_str (es, envname, common_name);
+#endif
+
+#ifdef ENABLE_EUREPHIA
+  /* export X509 cert SHA1 fingerprint */
+  {
+    struct gc_arena gc = gc_new ();
+    openvpn_snprintf (envname, sizeof(envname), "tls_digest_%d", cert_depth);
+    setenv_str (es, envname,
+         format_hex_ex(peer_cert->sha1_hash, SHA_DIGEST_LENGTH, 0, 1, ":", &gc));
+    gc_free(&gc);
+  }
+#endif
+
+  /* export serial number as environmental variable,
+     use bignum in case serial number is large */
+  {
+    char *serial = verify_get_serial(peer_cert);
+    openvpn_snprintf (envname, sizeof(envname), "tls_serial_%d", cert_depth);
+    setenv_str (es, envname, serial);
+    verify_free_serial(serial);
+  }
+}
+
 
 /* ***************************************************************************
  * Functions for the management of deferred authentication when using
index ad94bc685664bf167ccf05ce88193a500810aaeb..03a794227edcfcad314746a6dab527c1e0f78e90 100644 (file)
@@ -40,6 +40,8 @@
 #include "ssl_verify_openssl.h"
 #endif
 
+#include "ssl_verify_backend.h"
+
 /*
  * Keep track of certificate hashes at various depths
  */
@@ -197,6 +199,21 @@ void verify_user_pass(struct user_pass *up, struct tls_multi *multi,
  */
 void verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session);
 
+#ifdef ENABLE_X509_TRACK
+
+struct x509_track
+{
+  const struct x509_track *next;
+  const char *name;
+# define XT_FULL_CHAIN (1<<0)
+  unsigned int flags;
+  int nid;
+};
+
+void x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc);
+
+#endif
+
 /*
  * TODO: document
  */
@@ -215,6 +232,11 @@ tls_client_reason (struct tls_multi *multi)
 #endif
 }
 
+/* TEMP */
+void
+verify_cert_set_env(struct env_set *es, x509_cert_t *peer_cert, int cert_depth,
+    const char *subject, const char *common_name,
+    const struct x509_track *x509_track);
 
 #endif /* SSL_VERIFY_H_ */
 
index 82109c86d6d614918e9cd55f5b708190f7fbabec..a32f0ea6af4a260ab6433af6c9298891118156dd 100644 (file)
@@ -98,6 +98,47 @@ bool verify_get_subject (char **subject, x509_cert_t *cert);
  * @return             \c 1 on failure, \c 0 on success
  */
 bool verify_get_username (char *common_name, int cn_len,
-    char * x509_username_field, X509 *peer_cert);
+    char * x509_username_field, x509_cert_t *peer_cert);
+
+/*
+ * Return the certificate's serial number.
+ *
+ * The serial number is returned as a string, since it might be a bignum.
+ * The returened string must be freed with \c verify_free_serial()
+ *
+ * @param cert         Certificate to retrieve the serial number from.
+ *
+ * @return             The certificate's serial number.
+ */
+char *verify_get_serial (x509_cert_t *cert);
+
+/*
+ * Free a serial number string as returned by \c verify_get_serial()
+ *
+ * @param serial       The string to be freed.
+ */
+void verify_free_serial (char *serial);
+
+/*
+ * TODO: document
+ *
+ * @param xt
+ * @param es           Environment set to save variables in
+ * @param cert_depth   Depth of the certificate
+ * @param cert         Certificate to set the environment for
+ */
+void setenv_x509_track (const struct x509_track *xt, struct env_set *es,
+    const int depth, x509_cert_t *x509);
+
+/*
+ * Save X509 fields to environment, using the naming convention:
+ *
+ * X509_{cert_depth}_{name}={value}
+ *
+ * @param es           Environment set to save variables in
+ * @param cert_depth   Depth of the certificate
+ * @param cert         Certificate to set the environment for
+ */
+void setenv_x509 (struct env_set *es, int cert_depth, x509_cert_t *cert);
 
 #endif /* SSL_VERIFY_BACKEND_H_ */
index 10374740ef0a3742cc7355e5676d0f5adc10ef4c..417e5d73d49c248a3b6861eac5159c5e8f42ea2b 100644 (file)
@@ -209,3 +209,171 @@ verify_get_username (char *common_name, int cn_len,
 
   return false;
 }
+
+char *
+verify_get_serial (x509_cert_t *cert)
+{
+  ASN1_INTEGER *asn1_i;
+  BIGNUM *bignum;
+  char *serial;
+
+  asn1_i = X509_get_serialNumber(cert);
+  bignum = ASN1_INTEGER_to_BN(asn1_i, NULL);
+  serial = BN_bn2dec(bignum);
+
+  BN_free(bignum);
+  return serial;
+}
+
+void
+verify_free_serial (char *serial)
+{
+  if (serial)
+    OPENSSL_free(serial);
+}
+
+#ifdef ENABLE_X509_TRACK
+/*
+ * setenv_x509_track function -- save X509 fields to environment,
+ * using the naming convention:
+ *
+ *  X509_{cert_depth}_{name}={value}
+ *
+ * This function differs from setenv_x509 below in the following ways:
+ *
+ * (1) Only explicitly named attributes in xt are saved, per usage
+ *     of --x509-track program options.
+ * (2) Only the level 0 cert info is saved unless the XT_FULL_CHAIN
+ *     flag is set in xt->flags (corresponds with prepending a '+'
+ *     to the name when specified by --x509-track program option).
+ * (3) This function supports both X509 subject name fields as
+ *     well as X509 V3 extensions.
+ */
+
+/* worker method for setenv_x509_track */
+static void
+do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth)
+{
+  char *name_expand;
+  size_t name_expand_size;
+
+  string_mod (value, CC_ANY, CC_CRLF, '?');
+  msg (D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth);
+  name_expand_size = 64 + strlen (name);
+  name_expand = (char *) malloc (name_expand_size);
+  check_malloc_return (name_expand);
+  openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", depth, name);
+  setenv_str (es, name_expand, value);
+  free (name_expand);
+}
+
+void
+setenv_x509_track (const struct x509_track *xt, struct env_set *es, const int depth, X509 *x509)
+{
+  X509_NAME *x509_name = X509_get_subject_name (x509);
+  const char nullc = '\0';
+  int i;
+
+  while (xt)
+    {
+      if (depth == 0 || (xt->flags & XT_FULL_CHAIN))
+       {
+         i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1);
+         if (i >= 0)
+           {
+             X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i);
+             if (ent)
+               {
+                 ASN1_STRING *val = X509_NAME_ENTRY_get_data (ent);
+                 unsigned char *buf;
+                 buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
+                 if (ASN1_STRING_to_UTF8 (&buf, val) > 0)
+                   {
+                     do_setenv_x509(es, xt->name, (char *)buf, depth);
+                     OPENSSL_free (buf);
+                   }
+               }
+           }
+         else
+           {
+             i = X509_get_ext_by_NID(x509, xt->nid, -1);
+             if (i >= 0)
+               {
+                 X509_EXTENSION *ext = X509_get_ext(x509, i);
+                 if (ext)
+                   {
+                     BIO *bio = BIO_new(BIO_s_mem());
+                     if (bio)
+                       {
+                         if (X509V3_EXT_print(bio, ext, 0, 0))
+                           {
+                             if (BIO_write(bio, &nullc, 1) == 1)
+                               {
+                                 char *str;
+                                 BIO_get_mem_data(bio, &str);
+                                 do_setenv_x509(es, xt->name, str, depth);
+                               }
+                           }
+                         BIO_free(bio);
+                       }
+                   }
+               }
+           }
+       }
+      xt = xt->next;
+    }
+}
+#endif
+
+/*
+ * Save X509 fields to environment, using the naming convention:
+ *
+ *  X509_{cert_depth}_{name}={value}
+ */
+void
+setenv_x509 (struct env_set *es, int cert_depth, x509_cert_t *peer_cert)
+{
+  int i, n;
+  int fn_nid;
+  ASN1_OBJECT *fn;
+  ASN1_STRING *val;
+  X509_NAME_ENTRY *ent;
+  const char *objbuf;
+  unsigned char *buf;
+  char *name_expand;
+  size_t name_expand_size;
+  X509_NAME *x509 = X509_get_subject_name (peer_cert);
+
+  n = X509_NAME_entry_count (x509);
+  for (i = 0; i < n; ++i)
+    {
+      ent = X509_NAME_get_entry (x509, i);
+      if (!ent)
+       continue;
+      fn = X509_NAME_ENTRY_get_object (ent);
+      if (!fn)
+       continue;
+      val = X509_NAME_ENTRY_get_data (ent);
+      if (!val)
+       continue;
+      fn_nid = OBJ_obj2nid (fn);
+      if (fn_nid == NID_undef)
+       continue;
+      objbuf = OBJ_nid2sn (fn_nid);
+      if (!objbuf)
+       continue;
+      buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
+      if (ASN1_STRING_to_UTF8 (&buf, val) <= 0)
+       continue;
+      name_expand_size = 64 + strlen (objbuf);
+      name_expand = (char *) malloc (name_expand_size);
+      check_malloc_return (name_expand);
+      openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", cert_depth,
+         objbuf);
+      string_mod (name_expand, CC_PRINT, CC_CRLF, '_');
+      string_mod ((char*)buf, CC_PRINT, CC_CRLF, '_');
+      setenv_str (es, name_expand, (char*)buf);
+      free (name_expand);
+      OPENSSL_free (buf);
+    }
+}