]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
crypto: Enable SHA256 fingerprint checking in --verify-hash
authorDavid Sommerseth <davids@openvpn.net>
Thu, 4 May 2017 20:42:01 +0000 (22:42 +0200)
committerGert Doering <gert@greenie.muc.de>
Thu, 18 May 2017 11:25:28 +0000 (13:25 +0200)
This enhances --verify-hash with an optional algorithm flag.  If not
provided, it defaults to SHA1 to preserve backwards compatbilitity with
existing configurations.  The only valid flags are SHA1 and SHA256.

In addition enhance the layout of the --verify-hash section in the man
page.

Signed-off-by: David Sommerseth <davids@openvpn.net>
Acked-by: Steffan Karger <steffan.karger@fox-it.com>
Message-Id: <20170504204201.1257-1-davids@openvpn.net>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14538.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
(cherry picked from commit 2193d7c08484d56ed07ba2e649abc2d08adcb245)

Changes.rst
doc/openvpn.8
src/openvpn/crypto_backend.h
src/openvpn/init.c
src/openvpn/options.c
src/openvpn/options.h
src/openvpn/ssl_common.h
src/openvpn/ssl_verify.c

index 5a02ad0d931d2b1a1326e1d5651882356bb2f985..fbe0fc46f9a02d65145746159891f2733cac1930 100644 (file)
@@ -303,6 +303,11 @@ Maintainer-visible changes
   use -std=gnu99 in CFLAGS.  This is known to be needed when doing
   i386/i686 builds on RHEL5.
 
+Version 2.4.3
+=============
+- ``--verify-hash`` can now take an optional flag which changes the hashing
+  algorithm. It can be either SHA1 or SHA256.  The default if not provided is
+  SHA1 to preserve backwards compatibility with existing configurations.
 
 Version 2.4.1
 =============
index 3a0fa9b28f42527f49ddf7cc723809c2ac9c4100..7cacc3ad35f0eb733968e84e0c94c54594973a5a 100644 (file)
@@ -4695,15 +4695,27 @@ and
 Not available with PolarSSL.
 .\"*********************************************************
 .TP
-.B \-\-verify\-hash hash
-Specify SHA1 fingerprint for level-1 cert.  The level-1 cert is the
+.B \-\-verify\-hash hash [algo]
+Specify SHA1 or SHA256 fingerprint for level-1 cert.  The level-1 cert is the
 CA (or intermediate cert) that signs the leaf certificate, and is
 one removed from the leaf certificate in the direction of the root.
 When accepting a connection from a peer, the level-1 cert
 fingerprint must match
 .B hash
 or certificate verification will fail.  Hash is specified
-as XX:XX:...  For example: AD:B0:95:D8:09:C8:36:45:12:A9:89:C8:90:09:CB:13:72:A6:AD:16
+as XX:XX:... For example:
+
+.nf
+.ft 3
+.in +4
+AD:B0:95:D8:09:C8:36:45:12:A9:89:C8:90:09:CB:13:72:A6:AD:16
+.in -4
+.ft
+.fi
+
+The
+.B algo
+flag can be either SHA1 or SHA256.  If not provided, it defaults to SHA1.
 .\"*********************************************************
 .TP
 .B \-\-pkcs11\-cert\-private [0|1]...
index 2c79baa15c2021d679e1bddf269f4662e1686e5f..9b113d7b933833139f6ddd54c1558491d7f80395 100644 (file)
 /* Maximum HMAC digest size (bytes) */
 #define OPENVPN_MAX_HMAC_SIZE   64
 
+/** Types referencing specific message digest hashing algorithms */
+typedef enum {
+    MD_SHA1,
+    MD_SHA256
+} hash_algo_type ;
+
 /** Struct used in cipher name translation table */
 typedef struct {
     const char *openvpn_name;   /**< Cipher name used by OpenVPN */
index 66126ef740eca8794b9970251ea3b23168510c2c..90d8314a3569ed276d7846cb4d96bb09555094ae 100644 (file)
@@ -2632,6 +2632,7 @@ do_init_crypto_tls(struct context *c, const unsigned int flags)
     memmove(to.remote_cert_ku, options->remote_cert_ku, sizeof(to.remote_cert_ku));
     to.remote_cert_eku = options->remote_cert_eku;
     to.verify_hash = options->verify_hash;
+    to.verify_hash_algo = options->verify_hash_algo;
 #ifdef ENABLE_X509ALTUSERNAME
     to.x509_username_field = (char *) options->x509_username_field;
 #else
index 9fef3945175a3b586fadfc29615728f440a031a4..4ce46b147f766bcb1eb09964286f3a9bfe1fd7d1 100644 (file)
@@ -592,7 +592,8 @@ static const char usage_message[] =
     "--x509-username-field : Field in x509 certificate containing the username.\n"
     "                        Default is CN in the Subject field.\n"
 #endif
-    "--verify-hash   : Specify SHA1 fingerprint for level-1 cert.\n"
+    "--verify-hash hash [algo] : Specify fingerprint for level-1 certificate.\n"
+    "                            Valid algo flags are SHA1 and SHA256. \n"
 #ifdef _WIN32
     "--cryptoapicert select-string : Load the certificate and private key from the\n"
     "                  Windows Certificate System Store.\n"
@@ -7703,10 +7704,25 @@ add_option(struct options *options,
             options->extra_certs_file_inline = p[2];
         }
     }
-    else if (streq(p[0], "verify-hash") && p[1] && !p[2])
+    else if (streq(p[0], "verify-hash") && p[1] && !p[3])
     {
         VERIFY_PERMISSION(OPT_P_GENERAL);
-        options->verify_hash = parse_hash_fingerprint(p[1], SHA_DIGEST_LENGTH, msglevel, &options->gc);
+
+        if (!p[2] || (p[2] && streq(p[2], "SHA1")))
+        {
+            options->verify_hash = parse_hash_fingerprint(p[1], SHA_DIGEST_LENGTH, msglevel, &options->gc);
+            options->verify_hash_algo = MD_SHA1;
+        }
+        else if (p[2] && streq(p[2], "SHA256"))
+        {
+            options->verify_hash = parse_hash_fingerprint(p[1], SHA256_DIGEST_LENGTH, msglevel, &options->gc);
+            options->verify_hash_algo = MD_SHA256;
+        }
+        else
+        {
+            msg(msglevel, "invalid or unsupported hashing algorithm: %s  (only SHA1 and SHA256 are valid)", p[2]);
+            goto err;
+        }
     }
 #ifdef ENABLE_CRYPTOAPI
     else if (streq(p[0], "cryptoapicert") && p[1] && !p[2])
index b3ab0293463d68b64dc4e8273badfcbcfd51f205..1d598fc3fb3d5f83bf984cae17bcddf8f831f1ae 100644 (file)
 #include "comp.h"
 #include "pushlist.h"
 #include "clinat.h"
+#ifdef ENABLE_CRYPTO
+#include "crypto_backend.h"
+#endif
+
 
 /*
  * Maximum number of parameters associated with an option,
@@ -519,6 +523,7 @@ struct options
     unsigned remote_cert_ku[MAX_PARMS];
     const char *remote_cert_eku;
     uint8_t *verify_hash;
+    hash_algo_type verify_hash_algo;
     unsigned int ssl_flags; /* set to SSLF_x flags from ssl.h */
 
 #ifdef ENABLE_PKCS11
index 9a16d77e2be7d2384f07612820ab75016c64021f..a99d24d652a3c9dbdd1ad1f9db8ed2275e8498cc 100644 (file)
@@ -271,6 +271,7 @@ struct tls_options
     unsigned remote_cert_ku[MAX_PARMS];
     const char *remote_cert_eku;
     uint8_t *verify_hash;
+    hash_algo_type verify_hash_algo;
     char *x509_username_field;
 
     /* allow openvpn config info to be
index ac1e110a8fe3b576515d0cc0bfbf4c25d4b655e2..078b65ad64c1a4319a3e2feacde4201bfda506be 100644 (file)
@@ -718,8 +718,31 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep
     /* verify level 1 cert, i.e. the CA that signed our leaf cert */
     if (cert_depth == 1 && opt->verify_hash)
     {
-        struct buffer sha1_hash = x509_get_sha1_fingerprint(cert, &gc);
-        if (memcmp(BPTR(&sha1_hash), opt->verify_hash, BLEN(&sha1_hash)))
+        struct buffer ca_hash = {0};
+
+        switch (opt->verify_hash_algo)
+        {
+        case MD_SHA1:
+            ca_hash = x509_get_sha1_fingerprint(cert, &gc);
+            break;
+
+        case MD_SHA256:
+            ca_hash = x509_get_sha256_fingerprint(cert, &gc);
+            break;
+
+        default:
+            /* This should normally not happen at all; the algorithm used
+             * is parsed by add_option() [options.c] and set to a predefined
+             * value in an enumerated type.  So if this unlikely scenario
+             * happens, consider this a failure
+             */
+            msg(M_WARN, "Unexpected invalid algorithm used with "
+                "--verify-hash (%i)", opt->verify_hash_algo);
+            ret = FAILURE;
+            goto cleanup;
+        }
+
+        if (memcmp(BPTR(&ca_hash), opt->verify_hash, BLEN(&ca_hash)))
         {
             msg(D_TLS_ERRORS, "TLS Error: level-1 certificate hash verification failed");
             goto cleanup;