mirror of
https://github.com/OpenVPN/openvpn.git
synced 2025-05-09 05:31:05 +08:00
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:
parent
9423103dab
commit
411e89ae6f
@ -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
2
init.c
@ -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
|
||||||
|
55
openvpn.8
55
openvpn.8
@ -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
|
||||||
|
58
options.c
58
options.c
@ -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);
|
||||||
|
@ -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
117
ssl.c
@ -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
2
ssl.h
@ -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 */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user