From: Adriaan de Jong Date: Thu, 30 Jun 2011 11:51:16 +0000 (+0200) Subject: Refactored: Netscape certificate type verification X-Git-Tag: v2.3-alpha1~122 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=06d22777e9172efe3b3dc15c1bc2c6ef5d292cfa;p=thirdparty%2Fopenvpn.git Refactored: Netscape certificate type verification Signed-off-by: Adriaan de Jong Acked-by: James Yonan Signed-off-by: David Sommerseth --- diff --git a/init.c b/init.c index b809b960d..6fc1a6bfb 100644 --- a/init.c +++ b/init.c @@ -2471,7 +2471,7 @@ do_option_warnings (struct context *c) if (o->tls_client && !o->tls_verify && !o->tls_remote - && !(o->ns_cert_type & NS_SSL_SERVER) + && !(o->ns_cert_type & NS_CERT_CHECK_SERVER) && !o->remote_cert_eku) msg (M_WARN, "WARNING: No server certificate verification method has been enabled. See http://openvpn.net/howto.html#mitm for more info."); if (o->tls_remote) diff --git a/options.c b/options.c index a84e34dff..f055185f7 100644 --- a/options.c +++ b/options.c @@ -6313,9 +6313,9 @@ add_option (struct options *options, { VERIFY_PERMISSION (OPT_P_GENERAL); if (streq (p[1], "server")) - options->ns_cert_type = NS_SSL_SERVER; + options->ns_cert_type = NS_CERT_CHECK_SERVER; else if (streq (p[1], "client")) - options->ns_cert_type = NS_SSL_CLIENT; + options->ns_cert_type = NS_CERT_CHECK_CLIENT; else { msg (msglevel, "--ns-cert-type must be 'client' or 'server'"); diff --git a/options.h b/options.h index c49cb521e..8532402cd 100644 --- a/options.h +++ b/options.h @@ -539,7 +539,7 @@ struct options const char *pkcs12_file_inline; /* contains the base64 encoding of pkcs12 file */ #endif - int ns_cert_type; /* set to 0, NS_SSL_SERVER, or NS_SSL_CLIENT */ + int ns_cert_type; /* set to 0, NS_CERT_CHECK_SERVER, or NS_CERT_CHECK_CLIENT */ unsigned remote_cert_ku[MAX_PARMS]; const char *remote_cert_eku; uint8_t *verify_hash; diff --git a/ssl.c b/ssl.c index ac337e082..e16f1a3da 100644 --- a/ssl.c +++ b/ssl.c @@ -387,26 +387,6 @@ bool verify_cert_ku (X509 *x509, const unsigned * const expected_ku, int expecte #endif /* OPENSSL_VERSION_NUMBER */ -/* - * nsCertType checking - */ - -#define verify_nsCertType(x, usage) (((x)->ex_flags & EXFLAG_NSCERT) && ((x)->ex_nscert & (usage))) - -static const char * -print_nsCertType (int type) -{ - switch (type) - { - case NS_SSL_SERVER: - return "SERVER"; - case NS_SSL_CLIENT: - return "CLIENT"; - default: - return "?"; - } -} - static void string_mod_sslname (char *str, const unsigned int restrictive_flags, const unsigned int ssl_flags) { @@ -532,21 +512,9 @@ verify_cert(struct tls_session *session, x509_cert_t *cert, int cert_depth) /* export current untrusted IP */ setenv_untrusted (session); - /* verify certificate nsCertType */ - if (opt->ns_cert_type && cert_depth == 0) - { - if (verify_nsCertType (cert, opt->ns_cert_type)) - { - msg (D_HANDSHAKE, "VERIFY OK: nsCertType=%s", - print_nsCertType (opt->ns_cert_type)); - } - else - { - msg (D_HANDSHAKE, "VERIFY nsCertType ERROR: %s, require nsCertType=%s", - subject, print_nsCertType (opt->ns_cert_type)); - goto err; /* Reject connection */ - } - } + /* If this is the peer's own certificate, verify it */ + if (cert_depth == 0 && verify_peer_cert(opt, cert, subject, common_name)) + goto err; #if OPENSSL_VERSION_NUMBER >= 0x00907000L diff --git a/ssl_verify.c b/ssl_verify.c index 5f743dadb..4ca414f93 100644 --- a/ssl_verify.c +++ b/ssl_verify.c @@ -306,6 +306,54 @@ x509_track_add (const struct x509_track **ll_head, const char *name, int msgleve #endif +/* + * Returns the string associated with the given certificate type. + */ +static const char * +print_nsCertType (int type) +{ + switch (type) + { + case NS_CERT_CHECK_SERVER: + return "SERVER"; + case NS_CERT_CHECK_CLIENT: + return "CLIENT"; + default: + return "?"; + } +} + +/* + * Verify the peer's certificate fields. + * + * @param opt the tls options to verify against + * @param peer_cert the peer's certificate + * @param subject the peer's extracted subject name + * @param subject the peer's extracted common name + */ +int +verify_peer_cert(const struct tls_options *opt, x509_cert_t *peer_cert, + const char *subject, const char *common_name) +{ + /* verify certificate nsCertType */ + if (opt->ns_cert_type != NS_CERT_CHECK_NONE) + { + if (verify_nsCertType (peer_cert, opt->ns_cert_type)) + { + msg (D_HANDSHAKE, "VERIFY OK: nsCertType=%s", + print_nsCertType (opt->ns_cert_type)); + } + else + { + msg (D_HANDSHAKE, "VERIFY nsCertType ERROR: %s, require nsCertType=%s", + subject, print_nsCertType (opt->ns_cert_type)); + return 1; /* Reject connection */ + } + } + + return 0; +} + /* * Export the subject, common_name, and raw certificate fields to the * environment for later verification by scripts and plugins. diff --git a/ssl_verify.h b/ssl_verify.h index 03a794227..acb27f5b4 100644 --- a/ssl_verify.h +++ b/ssl_verify.h @@ -214,6 +214,16 @@ void x509_track_add (const struct x509_track **ll_head, const char *name, int ms #endif +/* + * Certificate checking for verify_nsCertType + */ +/** Do not perform Netscape certificate type verification */ +#define NS_CERT_CHECK_NONE (0) +/** Do not perform Netscape certificate type verification */ +#define NS_CERT_CHECK_SERVER (1<<0) +/** Do not perform Netscape certificate type verification */ +#define NS_CERT_CHECK_CLIENT (1<<1) + /* * TODO: document */ @@ -233,6 +243,8 @@ tls_client_reason (struct tls_multi *multi) } /* TEMP */ +int verify_peer_cert(const struct tls_options *opt, x509_cert_t *peer_cert, + const char *subject, const char *common_name); void verify_cert_set_env(struct env_set *es, x509_cert_t *peer_cert, int cert_depth, const char *subject, const char *common_name, diff --git a/ssl_verify_backend.h b/ssl_verify_backend.h index a32f0ea6a..6f0e54e9a 100644 --- a/ssl_verify_backend.h +++ b/ssl_verify_backend.h @@ -141,4 +141,17 @@ void setenv_x509_track (const struct x509_track *xt, struct env_set *es, */ void setenv_x509 (struct env_set *es, int cert_depth, x509_cert_t *cert); +/* + * Check X.509 Netscape certificate type field, if available. + * + * @param cert Certificate to check. + * @param usage One of \c NS_CERT_CHECK_CLIENT, \c NS_CERT_CHECK_SERVER, + * or \c NS_CERT_CHECK_NONE. + * + * @return \c true if NS_CERT_CHECK_NONE or if the certificate has + * the expected bit set. \c false if the certificate does + * not have NS cert type verification or the wrong bit set. + */ +bool verify_nsCertType(const x509_cert_t *cert, const int usage); + #endif /* SSL_VERIFY_BACKEND_H_ */ diff --git a/ssl_verify_openssl.c b/ssl_verify_openssl.c index 417e5d73d..033af1dbf 100644 --- a/ssl_verify_openssl.c +++ b/ssl_verify_openssl.c @@ -377,3 +377,18 @@ setenv_x509 (struct env_set *es, int cert_depth, x509_cert_t *peer_cert) OPENSSL_free (buf); } } + +bool +verify_nsCertType(const x509_cert_t *peer_cert, const int usage) +{ + if (usage == NS_CERT_CHECK_NONE) + return true; + if (usage == NS_CERT_CHECK_CLIENT) + return ((peer_cert->ex_flags & EXFLAG_NSCERT) + && (peer_cert->ex_nscert & NS_SSL_CLIENT)); + if (usage == NS_CERT_CHECK_SERVER) + return ((peer_cert->ex_flags & EXFLAG_NSCERT) + && (peer_cert->ex_nscert & NS_SSL_SERVER)); + + return false; +}