mirror of
https://github.com/OpenVPN/openvpn.git
synced 2026-05-28 04:03:29 -04:00
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>
This commit is contained in:
parent
fc3ee19dee
commit
5e86fd9377
7 changed files with 55 additions and 75 deletions
23
openvpn.8
23
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.
|
||||
|
|
|
|||
12
options.c
12
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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
45
ssl_verify.c
45
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
|
||||
|
|
|
|||
|
|
@ -246,17 +246,53 @@ x509_free_sha1_hash (unsigned char *hash)
|
|||
free(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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
Loading…
Reference in a new issue