]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Author: Jan Just Keijser <janjust@nikhef.nl>
authorJan Just Keijser <janjust@nikhef.nl>
Fri, 9 Oct 2015 09:39:19 +0000 (11:39 +0200)
committerGert Doering <gert@greenie.muc.de>
Mon, 9 Nov 2015 16:23:15 +0000 (17:23 +0100)
Add extended client certificate verification support.

Replace --client-cert-not-required with a more flexible option,
that allows for no, optional or mandatory client certificate
verification.

Signed-off-by: Jan Just Keijser <janjust@nikhef.nl>
Acked-by: Steffan Karger <steffan.karger@fox-it.com>
Message-Id: <1444383559-15788-1-git-send-email-janjust@nikhef.nl>
URL: http://article.gmane.org/gmane.network.openvpn.devel/10213
Signed-off-by: Gert Doering <gert@greenie.muc.de>
doc/openvpn.8
src/openvpn/options.c
src/openvpn/ssl_common.h
src/openvpn/ssl_openssl.c

index b6d5aedce0061bb95159242252619e953ff65cff..2978b7fd502a01979abe13a128b9fc33f50b36bf 100644 (file)
@@ -3588,18 +3588,63 @@ to empty strings ("").  The authentication module/script MUST have logic
 to detect this condition and respond accordingly.
 .\"*********************************************************
 .TP
-.B \-\-client\-cert\-not\-required
+.B \-\-client\-cert\-not\-required (DEPRECATED)
 Don't require client certificate, client will authenticate
 using username/password only.  Be aware that using this directive
 is less secure than requiring certificates from all clients.
 
+
+.B Please note:
+This option is now deprecated and will be removed in OpenVPN v2.5.
+It is replaced by
+.B \-\-verify\-client\-cert
+which allows for more flexibility. The option
+.B \-\-verify\-client\-cert none
+is functionally equivalent to
+.B \-\-client\-cert\-not\-required
+.
+
+.\"*********************************************************
+.TP
+.B \-\-verify\-client\-cert none|optional|require
+Specify whether the client is required to supply a valid certificate.
+
+Possible options are
+
+.B none
+: a client certificate is not required. the client need to authenticate
+using username/password only.  Be aware that using this directive
+is less secure than requiring certificates from all clients.
+
 If you use this directive, the
 entire responsibility of authentication will rest on your
 .B \-\-auth\-user\-pass\-verify
 script, so keep in mind that bugs in your script
 could potentially compromise the security of your VPN.
 
-If you don't use this directive, but you also specify an
+.B \-\-verify\-client\-cert none
+is functionally equivalent to
+.B \-\-client\-cert\-not\-required.
+
+.B optional
+: a client may present a certificate but it is not required to do so.
+When using this directive, you should also use a
+.B \-\-auth\-user\-pass\-verify
+script to ensure that clients are authenticated using a
+certificate, a username and password, or possibly even both.
+
+Again, the entire responsibility of authentication will rest on your
+.B \-\-auth\-user\-pass\-verify
+script, so keep in mind that bugs in your script
+could potentially compromise the security of your VPN.
+
+.B require
+: this is the default option. A client is required to present a
+certificate, otherwise VPN access is refused.
+
+If you don't use this directive (or use
+.B \-\-verify\-client\-cert require
+) but you also specify an
 .B \-\-auth\-user\-pass\-verify
 script, then OpenVPN will perform double authentication.  The
 client certificate verification AND the
index 2f8915daa08696a709a913ddcf25d7b75ca60b68..8de4c3cc2ed615308c9ce351109b140560fc5ab9 100644 (file)
@@ -432,6 +432,9 @@ static const char usage_message[] =
   "                  Only valid in a client-specific config file.\n"
   "--client-cert-not-required : Don't require client certificate, client\n"
   "                  will authenticate using username/password.\n"
+  "--verify-client-cert [none|optional|require] : perform no, optional or\n"
+  "                  mandatory client certificate verification.\n"
+  "                  Default is to require the client to supply a certificate.\n"
   "--username-as-common-name  : For auth-user-pass authentication, use\n"
   "                  the authenticated username as the common name,\n"
   "                  rather than the common name from the client cert.\n"
@@ -2081,8 +2084,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
        msg (M_USAGE, "--duplicate-cn requires --mode server");
       if (options->cf_max || options->cf_per)
        msg (M_USAGE, "--connect-freq requires --mode server");
-      if (options->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)
-       msg (M_USAGE, "--client-cert-not-required requires --mode server");
+      if (options->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED || options->ssl_flags & SSLF_CLIENT_CERT_OPTIONAL)
+       msg (M_USAGE, "--client-cert-not-required and --verify-client-cert require --mode server");
       if (options->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME)
        msg (M_USAGE, "--username-as-common-name requires --mode server");
       if (options->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL)
@@ -5664,6 +5667,27 @@ add_option (struct options *options,
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
       options->ssl_flags |= SSLF_CLIENT_CERT_NOT_REQUIRED;
+      msg (M_WARN, "DEPRECATED OPTION: --client-cert-not-required, use --verify-client-cert instead");
+    }
+  else if (streq (p[0], "verify-client-cert") && !p[2])
+    {
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+
+      /* Reset any existing flags */
+      options->ssl_flags &= ~SSLF_CLIENT_CERT_OPTIONAL;
+      options->ssl_flags &= ~SSLF_CLIENT_CERT_NOT_REQUIRED;
+      if (p[1])
+       {
+         if (streq (p[1], "none"))
+             options->ssl_flags |= SSLF_CLIENT_CERT_NOT_REQUIRED;
+         else if (streq (p[1], "optional"))
+             options->ssl_flags |= SSLF_CLIENT_CERT_OPTIONAL;
+         else if (!streq (p[1], "require"))
+           {
+             msg (msglevel, "parameter to --verify-client-cert must be 'none', 'optional' or 'require'");
+             goto err;
+           }
+       }
     }
   else if (streq (p[0], "username-as-common-name") && !p[1])
     {
index 86e4ac8adeab04bd4d83df8cafc8e97d64e0be1e..e2b0ebf0f74307b5fdc1eabb1ad2a5c55966b111 100644 (file)
@@ -293,8 +293,9 @@ struct tls_options
 
   /* configuration file SSL-related boolean and low-permutation options */
 # define SSLF_CLIENT_CERT_NOT_REQUIRED (1<<0)
-# define SSLF_USERNAME_AS_COMMON_NAME  (1<<1)
-# define SSLF_AUTH_USER_PASS_OPTIONAL  (1<<2)
+# define SSLF_CLIENT_CERT_OPTIONAL     (1<<1)
+# define SSLF_USERNAME_AS_COMMON_NAME  (1<<2)
+# define SSLF_AUTH_USER_PASS_OPTIONAL  (1<<3)
 # define SSLF_OPT_VERIFY               (1<<4)
 # define SSLF_CRL_VERIFY_DIR           (1<<5)
 # define SSLF_TLS_VERSION_MIN_SHIFT    6
index f05f95ff5042282772e437cae6bec9d6f0606dcc..0bf15b3e1e84ac0df1cd4833d8522cc1969bdffc 100644 (file)
@@ -213,6 +213,9 @@ tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
 {
   ASSERT(NULL != ctx);
 
+  /* default certificate verification flags */
+  int flags = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+
   /* process SSL options including minimum TLS version we will accept from peer */
   {
     long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_TICKET | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
@@ -253,13 +256,15 @@ tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
   if (ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)
     {
       msg (M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION "
-         "--client-cert-not-required may accept clients which do not present "
-         "a certificate");
+         "--client-cert-not-required and --verify-client-cert none "
+      "may accept clients which do not present a certificate");
+
+      flags = 0;
     }
-  else
+  else if (ssl_flags & SSLF_CLIENT_CERT_OPTIONAL)
+    flags = SSL_VERIFY_PEER;
 #endif
-  SSL_CTX_set_verify (ctx->ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
-                     verify_callback);
+  SSL_CTX_set_verify (ctx->ctx, flags, verify_callback);
 
   SSL_CTX_set_info_callback (ctx->ctx, info_callback);
 }