summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiko Hund <heiko.hund@sophos.com>2012-02-04 12:56:24 +0000
committerDavid Sommerseth <davids@redhat.com>2012-02-04 14:50:50 +0100
commit5e86fd93779482b90a191f929edebe414cd78a4f (patch)
tree2bcc361091366cd0c0e1cbba0af5a7a869b747dd
parentfc3ee19dee6c66e2325a24e864b5328128404e83 (diff)
downloadopenvpn-5e86fd93779482b90a191f929edebe414cd78a4f.tar.gz
openvpn-5e86fd93779482b90a191f929edebe414cd78a4f.tar.xz
openvpn-5e86fd93779482b90a191f929edebe414cd78a4f.zip
UTF-8 X.509 distinguished names
The UTF-8 support that came with commit 2627335 does allow international usernames and passwords. This patch introduces UTF-8 support for X.509 DNs. Additionally, instead of using the legacy openssl format, DNs are now displayed in RFC 2253 format; "/C=ru/L=\xD0\x9C\xD0\xBE\xD1\x81\xD0\xBA\xD0 \xB2\xD0\xB0/O=\xD0\x9A\xD1\x80\xD0\xB5\xD0\xBC\xD0\xBB\xD1\x8C/CN=kreml.ru" becomes "C=ru, L=Москва, O=Кремль, CN=kreml.ru". Since the specific character classes for X.509 names are removed, the "no-name-remapping" configuration option has no use anymore and is removed as well. Signed-off-by: Heiko Hund <heiko.hund@sophos.com> Acked-by: Adriaan de Jong <dejong@fox-it.com> Acked-by: David Sommerseth <davids@redhat.com> Signed-off-by: David Sommerseth <davids@redhat.com>
-rw-r--r--openvpn.823
-rw-r--r--options.c12
-rw-r--r--pkcs11_openssl.c2
-rwxr-xr-xsample-scripts/verify-cn6
-rw-r--r--ssl_verify.c45
-rw-r--r--ssl_verify_openssl.c40
-rw-r--r--ssl_verify_openssl.h2
7 files changed, 55 insertions, 75 deletions
diff --git a/openvpn.8 b/openvpn.8
index a6d7567..00acd01 100644
--- a/openvpn.8
+++ b/openvpn.8
@@ -3322,27 +3322,6 @@ the authenticated username as the common name,
rather than the common name from the client cert.
.\"*********************************************************
.TP
-.B \-\-no-name-remapping
-Allow Common Name, X509 Subject, and username strings to include
-any printable character including space, but excluding control
-characters such as tab, newline, and carriage-return.
-
-By default, OpenVPN will remap
-any character other than alphanumeric, underbar ('_'), dash
-('-'), dot ('.'), and slash ('/') to underbar ('_'). The X509
-Subject string as returned by the
-.B tls_id
-environmental variable, can additionally contain colon (':') or
-equal ('=').
-
-While name remapping is performed for security reasons to reduce
-the possibility of introducing string expansion security vulnerabilities
-in user-defined authentication
-scripts, this option is provided for those cases where it is desirable to
-disable the remapping feature. Don't use this option unless you
-know what you are doing!
-.\"*********************************************************
-.TP
.B \-\-port-share host port [dir]
When run in TCP server mode, share the OpenVPN port with
another application, such as an HTTPS server. If OpenVPN
@@ -4463,7 +4442,7 @@ When
.B cmd
is executed two arguments are appended, as follows:
-.B cmd certificate_depth X509_NAME_oneline
+.B cmd certificate_depth subject
These arguments are, respectively, the current certificate depth and
the X509 common name (cn) of the peer.
diff --git a/options.c b/options.c
index cb9738a..6b8ae22 100644
--- a/options.c
+++ b/options.c
@@ -601,7 +601,7 @@ static const char usage_message[] =
" pending TLS connection that has otherwise passed all other\n"
" tests of certification. cmd should return 0 to allow\n"
" TLS handshake to proceed, or 1 to fail. (cmd is\n"
- " executed as 'cmd certificate_depth X509_NAME_oneline')\n"
+ " executed as 'cmd certificate_depth subject')\n"
"--tls-export-cert [directory] : Get peer cert in PEM format and store it \n"
" in an openvpn temporary file in [directory]. Peer cert is \n"
" stored before tls-verify script execution and deleted after.\n"
@@ -2164,9 +2164,6 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
if ((options->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) && !ccnr)
msg (M_USAGE, "--auth-user-pass-optional %s", postfix);
}
-
- if ((options->ssl_flags & SSLF_NO_NAME_REMAPPING) && script_method == SM_SYSTEM)
- msg (M_USAGE, "--script-security method='system' cannot be combined with --no-name-remapping");
}
else
{
@@ -2201,8 +2198,6 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg (M_USAGE, "--username-as-common-name requires --mode server");
if (options->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL)
msg (M_USAGE, "--auth-user-pass-optional requires --mode server");
- if (options->ssl_flags & SSLF_NO_NAME_REMAPPING)
- msg (M_USAGE, "--no-name-remapping requires --mode server");
if (options->ssl_flags & SSLF_OPT_VERIFY)
msg (M_USAGE, "--opt-verify requires --mode server");
if (options->server_flags & SF_TCP_NODELAY_HELPER)
@@ -5581,11 +5576,6 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_GENERAL);
options->ssl_flags |= SSLF_AUTH_USER_PASS_OPTIONAL;
}
- else if (streq (p[0], "no-name-remapping"))
- {
- VERIFY_PERMISSION (OPT_P_GENERAL);
- options->ssl_flags |= SSLF_NO_NAME_REMAPPING;
- }
else if (streq (p[0], "opt-verify"))
{
VERIFY_PERMISSION (OPT_P_GENERAL);
diff --git a/pkcs11_openssl.c b/pkcs11_openssl.c
index e3463dc..aa1eccc 100644
--- a/pkcs11_openssl.c
+++ b/pkcs11_openssl.c
@@ -129,7 +129,7 @@ pkcs11_certificate_dn (pkcs11h_certificate_t certificate, char *dn,
goto cleanup;
}
- X509_NAME_oneline (X509_get_subject_name (x509), dn, dn_len);
+ _openssl_get_subject (x509, dn, dn_len);
ret = 0;
diff --git a/sample-scripts/verify-cn b/sample-scripts/verify-cn
index f9fea0f..6e747ef 100755
--- a/sample-scripts/verify-cn
+++ b/sample-scripts/verify-cn
@@ -3,7 +3,7 @@
# verify-cn -- a sample OpenVPN tls-verify script
#
# Return 0 if cn matches the common name component of
-# X509_NAME_oneline, 1 otherwise.
+# subject, 1 otherwise.
#
# For example in OpenVPN, you could use the directive:
#
@@ -13,7 +13,7 @@
# the client common name is listed on a line in the
# allowed_clients file.
-die "usage: verify-cn cnfile certificate_depth X509_NAME_oneline" if (@ARGV != 3);
+die "usage: verify-cn cnfile certificate_depth subject" if (@ARGV != 3);
# Parse out arguments:
# cnfile -- The file containing the list of common names, one per
@@ -37,7 +37,7 @@ if ($depth == 0) {
# If so, parse out the common name substring in
# the X509 subject string.
- if ($x509 =~ /\/CN=([^\/]+)/) {
+ if ($x509 =~ / CN=([^,]+)/) {
$cn = $1;
# Accept the connection if the X509 common name
# string matches the passed cn argument.
diff --git a/ssl_verify.c b/ssl_verify.c
index 326b005..0b2a1fb 100644
--- a/ssl_verify.c
+++ b/ssl_verify.c
@@ -40,24 +40,9 @@
#include "ssl_verify_openssl.h"
#endif
-/** Legal characters in an X509 name */
-#define X509_NAME_CHAR_CLASS (CC_ALNUM|CC_UNDERBAR|CC_DASH|CC_DOT|CC_AT|CC_COLON|CC_SLASH|CC_EQUAL)
-
-/** Legal characters in a common name */
-#define COMMON_NAME_CHAR_CLASS (CC_ALNUM|CC_UNDERBAR|CC_DASH|CC_DOT|CC_AT|CC_SLASH)
-
/** Maximum length of common name */
#define TLS_USERNAME_LEN 64
-static void
-string_mod_sslname (char *str, const unsigned int restrictive_flags, const unsigned int ssl_flags)
-{
- if (ssl_flags & SSLF_NO_NAME_REMAPPING)
- string_mod (str, CC_PRINT, CC_CRLF, '_');
- else
- string_mod (str, restrictive_flags, 0, '_');
-}
-
/*
* Export the untrusted IP address and port to the environment
*/
@@ -595,7 +580,7 @@ verify_cert(struct tls_session *session, x509_cert_t *cert, int cert_depth)
}
/* enforce character class restrictions in X509 name */
- string_mod_sslname (subject, X509_NAME_CHAR_CLASS, opt->ssl_flags);
+ string_mod (subject, CC_PRINT, CC_CRLF, '_');
string_replace_leading (subject, '-', '_');
/* extract the username (default is CN) */
@@ -615,7 +600,7 @@ verify_cert(struct tls_session *session, x509_cert_t *cert, int cert_depth)
}
/* enforce character class restrictions in common name */
- string_mod_sslname (common_name, COMMON_NAME_CHAR_CLASS, opt->ssl_flags);
+ string_mod (common_name, CC_PRINT, CC_CRLF, '_');
/* warn if cert chain is too deep */
if (cert_depth >= MAX_CERT_DEPTH)
@@ -1005,7 +990,7 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
* Verify the username and password using a plugin
*/
static int
-verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up, const char *raw_username)
+verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up)
{
int retval = OPENVPN_PLUGIN_FUNC_ERROR;
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
@@ -1014,7 +999,7 @@ verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up
if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
{
/* set username/password in private env space */
- setenv_str (session->opt->es, "username", raw_username);
+ setenv_str (session->opt->es, "username", up->username);
setenv_str (session->opt->es, "password", up->password);
/* setenv incoming cert common name for script */
@@ -1038,7 +1023,6 @@ verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up
#endif
setenv_del (session->opt->es, "password");
- setenv_str (session->opt->es, "username", up->username);
}
else
{
@@ -1059,7 +1043,7 @@ verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up
#define KMDA_DEF 3
static int
-verify_user_pass_management (struct tls_session *session, const struct user_pass *up, const char *raw_username)
+verify_user_pass_management (struct tls_session *session, const struct user_pass *up)
{
int retval = KMDA_ERROR;
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
@@ -1068,7 +1052,7 @@ verify_user_pass_management (struct tls_session *session, const struct user_pass
if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
{
/* set username/password in private env space */
- setenv_str (session->opt->es, "username", raw_username);
+ setenv_str (session->opt->es, "username", up->username);
setenv_str (session->opt->es, "password", up->password);
/* setenv incoming cert common name for script */
@@ -1081,7 +1065,6 @@ verify_user_pass_management (struct tls_session *session, const struct user_pass
management_notify_client_needing_auth (management, ks->mda_key_id, session->opt->mda_context, session->opt->es);
setenv_del (session->opt->es, "password");
- setenv_str (session->opt->es, "username", up->username);
retval = KMDA_SUCCESS;
}
@@ -1105,9 +1088,6 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,
bool s2 = true;
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- struct gc_arena gc = gc_new ();
- char *raw_username;
-
#ifdef MANAGEMENT_DEF_AUTH
int man_def_auth = KMDA_UNDEF;
@@ -1115,22 +1095,17 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,
man_def_auth = KMDA_DEF;
#endif
- /* preserve raw username before string_mod remapping, for plugins */
- ALLOC_ARRAY_CLEAR_GC (raw_username, char, USER_PASS_LEN, &gc);
- strcpy (raw_username, up->username);
- string_mod (raw_username, CC_PRINT, CC_CRLF, '_');
-
/* enforce character class restrictions in username/password */
- string_mod_sslname (up->username, COMMON_NAME_CHAR_CLASS, session->opt->ssl_flags);
+ string_mod (up->username, CC_PRINT, CC_CRLF, '_');
string_mod (up->password, CC_PRINT, CC_CRLF, '_');
/* call plugin(s) and/or script */
#ifdef MANAGEMENT_DEF_AUTH
if (man_def_auth == KMDA_DEF)
- man_def_auth = verify_user_pass_management (session, up, raw_username);
+ man_def_auth = verify_user_pass_management (session, up);
#endif
if (plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY))
- s1 = verify_user_pass_plugin (session, up, raw_username);
+ s1 = verify_user_pass_plugin (session, up);
if (session->opt->auth_user_pass_verify_script)
s2 = verify_user_pass_script (session, up);
@@ -1179,8 +1154,6 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,
{
msg (D_TLS_ERRORS, "TLS Auth Error: Auth Username/Password verification failed for peer");
}
-
- gc_free (&gc);
}
void
diff --git a/ssl_verify_openssl.c b/ssl_verify_openssl.c
index e82f6f9..e3f2d13 100644
--- a/ssl_verify_openssl.c
+++ b/ssl_verify_openssl.c
@@ -247,16 +247,52 @@ x509_free_sha1_hash (unsigned char *hash)
}
char *
+_openssl_get_subject (X509 *cert, char *buf, int size)
+{
+ BIO *subject_bio;
+ BUF_MEM *subject_mem;
+ char *subject = buf;
+ int maxlen = size;
+
+ subject_bio = BIO_new (BIO_s_mem ());
+ if (subject_bio == NULL)
+ goto out;
+
+ X509_NAME_print_ex (subject_bio, X509_get_subject_name (cert),
+ 0, XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_FN_SN |
+ ASN1_STRFLGS_UTF8_CONVERT | ASN1_STRFLGS_ESC_CTRL);
+
+ if (BIO_eof (subject_bio))
+ goto out_free;
+
+ BIO_get_mem_ptr (subject_bio, &subject_mem);
+ if (subject == NULL)
+ {
+ maxlen = subject_mem->length + 1;
+ subject = malloc (maxlen);
+ check_malloc_return (subject);
+ }
+
+ memcpy (subject, subject_mem->data, maxlen);
+ subject[maxlen - 1] = '\0';
+
+out_free:
+ BIO_free (subject_bio);
+out:
+ return subject;
+}
+
+char *
x509_get_subject (X509 *cert)
{
- return X509_NAME_oneline (X509_get_subject_name (cert), NULL, 0);
+ return _openssl_get_subject (cert, NULL, 0);
}
void
x509_free_subject (char *subject)
{
if (subject)
- OPENSSL_free(subject);
+ free(subject);
}
diff --git a/ssl_verify_openssl.h b/ssl_verify_openssl.h
index 4814d30..9c76d34 100644
--- a/ssl_verify_openssl.h
+++ b/ssl_verify_openssl.h
@@ -69,4 +69,6 @@ int verify_callback (int preverify_ok, X509_STORE_CTX * ctx);
/** @} name Function for authenticating a new connection from a remote OpenVPN peer */
+char *_openssl_get_subject (X509 *cert, char *buf, int size);
+
#endif /* SSL_VERIFY_OPENSSL_H_ */