Merged --remote-cert-ku, --remote-cert-eku, and

--remote-cert-tls from Alon's branch:
svn merge -r 793:796 $SO/contrib/alon/BETA21/openvpn .


git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@797 e7ae566f-a301-0410-adde-c780ea21d3b5
This commit is contained in:
james 2005-11-12 08:26:57 +00:00
parent 9423103dab
commit 411e89ae6f
7 changed files with 238 additions and 0 deletions

View File

@ -207,6 +207,8 @@ nsCertType = server
nsComment = "OpenSSL Generated Server Certificate" nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier=hash subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer:always authorityKeyIdentifier=keyid,issuer:always
extendedKeyUsage=serverAuth
keyUsage = digitalSignature, keyEncipherment
[ v3_req ] [ v3_req ]

2
init.c
View File

@ -1445,6 +1445,8 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
to.verify_x509name = options->tls_remote; to.verify_x509name = options->tls_remote;
to.crl_file = options->crl_file; to.crl_file = options->crl_file;
to.ns_cert_type = options->ns_cert_type; to.ns_cert_type = options->ns_cert_type;
memmove (to.remote_cert_ku, options->remote_cert_ku, sizeof (to.remote_cert_ku));
to.remote_cert_eku = options->remote_cert_eku;
to.es = c->c2.es; to.es = c->c2.es;
#ifdef ENABLE_DEBUG #ifdef ENABLE_DEBUG

View File

@ -225,6 +225,9 @@ openvpn \- secure IP tunnel daemon.
[\ \fB\-\-remap\-usr1\fR\ \fIsignal\fR\ ] [\ \fB\-\-remap\-usr1\fR\ \fIsignal\fR\ ]
[\ \fB\-\-remote\-random\fR\ ] [\ \fB\-\-remote\-random\fR\ ]
[\ \fB\-\-remote\fR\ \fIhost\ [port]\fR\ ] [\ \fB\-\-remote\fR\ \fIhost\ [port]\fR\ ]
[\ \fB\-\-remote\-cert\-ku\ \fIv...\fR\ ]
[\ \fB\-\-remote\-cert\-eku\ \fIoid\fR\ ]
[\ \fB\-\-remote\-cert\-tls\ \fIt\fR\ ]
[\ \fB\-\-reneg\-bytes\fR\ \fIn\fR\ ] [\ \fB\-\-reneg\-bytes\fR\ \fIn\fR\ ]
[\ \fB\-\-reneg\-pkts\fR\ \fIn\fR\ ] [\ \fB\-\-reneg\-pkts\fR\ \fIn\fR\ ]
[\ \fB\-\-reneg\-sec\fR\ \fIn\fR\ ] [\ \fB\-\-reneg\-sec\fR\ \fIn\fR\ ]
@ -4044,6 +4047,58 @@ or
.B --tls-verify. .B --tls-verify.
.\"********************************************************* .\"*********************************************************
.TP .TP
.B --remote-cert-ku v...
Require that peer certificate was signed with an explicit
.B key usage.
This is useful security option for clients, to ensure that
the host they connect with is a designated server.
The key usage should be encoded in hex, more than one key
usage can be specified.
.\"*********************************************************
.TP
.B --remote-cert-eku oid
Require that peer certificate was signed with an explicit
.B extended key usage.
This is useful security option for clients, to ensure that
the host they connect with is a designated server.
The extended key usage should be encoded in oid notation, or
OpenSSL symbolic representation.
.\"*********************************************************
.TP
.B --remote-cert-tls client|server
Require that peer certificate was signed with an explicit
.B key usage
and
.B extended key usage
based on TLS rules.
This is a useful security option for clients, to ensure that
the host they connect with is a designated server.
The
.B --remote-cert-tls client
option is equivalent to
.B --remote-cert-ku 80 08 88 --remote-cert-eku \fB"TLS Web Client Authentication"
The
.B --remote-cert-tls server
option is equivalent to
.B --remote-cert-ku a0 08 --remote-cert-eku \fB"TLS Web Server Authentication"
This is an important security precaution to protect against
a man-in-the-middle attack where an authorized client
attempts to connect to another client by impersonating the server.
The attack is easily prevented by having clients verify
the server certificate using any one of
.B --remote-cert-tls, --tls-remote,
or
.B --tls-verify.
.\"*********************************************************
.TP
.B --crl-verify crl .B --crl-verify crl
Check peer certificate against the file Check peer certificate against the file
.B crl .B crl

View File

@ -463,6 +463,17 @@ static const char usage_message[] =
" of verification.\n" " of verification.\n"
"--ns-cert-type t: Require that peer certificate was signed with an explicit\n" "--ns-cert-type t: Require that peer certificate was signed with an explicit\n"
" nsCertType designation t = 'client' | 'server'.\n" " nsCertType designation t = 'client' | 'server'.\n"
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
"--remote-cert-ku v ... : Require that the peer certificate was signed with\n"
" explicit key usage, you can specify more than one value.\n"
" value should be given in hex format.\n"
"--remote-cert-eku oid : Require that the peer certificate was signed with\n"
" explicit extended key usage. Extended key usage can be encoded\n"
" as on object identifier or OpenSSL string representation.\n"
"--remote-cert-tls t: Require that peer certificate was signed with explicit\n"
" key usage and extended key usage based on TLS rules.\n"
" t = 'client | 'server'.\n"
#endif /* OPENSSL_VERSION_NUMBER */
#endif /* USE_SSL */ #endif /* USE_SSL */
#ifdef ENABLE_PKCS11 #ifdef ENABLE_PKCS11
"\n" "\n"
@ -1197,6 +1208,12 @@ show_settings (const struct options *o)
SHOW_STR (tls_remote); SHOW_STR (tls_remote);
SHOW_STR (crl_file); SHOW_STR (crl_file);
SHOW_INT (ns_cert_type); SHOW_INT (ns_cert_type);
{
int i;
for (i=0;i<MAX_PARMS;i++)
SHOW_INT (remote_cert_ku[i]);
}
SHOW_STR (remote_cert_eku);
SHOW_INT (tls_timeout); SHOW_INT (tls_timeout);
@ -1813,6 +1830,8 @@ options_postprocess (struct options *options, bool first_time)
MUST_BE_UNDEF (crl_file); MUST_BE_UNDEF (crl_file);
MUST_BE_UNDEF (key_method); MUST_BE_UNDEF (key_method);
MUST_BE_UNDEF (ns_cert_type); MUST_BE_UNDEF (ns_cert_type);
MUST_BE_UNDEF (remote_cert_ku[0]);
MUST_BE_UNDEF (remote_cert_eku);
#ifdef ENABLE_PKCS11 #ifdef ENABLE_PKCS11
MUST_BE_UNDEF (pkcs11_providers[0]); MUST_BE_UNDEF (pkcs11_providers[0]);
MUST_BE_UNDEF (pkcs11_sign_mode[0]); MUST_BE_UNDEF (pkcs11_sign_mode[0]);
@ -4786,6 +4805,45 @@ add_option (struct options *options,
goto err; goto err;
} }
} }
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
else if (streq (p[0], "remote-cert-ku"))
{
int j;
VERIFY_PERMISSION (OPT_P_GENERAL);
for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j)
sscanf (p[j], "%x", &(options->remote_cert_ku[j-1]));
}
else if (streq (p[0], "remote-cert-eku") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->remote_cert_eku = p[1];
}
else if (streq (p[0], "remote-cert-tls") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (streq (p[1], "server"))
{
options->remote_cert_ku[0] = 0xa0;
options->remote_cert_ku[1] = 0x08;
options->remote_cert_eku = "TLS Web Server Authentication";
}
else if (streq (p[1], "client"))
{
options->remote_cert_ku[0] = 0x80;
options->remote_cert_ku[1] = 0x08;
options->remote_cert_ku[2] = 0x88;
options->remote_cert_eku = "TLS Web Client Authentication";
}
else
{
msg (msglevel, "--remote-cert-tls must be 'client' or 'server'");
goto err;
}
}
#endif /* OPENSSL_VERSION_NUMBER */
else if (streq (p[0], "tls-timeout") && p[1]) else if (streq (p[0], "tls-timeout") && p[1])
{ {
VERIFY_PERMISSION (OPT_P_TLS_PARMS); VERIFY_PERMISSION (OPT_P_TLS_PARMS);

View File

@ -392,6 +392,8 @@ struct options
#endif #endif
int ns_cert_type; /* set to 0, NS_SSL_SERVER, or NS_SSL_CLIENT */ int ns_cert_type; /* set to 0, NS_SSL_SERVER, or NS_SSL_CLIENT */
unsigned remote_cert_ku[MAX_PARMS];
const char *remote_cert_eku;
const char *pkcs11_providers[MAX_PARMS]; const char *pkcs11_providers[MAX_PARMS];
const char *pkcs11_sign_mode[MAX_PARMS]; const char *pkcs11_sign_mode[MAX_PARMS];
const char *pkcs11_slot_type; const char *pkcs11_slot_type;

117
ssl.c
View File

@ -389,6 +389,91 @@ set_common_name (struct tls_session *session, const char *common_name)
} }
} }
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
bool verify_cert_eku (X509 *x509, const char * const expected_oid) {
EXTENDED_KEY_USAGE *eku = NULL;
bool fFound = false;
if ((eku = (EXTENDED_KEY_USAGE *)X509_get_ext_d2i (x509, NID_ext_key_usage, NULL, NULL)) == NULL) {
msg (D_HANDSHAKE, "Certificate does not have extended key usage extension");
}
else {
int i;
msg (D_HANDSHAKE, "Validating certificate extended key usage");
for(i = 0; !fFound && i < sk_ASN1_OBJECT_num (eku); i++) {
ASN1_OBJECT *oid = sk_ASN1_OBJECT_value (eku, i);
char szOid[1024];
if (!fFound && OBJ_obj2txt (szOid, sizeof (szOid), oid, 0) != -1) {
msg (D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s", szOid, expected_oid);
if (!strcmp (expected_oid, szOid)) {
fFound = true;
}
}
if (!fFound && OBJ_obj2txt (szOid, sizeof (szOid), oid, 1) != -1) {
msg (D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s", szOid, expected_oid);
if (!strcmp (expected_oid, szOid)) {
fFound = true;
}
}
}
}
if (eku != NULL) {
sk_ASN1_OBJECT_pop_free (eku, ASN1_OBJECT_free);
}
return fFound;
}
bool verify_cert_ku (X509 *x509, const unsigned * const expected_ku, int expected_len) {
ASN1_BIT_STRING *ku = NULL;
bool fFound = false;
if ((ku = (ASN1_BIT_STRING *)X509_get_ext_d2i (x509, NID_key_usage, NULL, NULL)) == NULL) {
msg (D_HANDSHAKE, "Certificate does not have key usage extension");
}
else {
unsigned nku = 0;
int i;
for (i=0;i<8;i++) {
if (ASN1_BIT_STRING_get_bit (ku, i)) {
nku |= 1<<(7-i);
}
}
/*
* Fixup if no LSB bits
*/
if ((nku & 0xff) == 0) {
nku >>= 8;
}
msg (D_HANDSHAKE, "Validating certificate key usage");
for (i=0;!fFound && i<expected_len;i++) {
if (expected_ku[i] != 0) {
msg (D_HANDSHAKE, "++ Certificate has key usage %04x, expects %04x", nku, expected_ku[i]);
if (nku == expected_ku[i]) {
fFound = true;
}
}
}
}
if (ku != NULL) {
ASN1_BIT_STRING_free (ku);
}
return fFound;
}
#endif /* OPENSSL_VERSION_NUMBER */
/* /*
* nsCertType checking * nsCertType checking
*/ */
@ -506,6 +591,38 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
} }
} }
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
/* verify certificate ku */
if (opt->remote_cert_ku[0] != 0 && ctx->error_depth == 0)
{
if (verify_cert_ku (ctx->current_cert, opt->remote_cert_ku, MAX_PARMS))
{
msg (D_HANDSHAKE, "VERIFY KU OK");
}
else
{
msg (D_HANDSHAKE, "VERIFY KU ERROR");
goto err; /* Reject connection */
}
}
/* verify certificate eku */
if (opt->remote_cert_eku != NULL && ctx->error_depth == 0)
{
if (verify_cert_eku (ctx->current_cert, opt->remote_cert_eku))
{
msg (D_HANDSHAKE, "VERIFY EKU OK");
}
else
{
msg (D_HANDSHAKE, "VERIFY EKU ERROR");
goto err; /* Reject connection */
}
}
#endif /* OPENSSL_VERSION_NUMBER */
/* verify X509 name or common name against --tls-remote */ /* verify X509 name or common name against --tls-remote */
if (opt->verify_x509name && strlen (opt->verify_x509name) > 0 && ctx->error_depth == 0) if (opt->verify_x509name && strlen (opt->verify_x509name) > 0 && ctx->error_depth == 0)
{ {

2
ssl.h
View File

@ -410,6 +410,8 @@ struct tls_options
const char *verify_x509name; const char *verify_x509name;
const char *crl_file; const char *crl_file;
int ns_cert_type; int ns_cert_type;
unsigned remote_cert_ku[MAX_PARMS];
const char *remote_cert_eku;
/* allow openvpn config info to be /* allow openvpn config info to be
passed over control channel */ passed over control channel */