summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdriaan de Jong <dejong@fox-it.com>2011-06-30 13:43:46 +0200
committerDavid Sommerseth <davids@redhat.com>2011-10-21 14:51:45 +0200
commitfe100528c780548c21d664d1c14b37cbfd4c3e0f (patch)
tree3a07195a53b59992e379515fd0f6cbd654dbe699
parent19dd3ef12f45b2c70c0657ea72fbdce5241e45c2 (diff)
downloadopenvpn-fe100528c780548c21d664d1c14b37cbfd4c3e0f.tar.gz
openvpn-fe100528c780548c21d664d1c14b37cbfd4c3e0f.tar.xz
openvpn-fe100528c780548c21d664d1c14b37cbfd4c3e0f.zip
Refactored: separated environment setup during verification
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>
-rw-r--r--ssl.c218
-rw-r--r--ssl.h15
-rw-r--r--ssl_verify.c75
-rw-r--r--ssl_verify.h22
-rw-r--r--ssl_verify_backend.h43
-rw-r--r--ssl_verify_openssl.c168
6 files changed, 313 insertions, 228 deletions
diff --git a/ssl.c b/ssl.c
index ef06782..ac337e0 100644
--- 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 0963c37..3bad848 100644
--- a/ssl.h
+++ b/ssl.h
@@ -145,21 +145,6 @@
*/
/* #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.
diff --git a/ssl_verify.c b/ssl_verify.c
index 928344c..5f743da 100644
--- a/ssl_verify.c
+++ b/ssl_verify.c
@@ -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
diff --git a/ssl_verify.h b/ssl_verify.h
index ad94bc6..03a7942 100644
--- a/ssl_verify.h
+++ b/ssl_verify.h
@@ -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_ */
diff --git a/ssl_verify_backend.h b/ssl_verify_backend.h
index 82109c8..a32f0ea 100644
--- a/ssl_verify_backend.h
+++ b/ssl_verify_backend.h
@@ -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_ */
diff --git a/ssl_verify_openssl.c b/ssl_verify_openssl.c
index 1037474..417e5d7 100644
--- a/ssl_verify_openssl.c
+++ b/ssl_verify_openssl.c
@@ -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);
+ }
+}