diff options
author | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2005-11-12 08:26:57 +0000 |
---|---|---|
committer | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2005-11-12 08:26:57 +0000 |
commit | 411e89ae6fa195885dc13c594235893c22cb33d8 (patch) | |
tree | 27126306bc8185ef538127bc5f03052be898814d | |
parent | Backed out change to update_time to handle time (diff) | |
download | openvpn-411e89ae6fa195885dc13c594235893c22cb33d8.tar.xz |
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
Diffstat (limited to '')
-rwxr-xr-x | easy-rsa/2.0/openssl.cnf | 2 | ||||
-rw-r--r-- | init.c | 2 | ||||
-rw-r--r-- | openvpn.8 | 55 | ||||
-rw-r--r-- | options.c | 58 | ||||
-rw-r--r-- | options.h | 2 | ||||
-rw-r--r-- | ssl.c | 117 | ||||
-rw-r--r-- | ssl.h | 2 |
7 files changed, 238 insertions, 0 deletions
diff --git a/easy-rsa/2.0/openssl.cnf b/easy-rsa/2.0/openssl.cnf index 7fedebe..b430b83 100755 --- a/easy-rsa/2.0/openssl.cnf +++ b/easy-rsa/2.0/openssl.cnf @@ -207,6 +207,8 @@ nsCertType = server nsComment = "OpenSSL Generated Server Certificate" subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer:always +extendedKeyUsage=serverAuth +keyUsage = digitalSignature, keyEncipherment [ v3_req ] @@ -1445,6 +1445,8 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.verify_x509name = options->tls_remote; to.crl_file = options->crl_file; 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; #ifdef ENABLE_DEBUG @@ -225,6 +225,9 @@ openvpn \- secure IP tunnel daemon. [\ \fB\-\-remap\-usr1\fR\ \fIsignal\fR\ ] [\ \fB\-\-remote\-random\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\-pkts\fR\ \fIn\fR\ ] [\ \fB\-\-reneg\-sec\fR\ \fIn\fR\ ] @@ -4044,6 +4047,58 @@ or .B --tls-verify. .\"********************************************************* .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 Check peer certificate against the file .B crl @@ -463,6 +463,17 @@ static const char usage_message[] = " of verification.\n" "--ns-cert-type t: Require that peer certificate was signed with an explicit\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 */ #ifdef ENABLE_PKCS11 "\n" @@ -1197,6 +1208,12 @@ show_settings (const struct options *o) SHOW_STR (tls_remote); SHOW_STR (crl_file); 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); @@ -1813,6 +1830,8 @@ options_postprocess (struct options *options, bool first_time) MUST_BE_UNDEF (crl_file); MUST_BE_UNDEF (key_method); MUST_BE_UNDEF (ns_cert_type); + MUST_BE_UNDEF (remote_cert_ku[0]); + MUST_BE_UNDEF (remote_cert_eku); #ifdef ENABLE_PKCS11 MUST_BE_UNDEF (pkcs11_providers[0]); MUST_BE_UNDEF (pkcs11_sign_mode[0]); @@ -4786,6 +4805,45 @@ add_option (struct options *options, 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]) { VERIFY_PERMISSION (OPT_P_TLS_PARMS); @@ -392,6 +392,8 @@ struct options #endif 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_sign_mode[MAX_PARMS]; const char *pkcs11_slot_type; @@ -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 */ @@ -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 */ if (opt->verify_x509name && strlen (opt->verify_x509name) > 0 && ctx->error_depth == 0) { @@ -410,6 +410,8 @@ struct tls_options const char *verify_x509name; const char *crl_file; int ns_cert_type; + unsigned remote_cert_ku[MAX_PARMS]; + const char *remote_cert_eku; /* allow openvpn config info to be passed over control channel */ |