]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
add new option for X.509 name verification
authorHeiko Hund <heiko.hund@sophos.com>
Thu, 7 Mar 2013 15:36:41 +0000 (16:36 +0100)
committerGert Doering <gert@greenie.muc.de>
Thu, 7 Mar 2013 19:23:36 +0000 (20:23 +0100)
Add the option --verify-x509-name to provide the functionality
of the now deprecated --tls-remote.

The new option accepts RFC 2253 subject DNs only and compares
RDN or RDN prefix only if configured explicitly.

Signed-off-by: Heiko Hund <heiko.hund@sophos.com>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Message-Id: 1362670601-18660-1-git-send-email-heiko.hund@sophos.com
URL: http://article.gmane.org/gmane.network.openvpn.devel/7376
Signed-off-by: Gert Doering <gert@greenie.muc.de>
doc/openvpn.8
src/openvpn/init.c
src/openvpn/options.c
src/openvpn/options.h
src/openvpn/ssl_common.h
src/openvpn/ssl_verify.c
src/openvpn/ssl_verify.h

index 998f7abb3d711760fddc6cc134f85e2ab6b3bbf0..d590714c4aef48ff6f0295b1bf9002bb71913f08 100644 (file)
@@ -3431,7 +3431,7 @@ the authenticated username as the common name,
 rather than the common name from the client cert.
 .\"*********************************************************
 .TP
-.B \-\-compat\-names [no\-remapping]
+.B \-\-compat\-names [no\-remapping] (DEPRECATED)
 Until OpenVPN v2.3 the format of the X.509 Subject fields was formatted
 like this:
 .IP
@@ -3467,17 +3467,20 @@ The
 mode flag can be used with the
 .B
 \-\-compat\-names
-option to be compatible with the now deprecated \-\-no\-name\-remapping feature
-present in older OpenVPN versions. When this mode flag is used, the Common Name,
+option to be compatible with the now deprecated \-\-no\-name\-remapping option.
+It is only available at the server. When this mode flag is used, the Common Name,
 Subject, and username strings are allowed to include any printable character
 including space, but excluding control characters such as tab, newline, and
-carriage-return.
+carriage-return. no-remapping is only available on the server side.
 
 .B Please note:
-This option will not be around for a long time.  It is only implemented
+This option is immediately deprecated.  It is only implemented
 to make the transition to the new formatting less intrusive.  It will be
-removed either in OpenVPN v2.4 or v2.5.  So please make sure you start
-the process to support the new formatting as soon as possible.
+removed either in OpenVPN v2.4 or v2.5.  So please make sure you use the
+.B \-\-verify-x509-name
+option instead of
+.B \-\-tls-remote
+as soon as possible and update your scripts where necessary.
 .\"*********************************************************
 .TP
 .B \-\-no\-name\-remapping (DEPRECATED)
@@ -3485,7 +3488,7 @@ The
 .B \-\-no\-name\-remapping
 option is an alias for
 .B \-\-compat\-names\ no\-remapping.
-It ensures compatibility with configurations using the
+It ensures compatibility with server configurations using the
 .B \-\-no\-name\-remapping
 option.
 
@@ -4671,11 +4674,11 @@ is available via the peer_cert environment variable.
 Field in x509 certificate subject to be used as username (default=CN).
 .B Fieldname
 will be uppercased before matching. When this option is used, the
---tls-remote option will match against the chosen fieldname instead
-of the CN.
+.B \-\-verify-x509-username
+option will match against the chosen fieldname instead of the CN.
 .\"*********************************************************
 .TP
-.B \-\-tls-remote name
+.B \-\-tls-remote name (DEPRECATED)
 Accept connections only from a host with X509 name
 or common name equal to
 .B name.
@@ -4707,6 +4710,59 @@ option to verify the remote host, because
 works in a
 .B \-\-chroot
 environment too.
+
+.B Please also note:
+This option is now deprecated.  It will be removed either in OpenVPN v2.4
+or v2.5.  So please make sure you support the new X.509 name formatting
+described with the
+.B \-\-compat-names
+option as soon as possible by updating your configurations to use
+.B \-\-verify-x509-name
+instead.
+.\"*********************************************************
+.TP
+.B \-\-verify-x509-name name type
+Accept connections only if a host's X.509 name is equal to
+.B name.
+The remote host must also pass all other tests of verification.
+
+Which X.509 name is compared to
+.B name
+depends on the setting of type.
+.B type
+can be "subject" to match the complete subject DN (default),
+"name" to match a subject RDN or "name-prefix" to match a subject RDN prefix.
+Which RDN is verified as name depends on the
+.B \-\-x509-username-field
+option. But it defaults to the common name (CN), e.g. a certificate with a
+subject DN "C=KG, ST=NA, L=Bishkek, CN=Server-1" would be matched by:
+
+.B \-\-verify-x509-name 'C=KG, ST=NA, L=Bishkek, CN=Server-1'
+and
+.B \-\-verify-x509-name Server-1 name
+or you could use
+.B \-\-verify-x509-name Server- name-prefix
+if you want a client to only accept connections to "Server-1", "Server-2", etc.
+
+.B \-\-verify-x509-name
+is a useful replacement for the
+.B \-\-tls-verify
+option to verify the remote host, because
+.B \-\-verify-x509-name
+works in a
+.B \-\-chroot
+environment without any dependencies.
+
+Using a name prefix is a useful alternative to managing
+a CRL (Certificate Revocation List) on the client, since it allows the client
+to refuse all certificates except for those associated
+with designated servers.
+
+.B NOTE:
+Test against a name prefix only when you are using OpenVPN with
+a custom CA certificate that is under your control.
+Never use this option with type "name-prefix" when your client certificates
+are signed by a third party, such as a commercial web CA.
 .\"*********************************************************
 .TP
 .B \-\-x509-track attribute
@@ -4744,7 +4800,7 @@ 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 \-\-ns-cert-type, \-\-tls-remote,
+.B \-\-ns-cert-type, \-\-verify-x509-name,
 or
 .B \-\-tls-verify.
 .\"*********************************************************
@@ -4802,7 +4858,7 @@ 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,
+.B \-\-remote-cert-tls, \-\-verify-x509-name,
 or
 .B \-\-tls-verify.
 .\"*********************************************************
index 25d8225aef3e0f273c353a94bb4195aa3154fac2..979ba231e09fb609df8062b5fc368d268a314489 100644 (file)
@@ -2205,7 +2205,8 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
 
   to.verify_command = options->tls_verify;
   to.verify_export_cert = options->tls_export_cert;
-  to.verify_x509name = options->tls_remote;
+  to.verify_x509_type = (options->verify_x509_type & 0xff);
+  to.verify_x509_name = options->verify_x509_name;
   to.crl_file = options->crl_file;
   to.ssl_flags = options->ssl_flags;
   to.ns_cert_type = options->ns_cert_type;
@@ -2467,12 +2468,10 @@ do_option_warnings (struct context *c)
     warn_on_use_of_common_subnets ();
   if (o->tls_client
       && !o->tls_verify
-      && !o->tls_remote
+      && o->verify_x509_type == VERIFY_X509_NONE
       && !(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)
-    msg (M_WARN, "WARNING: Make sure you understand the semantics of --tls-remote before using it (see the man page).");
 #endif
 #endif
 
index 7fda76f5fbb0bf0b5a36613b602600ce9956e96a..8592955ff5fa02231c0b6544401f48e16febcd19 100644 (file)
@@ -614,8 +614,8 @@ static const char usage_message[] =
   "--tls-export-cert [directory] : Get peer cert in PEM format and store it \n"
   "                  in an openvpn temporary file in [directory]. Peer cert is \n"
   "                  stored before tls-verify script execution and deleted after.\n"
-  "--tls-remote x509name: Accept connections only from a host with X509 name\n"
-  "                  x509name. The remote host must also pass all other tests\n"
+  "--verify-x509-name name: Accept connections only from a host with X509 subject\n"
+  "                  DN name. The remote host must also pass all other tests\n"
   "                  of verification.\n"
   "--ns-cert-type t: Require that peer certificate was signed with an explicit\n"
   "                  nsCertType designation t = 'client' | 'server'.\n"
@@ -1596,7 +1596,8 @@ show_settings (const struct options *o)
   SHOW_STR (cipher_list);
   SHOW_STR (tls_verify);
   SHOW_STR (tls_export_cert);
-  SHOW_STR (tls_remote);
+  SHOW_INT (verify_x509_type);
+  SHOW_STR (verify_x509_name);
   SHOW_STR (crl_file);
   SHOW_INT (ns_cert_type);
   {
@@ -2130,7 +2131,6 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
 
       if (options->stale_routes_check_interval)
         msg (M_USAGE, "--stale-routes-check requires --mode server");
-
       if (compat_flag (COMPAT_FLAG_QUERY | COMPAT_NO_NAME_REMAPPING))
         msg (M_USAGE, "--compat-x509-names no-remapping requires --mode server");
     }
@@ -2302,7 +2302,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
       MUST_BE_UNDEF (cipher_list);
       MUST_BE_UNDEF (tls_verify);
       MUST_BE_UNDEF (tls_export_cert);
-      MUST_BE_UNDEF (tls_remote);
+      MUST_BE_UNDEF (verify_x509_name);
       MUST_BE_UNDEF (tls_timeout);
       MUST_BE_UNDEF (renegotiate_bytes);
       MUST_BE_UNDEF (renegotiate_packets);
@@ -6514,27 +6514,97 @@ add_option (struct options *options,
   else if (streq (p[0], "compat-names"))
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
+      if (options->verify_x509_type != VERIFY_X509_NONE &&
+          options->verify_x509_type != TLS_REMOTE_SUBJECT_DN &&
+          options->verify_x509_type != TLS_REMOTE_SUBJECT_RDN_PREFIX)
+        {
+          msg (msglevel, "you cannot use --compat-names with --verify-x509-name");
+          goto err;
+        }
+      msg (M_WARN, "DEPRECATED OPTION: --compat-names, please update your configuration");
       compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES);
+#if P2MP_SERVER
       if (p[1] && streq (p[1], "no-remapping"))
         compat_flag (COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING);
     }
   else if (streq (p[0], "no-name-remapping"))
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
+      if (options->verify_x509_type != VERIFY_X509_NONE &&
+          options->verify_x509_type != TLS_REMOTE_SUBJECT_DN &&
+          options->verify_x509_type != TLS_REMOTE_SUBJECT_RDN_PREFIX)
+        {
+          msg (msglevel, "you cannot use --no-name-remapping with --verify-x509-name");
+          goto err;
+        }
       msg (M_WARN, "DEPRECATED OPTION: --no-name-remapping, please update your configuration");
       compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES);
       compat_flag (COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING);
+#endif
     }
   else if (streq (p[0], "tls-remote") && p[1])
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
-      /*
-       * Enable legacy openvpn format for DNs that have not been converted
-       * yet and X.509 common names (not containing an '=' or ', ')
-       */
-      if (p[1][0] == '/' || !strchr (p[1], '=') || !strstr (p[1], ", "))
-        compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES);
-      options->tls_remote = p[1];
+
+      if (options->verify_x509_type != VERIFY_X509_NONE &&
+          options->verify_x509_type != TLS_REMOTE_SUBJECT_DN &&
+          options->verify_x509_type != TLS_REMOTE_SUBJECT_RDN_PREFIX)
+        {
+          msg (msglevel, "you cannot use --tls-remote with --verify-x509-name");
+          goto err;
+        }
+      msg (M_WARN, "DEPRECATED OPTION: --tls-remote, please update your configuration");
+
+      if (strlen (p[1]))
+        {
+          int is_username = (!strchr (p[1], '=') || !strstr (p[1], ", "));
+          int type = TLS_REMOTE_SUBJECT_DN;
+          if (p[1][0] != '/' && is_username)
+            type = TLS_REMOTE_SUBJECT_RDN_PREFIX;
+
+          /*
+           * Enable legacy openvpn format for DNs that have not been converted
+           * yet and --x509-username-field (not containing an '=' or ', ')
+           */
+          if (p[1][0] == '/' || is_username)
+            compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES);
+
+          options->verify_x509_type = type;
+          options->verify_x509_name = p[1];
+        }
+    }
+  else if (streq (p[0], "verify-x509-name") && p[1] && strlen (p[1]))
+    {
+      int type = VERIFY_X509_SUBJECT_DN;
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      if (options->verify_x509_type == TLS_REMOTE_SUBJECT_DN ||
+          options->verify_x509_type == TLS_REMOTE_SUBJECT_RDN_PREFIX)
+        {
+          msg (msglevel, "you cannot use --verify-x509-name with --tls-remote");
+          goto err;
+        }
+      if (compat_flag (COMPAT_FLAG_QUERY | COMPAT_NAMES))
+        {
+          msg (msglevel, "you cannot use --verify-x509-name with "
+                         "--compat-names or --no-name-remapping");
+          goto err;
+        }
+      if (p[2])
+        {
+          if (streq (p[2], "subject"))
+            type = VERIFY_X509_SUBJECT_DN;
+          else if (streq (p[2], "name"))
+            type = VERIFY_X509_SUBJECT_RDN;
+          else if (streq (p[2], "name-prefix"))
+            type = VERIFY_X509_SUBJECT_RDN_PREFIX;
+          else
+            {
+              msg (msglevel, "unknown X.509 name type: %s", p[2]);
+              goto err;
+            }
+        }
+      options->verify_x509_type = type;
+      options->verify_x509_name = p[1];
     }
   else if (streq (p[0], "ns-cert-type") && p[1])
     {
index 306520b0bf3e03c8cfbe754fe72e34e8879791e3..d2ad94ce8f235adba3ef3cb937c1cfc8dbc82fd1 100644 (file)
@@ -506,8 +506,9 @@ struct options
   const char *pkcs12_file;
   const char *cipher_list;
   const char *tls_verify;
+  int verify_x509_type;
+  const char *verify_x509_name;
   const char *tls_export_cert;
-  const char *tls_remote;
   const char *crl_file;
 
   const char *ca_file_inline;
index cb259a96e78f4da2dc0a00a2dfd24f18067c4dae..c62294f59929ca5be9032d129b15d959aba359dd 100644 (file)
@@ -245,7 +245,8 @@ struct tls_options
   /* cert verification parms */
   const char *verify_command;
   const char *verify_export_cert;
-  const char *verify_x509name;
+  int verify_x509_type;
+  const char *verify_x509_name;
   const char *crl_file;
   int ns_cert_type;
   unsigned remote_cert_ku[MAX_PARMS];
index cac46e989af6adbc47b6cff7938fd8958d0ccf47..e651a8e0f52f76ad50e6190066d13f2ec307d942 100644 (file)
@@ -369,16 +369,21 @@ verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert,
 
 #endif /* OPENSSL_VERSION_NUMBER */
 
-  /* verify X509 name or common name against --tls-remote */
-  if (opt->verify_x509name && strlen (opt->verify_x509name) > 0)
+  /* verify X509 name or username against --verify-x509-[user]name */
+  if (opt->verify_x509_type != VERIFY_X509_NONE)
     {
-      if (strcmp (opt->verify_x509name, subject) == 0
-         || strncmp (opt->verify_x509name, common_name, strlen (opt->verify_x509name)) == 0)
+      if ( (opt->verify_x509_type == VERIFY_X509_SUBJECT_DN
+            && strcmp (opt->verify_x509_name, subject) == 0)
+        || (opt->verify_x509_type == VERIFY_X509_SUBJECT_RDN
+            && strcmp (opt->verify_x509_name, common_name) == 0)
+        || (opt->verify_x509_type == VERIFY_X509_SUBJECT_RDN_PREFIX
+            && strncmp (opt->verify_x509_name, common_name,
+                        strlen (opt->verify_x509_name)) == 0) )
        msg (D_HANDSHAKE, "VERIFY X509NAME OK: %s", subject);
       else
        {
          msg (D_HANDSHAKE, "VERIFY X509NAME ERROR: %s, must be %s",
-              subject, opt->verify_x509name);
+              subject, opt->verify_x509_name);
          return FAILURE;               /* Reject connection */
        }
     }
index 1d201523cddd62d910e534532b1e18a223ef01ec..e0bcba42c0dec61ee6d3611c2dc88f347f7165c1 100644 (file)
@@ -62,6 +62,12 @@ struct cert_hash_set {
   struct cert_hash *ch[MAX_CERT_DEPTH]; /**< Array of certificate hashes */
 };
 
+#define VERIFY_X509_NONE                0
+#define VERIFY_X509_SUBJECT_DN          1
+#define VERIFY_X509_SUBJECT_RDN         2
+#define VERIFY_X509_SUBJECT_RDN_PREFIX  3
+#define TLS_REMOTE_SUBJECT_DN           1 + 0x100
+#define TLS_REMOTE_SUBJECT_RDN_PREFIX   3 + 0x100
 
 #define TLS_AUTHENTICATION_SUCCEEDED  0
 #define TLS_AUTHENTICATION_FAILED     1