This patch is a variant of the patch to implement x509-track for
PolarSSL that was sent to openvpn-devel@ by James Yonan
(<
1456993146-63968-7-git-send-email-james@openvpn.net>). It still uses
some of the original code from James, but proposes a different
implementation.
This patch does the following things differently:
* Do not introduce NID_* defines that need to be maintained. Instead,
just use the short name of the attribute for identification. This
has the advantage that we automatically support everything that
PolarSSL supports, it is less code and we do not have maintain the
list. But the disadvantage is that this approach will not error out
when an unknown attribute name is supplied. PolarSSL (at least 1.3,
I didn't check 2.x) does not provide the functions required to do
that. Instead of erroring out, this implementation will just
silently ignore the unknown --x509-track attribute name.
* Remove the ENABLE_X509_TRACK define completely - it depended just on
ENABLE_CRYPTO anyway.
* Move the --x509-track option parsing out of ENABLE_MANAGEMENT, since
it does not depend on management functionality.
Signed-off-by: Steffan Karger <steffan@karger.me>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Message-Id: <CAA1AbxL1w8e_o-GjS2jETZWxYdMbS2iKABPc6OZBA8bOVycjtA@mail.gmail.com>
URL: http://article.gmane.org/gmane.network.openvpn.devel/11350
Signed-off-by: Gert Doering <gert@greenie.muc.de>
as X509_<depth>_<attribute>=<value>. Multiple
.B \-\-x509\-track
options can be defined to track multiple attributes.
-Not available with PolarSSL.
.\"*********************************************************
.TP
.B \-\-ns\-cert\-type client|server
to.auth_user_pass_file = options->auth_user_pass_file;
#endif
-#ifdef ENABLE_X509_TRACK
to.x509_track = options->x509_track;
-#endif
#if P2MP
#ifdef ENABLE_CLIENT_CR
" of verification.\n"
"--ns-cert-type t: Require that peer certificate was signed with an explicit\n"
" nsCertType designation t = 'client' | 'server'.\n"
-#ifdef ENABLE_X509_TRACK
"--x509-track x : Save peer X509 attribute x in environment for use by\n"
" plugins and management interface.\n"
-#endif
#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000
"--keying-material-exporter label len : Save Exported Keying Material (RFC5705)\n"
" of len bytes (min. 16 bytes) using label in environment for use by plugins.\n"
options->management_flags |= MF_CLIENT_AUTH;
}
#endif
-#ifdef ENABLE_X509_TRACK
- else if (streq (p[0], "x509-track") && p[1] && !p[2])
- {
- VERIFY_PERMISSION (OPT_P_GENERAL);
- x509_track_add (&options->x509_track, p[1], msglevel, &options->gc);
- }
-#endif
#ifdef MANAGEMENT_PF
else if (streq (p[0], "management-client-pf") && !p[1])
{
}
options->key_method = key_method;
}
+ else if (streq (p[0], "x509-track") && p[1] && !p[2])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ x509_track_add (&options->x509_track, p[1], msglevel, &options->gc);
+ }
#ifdef ENABLE_X509ALTUSERNAME
else if (streq (p[0], "x509-username-field") && p[1] && !p[2])
{
#endif /* ENABLE_CRYPTO */
-#ifdef ENABLE_X509_TRACK
const struct x509_track *x509_track;
-#endif
/* special state parms */
int foreign_option_index;
struct man_def_auth_context *mda_context;
#endif
-#ifdef ENABLE_X509_TRACK
const struct x509_track *x509_track;
-#endif
#ifdef ENABLE_CLIENT_CR
const struct static_challenge_info *sci;
*/
static void
verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert_depth,
- const char *subject, const char *common_name
-#ifdef ENABLE_X509_TRACK
- , const struct x509_track *x509_track
-#endif
- )
+ const char *subject, const char *common_name,
+ const struct x509_track *x509_track)
{
char envname[64];
char *serial = NULL;
struct gc_arena gc = gc_new ();
/* Save X509 fields in environment */
-#ifdef ENABLE_X509_TRACK
if (x509_track)
x509_setenv_track (x509_track, es, cert_depth, peer_cert);
else
-#endif
x509_setenv (es, cert_depth, peer_cert);
/* export subject name string as environmental variable */
session->verify_maxlevel = max_int (session->verify_maxlevel, cert_depth);
/* export certificate values to the environment */
- verify_cert_set_env(opt->es, cert, cert_depth, subject, common_name
-#ifdef ENABLE_X509_TRACK
- , opt->x509_track
-#endif
- );
+ verify_cert_set_env(opt->es, cert, cert_depth, subject, common_name,
+ opt->x509_track);
/* export current untrusted IP */
setenv_untrusted (session);
*/
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;
int nid;
};
-void x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc);
-
-#endif
-
/*
* Certificate checking for verify_nsCertType
*/
*/
void x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert);
-#ifdef ENABLE_X509_TRACK
-
/*
* Start tracking the given attribute.
*
void x509_setenv_track (const struct x509_track *xt, struct env_set *es,
const int depth, openvpn_x509_cert_t *x509);
-#endif
-
/*
* Check X.509 Netscape certificate type field, if available.
*
}
-#ifdef ENABLE_X509_TRACK
-
/*
* x509-track implementation -- save X509 fields to environment,
* using the naming convention:
}
gc_free(&gc);
}
-#endif
/*
* Save X509 fields to environment, using the naming convention:
#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_POLARSSL)
+#include "crypto_polarssl.h"
#include "ssl_verify.h"
+#include <polarssl/asn1.h>
#include <polarssl/error.h>
#include <polarssl/bignum.h>
#include <polarssl/oid.h>
return subject;
}
+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 char *
+asn1_buf_to_c_string(const asn1_buf *orig, struct gc_arena *gc)
+{
+ size_t i;
+ char *val;
+
+ for (i = 0; i < orig->len; ++i)
+ if (orig->p[i] == '\0')
+ return "ERROR: embedded null value";
+ val = gc_malloc(orig->len+1, false, gc);
+ memcpy(val, orig->p, orig->len);
+ val[orig->len] = '\0';
+ return val;
+}
+
+static void
+do_setenv_name(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)
+ {
+ const char *xn_short_name = NULL;
+ if (0 == oid_get_attr_short_name (&xn->oid, &xn_short_name) &&
+ 0 == strcmp (xt->name, xn_short_name))
+ {
+ char *val_str = asn1_buf_to_c_string (&xn->val, gc);
+ do_setenv_x509 (es, xt->name, val_str, depth);
+ }
+ }
+}
+
+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->next = *ll_head;
+ *ll_head = xt;
+}
+
+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))
+ {
+ if (0 == strcmp(xt->name, "SHA1"))
+ {
+ /* SHA1 fingerprint is not part of X509 structure */
+ 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);
+ }
+ else
+ {
+ do_setenv_name(es, xt, cert, depth, &gc);
+ }
+ }
+ xt = xt->next;
+ }
+ gc_free(&gc);
+}
+
/*
* Save X509 fields to environment, using the naming convention:
*
#define ENABLE_CRYPTOAPI
#endif
-/*
- * Enable x509-track feature?
- */
-#if defined(ENABLE_CRYPTO) && defined (ENABLE_CRYPTO_OPENSSL)
-#define ENABLE_X509_TRACK
-#endif
-
/*
* Is poll available on this platform?
*/