Signed-off-by: James Yonan <ja...@openvpn.net>
---
 src/openvpn/ssl_verify_polarssl.c | 166 ++++++++++++++++++++++++++++++++++++++
 src/openvpn/syshead.h             |   2 +-
 2 files changed, 167 insertions(+), 1 deletion(-)

diff --git a/src/openvpn/ssl_verify_polarssl.c 
b/src/openvpn/ssl_verify_polarssl.c
index 9d0d086..ab693d2 100644
--- a/src/openvpn/ssl_verify_polarssl.c
+++ b/src/openvpn/ssl_verify_polarssl.c
@@ -198,6 +198,172 @@ x509_get_subject(x509_crt *cert, struct gc_arena *gc)
   return subject;
 }

+#ifdef ENABLE_X509_TRACK
+
+/* these match NID's in OpenSSL crypto/objects/objects.h */
+#define NID_undef                      0
+#define NID_sha1                        64
+#define NID_commonName                  13
+#define NID_countryName                 14
+#define NID_localityName                15
+#define NID_stateOrProvinceName         16
+#define NID_organizationName           17
+#define NID_organizationalUnitName      18
+#define NID_pkcs9_emailAddress          48
+
+struct nid_entry {
+  const char *name;
+  int nid;
+};
+
+static const struct nid_entry nid_list[] = {
+  { "SHA1",         NID_sha1 },
+  { "CN",           NID_commonName },
+  { "C",            NID_countryName },
+  { "L",            NID_localityName },
+  { "ST",           NID_stateOrProvinceName },
+  { "O",            NID_organizationName },
+  { "OU",           NID_organizationalUnitName },
+  { "emailAddress", NID_pkcs9_emailAddress },
+  { NULL, 0 }
+};
+
+static int
+name_to_nid(const char *name)
+{
+  const struct nid_entry *e = nid_list;
+  while (e->name)
+    {
+      if (!strcmp(name, e->name))
+       return e->nid;
+      ++e;
+    }
+  return NID_undef;
+}
+
+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
+do_setenv_nid_value(struct env_set *es, const struct x509_track *xt, const 
x509_name *xn,
+                   int depth, struct gc_arena *gc)
+{
+  size_t i;
+  char *val;
+
+  for (i = 0; i < xn->val.len; ++i)
+    if (xn->val.p[i] == '\0') /* error if embedded null in value */
+      return;
+  val = gc_malloc(xn->val.len+1, false, gc);
+  memcpy(val, xn->val.p, xn->val.len);
+  val[xn->val.len] = '\0';
+  do_setenv_x509(es, xt->name, val, depth);
+}
+
+static void
+do_setenv_nid(struct env_set *es, const struct x509_track *xt, const x509_crt 
*cert,
+             int depth, struct gc_arena *gc)
+{
+  const x509_name *xn;
+  for (xn = &cert->subject; xn != NULL; xn = xn->next)
+    {
+      switch (xt->nid)
+       {
+       case NID_commonName:
+         if (OID_CMP(OID_AT_CN, &xn->oid))
+           do_setenv_nid_value(es, xt, xn, depth, gc);
+         break;
+       case NID_countryName:
+         if (OID_CMP(OID_AT_COUNTRY, &xn->oid))
+           do_setenv_nid_value(es, xt, xn, depth, gc);
+         break;
+       case NID_localityName:
+         if (OID_CMP(OID_AT_LOCALITY, &xn->oid))
+           do_setenv_nid_value(es, xt, xn, depth, gc);
+         break;
+       case NID_stateOrProvinceName:
+         if (OID_CMP(OID_AT_STATE, &xn->oid))
+           do_setenv_nid_value(es, xt, xn, depth, gc);
+         break;
+       case NID_organizationName:
+         if (OID_CMP(OID_AT_ORGANIZATION, &xn->oid))
+           do_setenv_nid_value(es, xt, xn, depth, gc);
+         break;
+       case NID_organizationalUnitName:
+         if (OID_CMP(OID_AT_ORG_UNIT, &xn->oid))
+           do_setenv_nid_value(es, xt, xn, depth, gc);
+         break;
+       case NID_pkcs9_emailAddress:
+         if (OID_CMP(OID_PKCS9_EMAIL, &xn->oid))
+           do_setenv_nid_value(es, xt, xn, depth, gc);
+         break;
+       }
+    }
+}
+
+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 = name_to_nid(name);
+  if (xt->nid != NID_undef)
+    {
+      xt->next = *ll_head;
+      *ll_head = xt;
+    }
+  else
+    msg(msglevel, "x509_track: no such attribute '%s'", name);
+}
+
+void
+x509_setenv_track (const struct x509_track *xt, struct env_set *es, const int 
depth, x509_crt *cert)
+{
+  struct gc_arena gc = gc_new();
+  while (xt)
+    {
+      if (depth == 0 || (xt->flags & XT_FULL_CHAIN))
+       {
+         switch (xt->nid)
+           {
+           case NID_sha1:
+             {
+               unsigned char *sha1_hash = x509_get_sha1_hash(cert, &gc);
+               char *sha1_fingerprint = format_hex_ex(sha1_hash, 
SHA_DIGEST_LENGTH, 0, 1 | FHE_CAPS, ":", &gc);
+               do_setenv_x509(es, xt->name, sha1_fingerprint, depth);
+             }
+             break;
+           default:
+             do_setenv_nid(es, xt, cert, depth, &gc);
+             break;
+           }
+       }
+      xt = xt->next;
+    }
+  gc_free(&gc);
+}
+
+#endif
+
 /*
  * Save X509 fields to environment, using the naming convention:
  *
diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h
index 7e77b6c..25aa69b 100644
--- a/src/openvpn/syshead.h
+++ b/src/openvpn/syshead.h
@@ -634,7 +634,7 @@ socket_defined (const socket_descriptor_t sd)
 /*
  * Enable x509-track feature?
  */
-#if defined(ENABLE_CRYPTO) && defined (ENABLE_CRYPTO_OPENSSL)
+#if defined(ENABLE_CRYPTO) && (defined(ENABLE_CRYPTO_OPENSSL) || 
defined(ENABLE_CRYPTO_POLARSSL))
 #define ENABLE_X509_TRACK
 #endif

-- 
1.9.1


Reply via email to