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>
... | ... |
@@ -303,6 +303,11 @@ Maintainer-visible changes |
303 | 303 |
use -std=gnu99 in CFLAGS. This is known to be needed when doing |
304 | 304 |
i386/i686 builds on RHEL5. |
305 | 305 |
|
306 |
+Version 2.4.3 |
|
307 |
+============= |
|
308 |
+- ``--verify-hash`` can now take an optional flag which changes the hashing |
|
309 |
+ algorithm. It can be either SHA1 or SHA256. The default if not provided is |
|
310 |
+ SHA1 to preserve backwards compatibility with existing configurations. |
|
306 | 311 |
|
307 | 312 |
Version 2.4.1 |
308 | 313 |
============= |
... | ... |
@@ -4694,15 +4694,27 @@ and |
4694 | 4694 |
Not available with PolarSSL. |
4695 | 4695 |
.\"********************************************************* |
4696 | 4696 |
.TP |
4697 |
-.B \-\-verify\-hash hash |
|
4698 |
-Specify SHA1 fingerprint for level-1 cert. The level-1 cert is the |
|
4697 |
+.B \-\-verify\-hash hash [algo] |
|
4698 |
+Specify SHA1 or SHA256 fingerprint for level-1 cert. The level-1 cert is the |
|
4699 | 4699 |
CA (or intermediate cert) that signs the leaf certificate, and is |
4700 | 4700 |
one removed from the leaf certificate in the direction of the root. |
4701 | 4701 |
When accepting a connection from a peer, the level-1 cert |
4702 | 4702 |
fingerprint must match |
4703 | 4703 |
.B hash |
4704 | 4704 |
or certificate verification will fail. Hash is specified |
4705 |
-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 |
|
4705 |
+as XX:XX:... For example: |
|
4706 |
+ |
|
4707 |
+.nf |
|
4708 |
+.ft 3 |
|
4709 |
+.in +4 |
|
4710 |
+AD:B0:95:D8:09:C8:36:45:12:A9:89:C8:90:09:CB:13:72:A6:AD:16 |
|
4711 |
+.in -4 |
|
4712 |
+.ft |
|
4713 |
+.fi |
|
4714 |
+ |
|
4715 |
+The |
|
4716 |
+.B algo |
|
4717 |
+flag can be either SHA1 or SHA256. If not provided, it defaults to SHA1. |
|
4706 | 4718 |
.\"********************************************************* |
4707 | 4719 |
.TP |
4708 | 4720 |
.B \-\-pkcs11\-cert\-private [0|1]... |
... | ... |
@@ -47,6 +47,12 @@ |
47 | 47 |
/* Maximum HMAC digest size (bytes) */ |
48 | 48 |
#define OPENVPN_MAX_HMAC_SIZE 64 |
49 | 49 |
|
50 |
+/** Types referencing specific message digest hashing algorithms */ |
|
51 |
+typedef enum { |
|
52 |
+ MD_SHA1, |
|
53 |
+ MD_SHA256 |
|
54 |
+} hash_algo_type ; |
|
55 |
+ |
|
50 | 56 |
/** Struct used in cipher name translation table */ |
51 | 57 |
typedef struct { |
52 | 58 |
const char *openvpn_name; /**< Cipher name used by OpenVPN */ |
... | ... |
@@ -2619,6 +2619,7 @@ do_init_crypto_tls(struct context *c, const unsigned int flags) |
2619 | 2619 |
memmove(to.remote_cert_ku, options->remote_cert_ku, sizeof(to.remote_cert_ku)); |
2620 | 2620 |
to.remote_cert_eku = options->remote_cert_eku; |
2621 | 2621 |
to.verify_hash = options->verify_hash; |
2622 |
+ to.verify_hash_algo = options->verify_hash_algo; |
|
2622 | 2623 |
#ifdef ENABLE_X509ALTUSERNAME |
2623 | 2624 |
to.x509_username_field = (char *) options->x509_username_field; |
2624 | 2625 |
#else |
... | ... |
@@ -591,7 +591,8 @@ static const char usage_message[] = |
591 | 591 |
"--x509-username-field : Field in x509 certificate containing the username.\n" |
592 | 592 |
" Default is CN in the Subject field.\n" |
593 | 593 |
#endif |
594 |
- "--verify-hash : Specify SHA1 fingerprint for level-1 cert.\n" |
|
594 |
+ "--verify-hash hash [algo] : Specify fingerprint for level-1 certificate.\n" |
|
595 |
+ " Valid algo flags are SHA1 and SHA256. \n" |
|
595 | 596 |
#ifdef _WIN32 |
596 | 597 |
"--cryptoapicert select-string : Load the certificate and private key from the\n" |
597 | 598 |
" Windows Certificate System Store.\n" |
... | ... |
@@ -7687,10 +7688,25 @@ add_option(struct options *options, |
7687 | 7687 |
options->extra_certs_file_inline = p[2]; |
7688 | 7688 |
} |
7689 | 7689 |
} |
7690 |
- else if (streq(p[0], "verify-hash") && p[1] && !p[2]) |
|
7690 |
+ else if (streq(p[0], "verify-hash") && p[1] && !p[3]) |
|
7691 | 7691 |
{ |
7692 | 7692 |
VERIFY_PERMISSION(OPT_P_GENERAL); |
7693 |
- options->verify_hash = parse_hash_fingerprint(p[1], SHA_DIGEST_LENGTH, msglevel, &options->gc); |
|
7693 |
+ |
|
7694 |
+ if (!p[2] || (p[2] && streq(p[2], "SHA1"))) |
|
7695 |
+ { |
|
7696 |
+ options->verify_hash = parse_hash_fingerprint(p[1], SHA_DIGEST_LENGTH, msglevel, &options->gc); |
|
7697 |
+ options->verify_hash_algo = MD_SHA1; |
|
7698 |
+ } |
|
7699 |
+ else if (p[2] && streq(p[2], "SHA256")) |
|
7700 |
+ { |
|
7701 |
+ options->verify_hash = parse_hash_fingerprint(p[1], SHA256_DIGEST_LENGTH, msglevel, &options->gc); |
|
7702 |
+ options->verify_hash_algo = MD_SHA256; |
|
7703 |
+ } |
|
7704 |
+ else |
|
7705 |
+ { |
|
7706 |
+ msg(msglevel, "invalid or unsupported hashing algorithm: %s (only SHA1 and SHA256 are valid)", p[2]); |
|
7707 |
+ goto err; |
|
7708 |
+ } |
|
7694 | 7709 |
} |
7695 | 7710 |
#ifdef ENABLE_CRYPTOAPI |
7696 | 7711 |
else if (streq(p[0], "cryptoapicert") && p[1] && !p[2]) |
... | ... |
@@ -42,6 +42,10 @@ |
42 | 42 |
#include "comp.h" |
43 | 43 |
#include "pushlist.h" |
44 | 44 |
#include "clinat.h" |
45 |
+#ifdef ENABLE_CRYPTO |
|
46 |
+#include "crypto_backend.h" |
|
47 |
+#endif |
|
48 |
+ |
|
45 | 49 |
|
46 | 50 |
/* |
47 | 51 |
* Maximum number of parameters associated with an option, |
... | ... |
@@ -518,6 +522,7 @@ struct options |
518 | 518 |
unsigned remote_cert_ku[MAX_PARMS]; |
519 | 519 |
const char *remote_cert_eku; |
520 | 520 |
uint8_t *verify_hash; |
521 |
+ hash_algo_type verify_hash_algo; |
|
521 | 522 |
unsigned int ssl_flags; /* set to SSLF_x flags from ssl.h */ |
522 | 523 |
|
523 | 524 |
#ifdef ENABLE_PKCS11 |
... | ... |
@@ -718,8 +718,31 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep |
718 | 718 |
/* verify level 1 cert, i.e. the CA that signed our leaf cert */ |
719 | 719 |
if (cert_depth == 1 && opt->verify_hash) |
720 | 720 |
{ |
721 |
- struct buffer sha1_hash = x509_get_sha1_fingerprint(cert, &gc); |
|
722 |
- if (memcmp(BPTR(&sha1_hash), opt->verify_hash, BLEN(&sha1_hash))) |
|
721 |
+ struct buffer ca_hash = {0}; |
|
722 |
+ |
|
723 |
+ switch (opt->verify_hash_algo) |
|
724 |
+ { |
|
725 |
+ case MD_SHA1: |
|
726 |
+ ca_hash = x509_get_sha1_fingerprint(cert, &gc); |
|
727 |
+ break; |
|
728 |
+ |
|
729 |
+ case MD_SHA256: |
|
730 |
+ ca_hash = x509_get_sha256_fingerprint(cert, &gc); |
|
731 |
+ break; |
|
732 |
+ |
|
733 |
+ default: |
|
734 |
+ /* This should normally not happen at all; the algorithm used |
|
735 |
+ * is parsed by add_option() [options.c] and set to a predefined |
|
736 |
+ * value in an enumerated type. So if this unlikely scenario |
|
737 |
+ * happens, consider this a failure |
|
738 |
+ */ |
|
739 |
+ msg(M_WARN, "Unexpected invalid algorithm used with " |
|
740 |
+ "--verify-hash (%i)", opt->verify_hash_algo); |
|
741 |
+ ret = FAILURE; |
|
742 |
+ goto cleanup; |
|
743 |
+ } |
|
744 |
+ |
|
745 |
+ if (memcmp(BPTR(&ca_hash), opt->verify_hash, BLEN(&ca_hash))) |
|
723 | 746 |
{ |
724 | 747 |
msg(D_TLS_ERRORS, "TLS Error: level-1 certificate hash verification failed"); |
725 | 748 |
goto cleanup; |