Blame SOURCES/bind-9.11-fips-code.patch

2e2c49
From fb8665aebd79ea33cb255f578544e1738f5bbb58 Mon Sep 17 00:00:00 2001
2e2c49
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
2e2c49
Date: Thu, 2 Aug 2018 23:34:45 +0200
2e2c49
Subject: [PATCH 1/2] Squashed commit of the following:
2e2c49
MIME-Version: 1.0
2e2c49
Content-Type: text/plain; charset=UTF-8
2e2c49
Content-Transfer-Encoding: 8bit
2e2c49
2e2c49
commit b49f70ce0575b6b52a71b90fe0376dbf16f92c6b
2e2c49
Author: Petr Menšík <pemensik@redhat.com>
2e2c49
Date:   Mon Jan 22 14:12:37 2018 +0100
2e2c49
2e2c49
    Update system tests to detect MD5 disabled at runtime
2e2c49
2e2c49
commit 80ceffee4860c24baf70bc9a8653d92731eda2e4
2e2c49
Author: Petr Menšík <pemensik@redhat.com>
2e2c49
Date:   Thu Aug 2 14:53:54 2018 +0200
2e2c49
2e2c49
    Avoid warning about undefined parameters
2e2c49
2e2c49
commit e4ad4363e3d1acaac58456117579f02761f38fdc
2e2c49
Author: Petr Menšík <pemensik@redhat.com>
2e2c49
Date:   Wed Jun 20 19:31:19 2018 +0200
2e2c49
2e2c49
    Fix rndc-confgen default algorithm, report true algorithm in usage.
2e2c49
2e2c49
commit 7e629a351010cb75e0589ec361f720085675998c
2e2c49
Author: Petr Menšík <pemensik@redhat.com>
2e2c49
Date:   Fri Feb 23 21:21:30 2018 +0100
2e2c49
2e2c49
    Cleanup only if initialization was successful
2e2c49
2e2c49
commit 2101b948c77cbcbe07eb4a1e60f3e693b2245ec6
2e2c49
Author: Petr Menšík <pemensik@redhat.com>
2e2c49
Date:   Mon Feb 5 12:19:28 2018 +0100
2e2c49
2e2c49
    Ensure dst backend is initialized first even before hmac algorithms.
2e2c49
2e2c49
commit 7567c7edde7519115a9ae7e20818c835d3eb1ffe
2e2c49
Author: Petr Menšík <pemensik@redhat.com>
2e2c49
Date:   Mon Feb 5 12:17:54 2018 +0100
2e2c49
2e2c49
    Skip initialization of MD5 based algorithms if not available.
2e2c49
2e2c49
commit 5782137df6b45a6d900d5a1c250c1257227e917a
2e2c49
Author: Petr Menšík <pemensik@redhat.com>
2e2c49
Date:   Mon Feb 5 10:21:27 2018 +0100
2e2c49
2e2c49
    Change secalgs skipping to be more safe
2e2c49
2e2c49
commit f2d78729898182d2d19d5064de1bec9b66817159
2e2c49
Author: Petr Menšík <pemensik@redhat.com>
2e2c49
Date:   Wed Jan 31 18:26:11 2018 +0100
2e2c49
2e2c49
    Skip MD5 algorithm also in case of NULL name
2e2c49
2e2c49
commit 32a2ad4abc7aaca1c257730319ad3c27405d3407
2e2c49
Author: Petr Menšík <pemensik@redhat.com>
2e2c49
Date:   Wed Jan 31 11:38:12 2018 +0100
2e2c49
2e2c49
    Make MD5 behave like unknown algorithm in TSIG.
2e2c49
2e2c49
commit 13cd3f704dce568fdf24a567be5802b58ac6007b
2e2c49
Author: Petr Menšík <pemensik@redhat.com>
2e2c49
Date:   Tue Nov 28 20:14:37 2017 +0100
2e2c49
2e2c49
    Select token with most supported functions, instead of demanding it must support all functions
2e2c49
2e2c49
    Initialize PKCS#11 always until successfully initialized
2e2c49
2e2c49
commit a71df74abdca4fe63bcdf542b81a109cf1f495b4
2e2c49
Author: Petr Menšík <pemensik@redhat.com>
2e2c49
Date:   Mon Jan 22 16:17:44 2018 +0100
2e2c49
2e2c49
    Handle MD5 unavailability from DST
2e2c49
2e2c49
commit dd82cb263efa2753d3ee772972726ea08bcc639b
2e2c49
Author: Petr Menšík <pemensik@redhat.com>
2e2c49
Date:   Mon Jan 22 14:11:16 2018 +0100
2e2c49
2e2c49
    Check runtime flag from library and applications, fail gracefully.
2e2c49
2e2c49
commit c7b2f87f07ecae75b821a908e29f08a42371e32e
2e2c49
Author: Petr Menšík <pemensik@redhat.com>
2e2c49
Date:   Mon Jan 22 08:39:08 2018 +0100
2e2c49
2e2c49
    Modify libraries to use isc_md5_available() if PK11_MD5_DISABLE is not
2e2c49
    defined.
2e2c49
    TODO: pk11.c should accept slot without MD5 support.
2e2c49
2e2c49
commit 0b8e470ec636b9e350b5ec3203eb2b4091415fde
2e2c49
Author: Petr Menšík <pemensik@redhat.com>
2e2c49
Date:   Mon Jan 22 07:21:04 2018 +0100
2e2c49
2e2c49
    Add runtime detection whether MD5 is useable.
2e2c49
---
2e2c49
 bin/confgen/keygen.c              | 10 ++++-
2e2c49
 bin/confgen/rndc-confgen.c        | 36 +++++-------------
2e2c49
 bin/dig/dig.c                     |  7 ++--
2e2c49
 bin/dig/dighost.c                 | 14 +++++--
2e2c49
 bin/dnssec/dnssec-keygen.c        | 14 +++++++
2e2c49
 bin/named/config.c                | 25 ++++++++++++-
2e2c49
 bin/nsupdate/nsupdate.c           | 24 +++++++-----
2e2c49
 bin/rndc/rndc.c                   |  3 +-
2e2c49
 bin/tests/optional/hash_test.c    | 78 ++++++++++++++++++++-------------------
2e2c49
 bin/tests/system/tkey/keycreate.c |  3 ++
2e2c49
 bin/tests/system/tkey/keydelete.c | 18 ++++++---
2e2c49
 lib/bind9/check.c                 | 10 +++++
2e2c49
 lib/dns/dst_api.c                 | 23 ++++++++----
2e2c49
 lib/dns/dst_internal.h            |  3 +-
2e2c49
 lib/dns/dst_parse.c               | 18 +++++++--
2e2c49
 lib/dns/hmac_link.c               | 20 +++-------
2e2c49
 lib/dns/opensslrsa_link.c         |  6 +++
2e2c49
 lib/dns/pkcs11rsa_link.c          | 33 +++++++++++++++--
2e2c49
 lib/dns/rcode.c                   | 21 ++++++++++-
2e2c49
 lib/dns/tests/rsa_test.c          | 29 ++++++++-------
2e2c49
 lib/dns/tests/tsig_test.c         |  1 +
2e2c49
 lib/dns/tkey.c                    |  9 +++++
2e2c49
 lib/dns/tsec.c                    |  8 +++-
2e2c49
 lib/dns/tsig.c                    | 17 +++++----
2e2c49
 lib/isc/include/isc/md5.h         |  3 ++
2e2c49
 lib/isc/md5.c                     | 59 +++++++++++++++++++++++++++++
2e2c49
 lib/isc/pk11.c                    | 58 ++++++++++++++++++++---------
2e2c49
 lib/isc/tests/hash_test.c         |  9 +++--
2e2c49
 lib/isccc/cc.c                    | 42 +++++++++++++--------
2e2c49
 29 files changed, 424 insertions(+), 177 deletions(-)
2e2c49
2e2c49
diff --git a/bin/confgen/keygen.c b/bin/confgen/keygen.c
2e2c49
index 453c641dba..11cc54dd46 100644
2e2c49
--- a/bin/confgen/keygen.c
2e2c49
+++ b/bin/confgen/keygen.c
2e2c49
@@ -22,6 +22,7 @@
2e2c49
 #include <isc/entropy.h>
2e2c49
 #include <isc/file.h>
2e2c49
 #include <isc/keyboard.h>
2e2c49
+#include <isc/md5.h>
2e2c49
 #include <isc/mem.h>
2e2c49
 #include <isc/print.h>
2e2c49
 #include <isc/result.h>
2e2c49
@@ -73,7 +74,7 @@ alg_fromtext(const char *name) {
2e2c49
 		p = &name[5];
2e2c49
 
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	if (strcasecmp(p, "md5") == 0)
2e2c49
+	if (strcasecmp(p, "md5") == 0 && isc_md5_available())
2e2c49
 		return DST_ALG_HMACMD5;
2e2c49
 #endif
2e2c49
 	if (strcasecmp(p, "sha1") == 0)
2e2c49
@@ -132,6 +133,13 @@ generate_key(isc_mem_t *mctx, const char *randomfile, dns_secalg_t alg,
2e2c49
 	switch (alg) {
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
 	    case DST_ALG_HMACMD5:
2e2c49
+		if (isc_md5_available() == ISC_FALSE) {
2e2c49
+			fatal("unsupported algorithm %d\n", alg);
2e2c49
+		} else if (keysize < 1 || keysize > 512) {
2e2c49
+			fatal("keysize %d out of range (must be 1-512)\n",
2e2c49
+			      keysize);
2e2c49
+		}
2e2c49
+		break;
2e2c49
 #endif
2e2c49
 	    case DST_ALG_HMACSHA1:
2e2c49
 	    case DST_ALG_HMACSHA224:
2e2c49
diff --git a/bin/confgen/rndc-confgen.c b/bin/confgen/rndc-confgen.c
2e2c49
index 2925baf32f..d7d8418073 100644
2e2c49
--- a/bin/confgen/rndc-confgen.c
2e2c49
+++ b/bin/confgen/rndc-confgen.c
2e2c49
@@ -35,6 +35,7 @@
2e2c49
 #include <isc/file.h>
2e2c49
 #include <isc/keyboard.h>
2e2c49
 #include <isc/mem.h>
2e2c49
+#include <isc/md5.h>
2e2c49
 #include <isc/net.h>
2e2c49
 #include <isc/print.h>
2e2c49
 #include <isc/result.h>
2e2c49
@@ -62,7 +63,7 @@ const char *progname;
2e2c49
 
2e2c49
 isc_boolean_t verbose = ISC_FALSE;
2e2c49
 
2e2c49
-const char *keyfile, *keydef;
2e2c49
+const char *keyfile, *keydef, *algdef;
2e2c49
 
2e2c49
 ISC_PLATFORM_NORETURN_PRE static void
2e2c49
 usage(int status) ISC_PLATFORM_NORETURN_POST;
2e2c49
@@ -70,13 +71,12 @@ usage(int status) ISC_PLATFORM_NORETURN_POST;
2e2c49
 static void
2e2c49
 usage(int status) {
2e2c49
 
2e2c49
-#ifndef PK11_MD5_DISABLE
2e2c49
 	fprintf(stderr, "\
2e2c49
 Usage:\n\
2e2c49
  %s [-a] [-b bits] [-c keyfile] [-k keyname] [-p port] [-r randomfile] \
2e2c49
 [-s addr] [-t chrootdir] [-u user]\n\
2e2c49
   -a:		 generate just the key clause and write it to keyfile (%s)\n\
2e2c49
-  -A alg:	 algorithm (default hmac-md5)\n\
2e2c49
+  -A alg:	 algorithm (default %s)\n\
2e2c49
   -b bits:	 from 1 through 512, default 256; total length of the secret\n\
2e2c49
   -c keyfile:	 specify an alternate key file (requires -a)\n\
2e2c49
   -k keyname:	 the name as it will be used  in named.conf and rndc.conf\n\
2e2c49
@@ -85,24 +85,7 @@ Usage:\n\
2e2c49
   -s addr:	 the address to which rndc should connect\n\
2e2c49
   -t chrootdir:	 write a keyfile in chrootdir as well (requires -a)\n\
2e2c49
   -u user:	 set the keyfile owner to \"user\" (requires -a)\n",
2e2c49
-		 progname, keydef);
2e2c49
-#else
2e2c49
-	fprintf(stderr, "\
2e2c49
-Usage:\n\
2e2c49
- %s [-a] [-b bits] [-c keyfile] [-k keyname] [-p port] [-r randomfile] \
2e2c49
-[-s addr] [-t chrootdir] [-u user]\n\
2e2c49
-  -a:		 generate just the key clause and write it to keyfile (%s)\n\
2e2c49
-  -A alg:	 algorithm (default hmac-sha256)\n\
2e2c49
-  -b bits:	 from 1 through 512, default 256; total length of the secret\n\
2e2c49
-  -c keyfile:	 specify an alternate key file (requires -a)\n\
2e2c49
-  -k keyname:	 the name as it will be used  in named.conf and rndc.conf\n\
2e2c49
-  -p port:	 the port named will listen on and rndc will connect to\n\
2e2c49
-  -r randomfile: source of random data (use \"keyboard\" for key timing)\n\
2e2c49
-  -s addr:	 the address to which rndc should connect\n\
2e2c49
-  -t chrootdir:	 write a keyfile in chrootdir as well (requires -a)\n\
2e2c49
-  -u user:	 set the keyfile owner to \"user\" (requires -a)\n",
2e2c49
-		 progname, keydef);
2e2c49
-#endif
2e2c49
+		 progname, keydef, algdef);
2e2c49
 
2e2c49
 	exit (status);
2e2c49
 }
2e2c49
@@ -138,13 +121,14 @@ main(int argc, char **argv) {
2e2c49
 	progname = program;
2e2c49
 
2e2c49
 	keyname = DEFAULT_KEYNAME;
2e2c49
-#ifndef PK11_MD5_DISABLE
2e2c49
-	alg = DST_ALG_HMACMD5;
2e2c49
-#else
2e2c49
-	alg = DST_ALG_HMACSHA256;
2e2c49
-#endif
2e2c49
 	serveraddr = DEFAULT_SERVER;
2e2c49
 	port = DEFAULT_PORT;
2e2c49
+	alg = DST_ALG_HMACSHA256;
2e2c49
+#ifndef PK11_MD5_DISABLE
2e2c49
+	if (isc_md5_available())
2e2c49
+		alg = DST_ALG_HMACMD5;
2e2c49
+#endif
2e2c49
+	algdef = alg_totext(alg);
2e2c49
 
2e2c49
 	isc_commandline_errprint = ISC_FALSE;
2e2c49
 
2e2c49
diff --git a/bin/dig/dig.c b/bin/dig/dig.c
2e2c49
index d4808ada67..9dff7c8ecd 100644
2e2c49
--- a/bin/dig/dig.c
2e2c49
+++ b/bin/dig/dig.c
2e2c49
@@ -17,6 +17,7 @@
2e2c49
 #include <ctype.h>
2e2c49
 
2e2c49
 #include <isc/app.h>
2e2c49
+#include <isc/md5.h>
2e2c49
 #include <isc/netaddr.h>
2e2c49
 #include <isc/parseint.h>
2e2c49
 #include <isc/platform.h>
2e2c49
@@ -1757,10 +1758,10 @@ dash_option(char *option, char *next, dig_lookup_t **lookup,
2e2c49
 			ptr = ptr2;
2e2c49
 			ptr2 = ptr3;
2e2c49
 		} else  {
2e2c49
-#ifndef PK11_MD5_DISABLE
2e2c49
-			hmacname = DNS_TSIG_HMACMD5_NAME;
2e2c49
-#else
2e2c49
 			hmacname = DNS_TSIG_HMACSHA256_NAME;
2e2c49
+#ifndef PK11_MD5_DISABLE
2e2c49
+			if (isc_md5_available())
2e2c49
+				hmacname = DNS_TSIG_HMACMD5_NAME;
2e2c49
 #endif
2e2c49
 			digestbits = 0;
2e2c49
 		}
2e2c49
diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c
2e2c49
index ecefc98453..94c428ed30 100644
2e2c49
--- a/bin/dig/dighost.c
2e2c49
+++ b/bin/dig/dighost.c
2e2c49
@@ -77,6 +77,7 @@
2e2c49
 #include <isc/hex.h>
2e2c49
 #include <isc/lang.h>
2e2c49
 #include <isc/log.h>
2e2c49
+#include <isc/md5.h>
2e2c49
 #include <isc/netaddr.h>
2e2c49
 #include <isc/netdb.h>
2e2c49
 #include <isc/parseint.h>
2e2c49
@@ -1243,9 +1244,10 @@ parse_hmac(const char *hmac) {
2e2c49
 	digestbits = 0;
2e2c49
 
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	if (strcasecmp(buf, "hmac-md5") == 0) {
2e2c49
+	if (strcasecmp(buf, "hmac-md5") == 0 && isc_md5_available()) {
2e2c49
 		hmacname = DNS_TSIG_HMACMD5_NAME;
2e2c49
-	} else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
2e2c49
+	} else if (strncasecmp(buf, "hmac-md5-", 9) == 0 &&
2e2c49
+		   isc_md5_available()) {
2e2c49
 		hmacname = DNS_TSIG_HMACMD5_NAME;
2e2c49
 		digestbits = parse_bits(&buf[9], "digest-bits [0..128]", 128);
2e2c49
 	} else
2e2c49
@@ -1365,7 +1367,13 @@ setup_file_key(void) {
2e2c49
 	switch (dst_key_alg(dstkey)) {
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
 	case DST_ALG_HMACMD5:
2e2c49
-		hmacname = DNS_TSIG_HMACMD5_NAME;
2e2c49
+		if (isc_md5_available()) {
2e2c49
+			hmacname = DNS_TSIG_HMACMD5_NAME;
2e2c49
+		} else {
2e2c49
+			printf(";; Couldn't create key %s: bad algorithm\n",
2e2c49
+			       keynametext);
2e2c49
+			goto failure;
2e2c49
+		}
2e2c49
 		break;
2e2c49
 #endif
2e2c49
 	case DST_ALG_HMACSHA1:
2e2c49
diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c
2e2c49
index 6fc3ab0979..fc04356ed4 100644
2e2c49
--- a/bin/dnssec/dnssec-keygen.c
2e2c49
+++ b/bin/dnssec/dnssec-keygen.c
2e2c49
@@ -34,6 +34,7 @@
2e2c49
 #include <isc/buffer.h>
2e2c49
 #include <isc/commandline.h>
2e2c49
 #include <isc/entropy.h>
2e2c49
+#include <isc/md5.h>
2e2c49
 #include <isc/mem.h>
2e2c49
 #include <isc/print.h>
2e2c49
 #include <isc/region.h>
2e2c49
@@ -560,6 +561,19 @@ main(int argc, char **argv) {
2e2c49
 					"\"-a RSAMD5\"\n");
2e2c49
 			INSIST(freeit == NULL);
2e2c49
 			return (1);
2e2c49
+		} else if (strcasecmp(algname, "HMAC-MD5") == 0) {
2e2c49
+			if (isc_md5_available()) {
2e2c49
+				alg = DST_ALG_HMACMD5;
2e2c49
+			} else {
2e2c49
+				fprintf(stderr,
2e2c49
+					"The use of HMAC-MD5 was disabled\n");
2e2c49
+				return (1);
2e2c49
+			}
2e2c49
+		} else if (strcasecmp(algname, "RSAMD5") == 0 &&
2e2c49
+			   isc_md5_available() == ISC_FALSE) {
2e2c49
+			fprintf(stderr, "The use of RSAMD5 was disabled\n");
2e2c49
+			INSIST(freeit == NULL);
2e2c49
+			return (1);
2e2c49
 		} else if (strcasecmp(algname, "HMAC-MD5") == 0) {
2e2c49
 			alg = DST_ALG_HMACMD5;
2e2c49
 #else
2e2c49
diff --git a/bin/named/config.c b/bin/named/config.c
2e2c49
index 54bc37fff7..c50f759ddd 100644
2e2c49
--- a/bin/named/config.c
2e2c49
+++ b/bin/named/config.c
2e2c49
@@ -17,6 +17,7 @@
2e2c49
 
2e2c49
 #include <isc/buffer.h>
2e2c49
 #include <isc/log.h>
2e2c49
+#include <isc/md5.h>
2e2c49
 #include <isc/mem.h>
2e2c49
 #include <isc/parseint.h>
2e2c49
 #include <isc/region.h>
2e2c49
@@ -966,6 +967,21 @@ ns_config_getkeyalgorithm(const char *str, dns_name_t **name,
2e2c49
 	return (ns_config_getkeyalgorithm2(str, name, NULL, digestbits));
2e2c49
 }
2e2c49
 
2e2c49
+static inline int
2e2c49
+algorithms_start() {
2e2c49
+#ifndef PK11_MD5_DISABLE
2e2c49
+	if (isc_md5_available() == ISC_FALSE) {
2e2c49
+		int i = 0;
2e2c49
+		while (algorithms[i].str != NULL &&
2e2c49
+			algorithms[i].hmac == hmacmd5) {
2e2c49
+			i++;
2e2c49
+		}
2e2c49
+		return i;
2e2c49
+	}
2e2c49
+#endif
2e2c49
+	return 0;
2e2c49
+}
2e2c49
+
2e2c49
 isc_result_t
2e2c49
 ns_config_getkeyalgorithm2(const char *str, dns_name_t **name,
2e2c49
 			   unsigned int *typep, isc_uint16_t *digestbits)
2e2c49
@@ -975,7 +991,7 @@ ns_config_getkeyalgorithm2(const char *str, dns_name_t **name,
2e2c49
 	isc_uint16_t bits;
2e2c49
 	isc_result_t result;
2e2c49
 
2e2c49
-	for (i = 0; algorithms[i].str != NULL; i++) {
2e2c49
+	for (i = algorithms_start(); algorithms[i].str != NULL; i++) {
2e2c49
 		len = strlen(algorithms[i].str);
2e2c49
 		if (strncasecmp(algorithms[i].str, str, len) == 0 &&
2e2c49
 		    (str[len] == '\0' ||
2e2c49
@@ -998,7 +1014,12 @@ ns_config_getkeyalgorithm2(const char *str, dns_name_t **name,
2e2c49
 	if (name != NULL) {
2e2c49
 		switch (algorithms[i].hmac) {
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-		case hmacmd5: *name = dns_tsig_hmacmd5_name; break;
2e2c49
+		case hmacmd5:
2e2c49
+			if (isc_md5_available()) {
2e2c49
+				*name = dns_tsig_hmacmd5_name; break;
2e2c49
+			} else {
2e2c49
+				return (ISC_R_NOTFOUND);
2e2c49
+			}
2e2c49
 #endif
2e2c49
 		case hmacsha1: *name = dns_tsig_hmacsha1_name; break;
2e2c49
 		case hmacsha224: *name = dns_tsig_hmacsha224_name; break;
2e2c49
diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c
2e2c49
index 6967b49754..bb5d50038f 100644
2e2c49
--- a/bin/nsupdate/nsupdate.c
2e2c49
+++ b/bin/nsupdate/nsupdate.c
2e2c49
@@ -29,6 +29,7 @@
2e2c49
 #include <isc/hash.h>
2e2c49
 #include <isc/lex.h>
2e2c49
 #include <isc/log.h>
2e2c49
+#include <isc/md5.h>
2e2c49
 #include <isc/mem.h>
2e2c49
 #include <isc/parseint.h>
2e2c49
 #include <isc/print.h>
2e2c49
@@ -474,9 +475,10 @@ parse_hmac(dns_name_t **hmac, const char *hmacstr, size_t len,
2e2c49
 	strlcpy(buf, hmacstr, ISC_MIN(len + 1, sizeof(buf)));
2e2c49
 
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	if (strcasecmp(buf, "hmac-md5") == 0) {
2e2c49
+	if (strcasecmp(buf, "hmac-md5") == 0 && isc_md5_available()) {
2e2c49
 		*hmac = DNS_TSIG_HMACMD5_NAME;
2e2c49
-	} else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
2e2c49
+	} else if (strncasecmp(buf, "hmac-md5-", 9) == 0 &&
2e2c49
+		   isc_md5_available()) {
2e2c49
 		*hmac = DNS_TSIG_HMACMD5_NAME;
2e2c49
 		result = isc_parse_uint16(&digestbits, &buf[9], 10);
2e2c49
 		if (result != ISC_R_SUCCESS || digestbits > 128) {
2e2c49
@@ -589,10 +591,10 @@ setup_keystr(void) {
2e2c49
 			exit(1);
2e2c49
 		}
2e2c49
 	} else {
2e2c49
-#ifndef PK11_MD5_DISABLE
2e2c49
-		hmacname = DNS_TSIG_HMACMD5_NAME;
2e2c49
-#else
2e2c49
 		hmacname = DNS_TSIG_HMACSHA256_NAME;
2e2c49
+#ifndef PK11_MD5_DISABLE
2e2c49
+		if (isc_md5_available())
2e2c49
+			hmacname = DNS_TSIG_HMACMD5_NAME;
2e2c49
 #endif
2e2c49
 		name = keystr;
2e2c49
 		n = s;
2e2c49
@@ -729,7 +731,8 @@ setup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) {
2e2c49
 	switch (dst_key_alg(dstkey)) {
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
 	case DST_ALG_HMACMD5:
2e2c49
-		hmacname = DNS_TSIG_HMACMD5_NAME;
2e2c49
+		if (isc_md5_available())
2e2c49
+			hmacname = DNS_TSIG_HMACMD5_NAME;
2e2c49
 		break;
2e2c49
 #endif
2e2c49
 	case DST_ALG_HMACSHA1:
2e2c49
@@ -1604,12 +1607,13 @@ evaluate_key(char *cmdline) {
2e2c49
 			return (STATUS_SYNTAX);
2e2c49
 		}
2e2c49
 		namestr = n + 1;
2e2c49
-	} else
2e2c49
-#ifndef PK11_MD5_DISABLE
2e2c49
-		hmacname = DNS_TSIG_HMACMD5_NAME;
2e2c49
-#else
2e2c49
+	} else {
2e2c49
 		hmacname = DNS_TSIG_HMACSHA256_NAME;
2e2c49
+#ifndef PK11_MD5_DISABLE
2e2c49
+		if (isc_md5_available())
2e2c49
+			hmacname = DNS_TSIG_HMACMD5_NAME;
2e2c49
 #endif
2e2c49
+	}
2e2c49
 
2e2c49
 	isc_buffer_init(&b, namestr, strlen(namestr));
2e2c49
 	isc_buffer_add(&b, strlen(namestr));
2e2c49
diff --git a/bin/rndc/rndc.c b/bin/rndc/rndc.c
2e2c49
index 5c29caf86b..617b06b4a1 100644
2e2c49
--- a/bin/rndc/rndc.c
2e2c49
+++ b/bin/rndc/rndc.c
2e2c49
@@ -21,6 +21,7 @@
2e2c49
 #include <isc/file.h>
2e2c49
 #include <isc/log.h>
2e2c49
 #include <isc/net.h>
2e2c49
+#include <isc/md5.h>
2e2c49
 #include <isc/mem.h>
2e2c49
 #include <isc/print.h>
2e2c49
 #include <isc/random.h>
2e2c49
@@ -634,7 +635,7 @@ parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname,
2e2c49
 	algorithmstr = cfg_obj_asstring(algorithmobj);
2e2c49
 
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	if (strcasecmp(algorithmstr, "hmac-md5") == 0)
2e2c49
+	if (strcasecmp(algorithmstr, "hmac-md5") == 0 && isc_md5_available())
2e2c49
 		algorithm = ISCCC_ALG_HMACMD5;
2e2c49
 	else
2e2c49
 #endif
2e2c49
diff --git a/bin/tests/optional/hash_test.c b/bin/tests/optional/hash_test.c
2e2c49
index bf2891ad4c..b5f0a1c5f5 100644
2e2c49
--- a/bin/tests/optional/hash_test.c
2e2c49
+++ b/bin/tests/optional/hash_test.c
2e2c49
@@ -90,43 +90,47 @@ main(int argc, char **argv) {
2e2c49
 	print_digest(s, "sha224", digest, ISC_SHA224_DIGESTLENGTH/4);
2e2c49
 
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	s = "abc";
2e2c49
-	isc_md5_init(&md5;;
2e2c49
-	memmove(buffer, s, strlen(s));
2e2c49
-	isc_md5_update(&md5, buffer, strlen(s));
2e2c49
-	isc_md5_final(&md5, digest);
2e2c49
-	print_digest(s, "md5", digest, 4);
2e2c49
-
2e2c49
-	/*
2e2c49
-	 * The 3 HMAC-MD5 examples from RFC2104
2e2c49
-	 */
2e2c49
-	s = "Hi There";
2e2c49
-	memset(key, 0x0b, 16);
2e2c49
-	isc_hmacmd5_init(&hmacmd5, key, 16);
2e2c49
-	memmove(buffer, s, strlen(s));
2e2c49
-	isc_hmacmd5_update(&hmacmd5, buffer, strlen(s));
2e2c49
-	isc_hmacmd5_sign(&hmacmd5, digest);
2e2c49
-	print_digest(s, "hmacmd5", digest, 4);
2e2c49
-
2e2c49
-	s = "what do ya want for nothing?";
2e2c49
-	strlcpy((char *)key, "Jefe", sizeof(key));
2e2c49
-	isc_hmacmd5_init(&hmacmd5, key, 4);
2e2c49
-	memmove(buffer, s, strlen(s));
2e2c49
-	isc_hmacmd5_update(&hmacmd5, buffer, strlen(s));
2e2c49
-	isc_hmacmd5_sign(&hmacmd5, digest);
2e2c49
-	print_digest(s, "hmacmd5", digest, 4);
2e2c49
-
2e2c49
-	s = "\335\335\335\335\335\335\335\335\335\335"
2e2c49
-	    "\335\335\335\335\335\335\335\335\335\335"
2e2c49
-	    "\335\335\335\335\335\335\335\335\335\335"
2e2c49
-	    "\335\335\335\335\335\335\335\335\335\335"
2e2c49
-	    "\335\335\335\335\335\335\335\335\335\335";
2e2c49
-	memset(key, 0xaa, 16);
2e2c49
-	isc_hmacmd5_init(&hmacmd5, key, 16);
2e2c49
-	memmove(buffer, s, strlen(s));
2e2c49
-	isc_hmacmd5_update(&hmacmd5, buffer, strlen(s));
2e2c49
-	isc_hmacmd5_sign(&hmacmd5, digest);
2e2c49
-	print_digest(s, "hmacmd5", digest, 4);
2e2c49
+	if (isc_md5_available()) {
2e2c49
+		s = "abc";
2e2c49
+		isc_md5_init(&md5;;
2e2c49
+		memmove(buffer, s, strlen(s));
2e2c49
+		isc_md5_update(&md5, buffer, strlen(s));
2e2c49
+		isc_md5_final(&md5, digest);
2e2c49
+		print_digest(s, "md5", digest, 4);
2e2c49
+
2e2c49
+		/*
2e2c49
+		 * The 3 HMAC-MD5 examples from RFC2104
2e2c49
+		 */
2e2c49
+		s = "Hi There";
2e2c49
+		memset(key, 0x0b, 16);
2e2c49
+		isc_hmacmd5_init(&hmacmd5, key, 16);
2e2c49
+		memmove(buffer, s, strlen(s));
2e2c49
+		isc_hmacmd5_update(&hmacmd5, buffer, strlen(s));
2e2c49
+		isc_hmacmd5_sign(&hmacmd5, digest);
2e2c49
+		print_digest(s, "hmacmd5", digest, 4);
2e2c49
+
2e2c49
+		s = "what do ya want for nothing?";
2e2c49
+		strlcpy((char *)key, "Jefe", sizeof(key));
2e2c49
+		isc_hmacmd5_init(&hmacmd5, key, 4);
2e2c49
+		memmove(buffer, s, strlen(s));
2e2c49
+		isc_hmacmd5_update(&hmacmd5, buffer, strlen(s));
2e2c49
+		isc_hmacmd5_sign(&hmacmd5, digest);
2e2c49
+		print_digest(s, "hmacmd5", digest, 4);
2e2c49
+
2e2c49
+		s = "\335\335\335\335\335\335\335\335\335\335"
2e2c49
+		    "\335\335\335\335\335\335\335\335\335\335"
2e2c49
+		    "\335\335\335\335\335\335\335\335\335\335"
2e2c49
+		    "\335\335\335\335\335\335\335\335\335\335"
2e2c49
+		    "\335\335\335\335\335\335\335\335\335\335";
2e2c49
+		memset(key, 0xaa, 16);
2e2c49
+		isc_hmacmd5_init(&hmacmd5, key, 16);
2e2c49
+		memmove(buffer, s, strlen(s));
2e2c49
+		isc_hmacmd5_update(&hmacmd5, buffer, strlen(s));
2e2c49
+		isc_hmacmd5_sign(&hmacmd5, digest);
2e2c49
+		print_digest(s, "hmacmd5", digest, 4);
2e2c49
+	} else {
2e2c49
+		fprintf(stderr, "Skipping disabled MD5 algorithm\n");
2e2c49
+	}
2e2c49
 #endif
2e2c49
 
2e2c49
 	/*
2e2c49
diff --git a/bin/tests/system/tkey/keycreate.c b/bin/tests/system/tkey/keycreate.c
2e2c49
index 2a0ee94888..489f4390dc 100644
2e2c49
--- a/bin/tests/system/tkey/keycreate.c
2e2c49
+++ b/bin/tests/system/tkey/keycreate.c
2e2c49
@@ -20,6 +20,7 @@
2e2c49
 #include <isc/entropy.h>
2e2c49
 #include <isc/hash.h>
2e2c49
 #include <isc/log.h>
2e2c49
+#include <isc/md5.h>
2e2c49
 #include <isc/mem.h>
2e2c49
 #include <isc/print.h>
2e2c49
 #include <isc/sockaddr.h>
2e2c49
@@ -142,6 +143,8 @@ sendquery(isc_task_t *task, isc_event_t *event) {
2e2c49
 	static char keystr[] = "0123456789ab";
2e2c49
 
2e2c49
 	isc_event_free(&event);
2e2c49
+	if (isc_md5_available() == ISC_FALSE)
2e2c49
+		CHECK("MD5 was disabled", ISC_R_NOTIMPLEMENTED);
2e2c49
 
2e2c49
 	result = ISC_R_FAILURE;
2e2c49
 	if (inet_pton(AF_INET, "10.53.0.1", &inaddr) != 1)
2e2c49
diff --git a/bin/tests/system/tkey/keydelete.c b/bin/tests/system/tkey/keydelete.c
2e2c49
index 7057c318e4..36ee6c7d21 100644
2e2c49
--- a/bin/tests/system/tkey/keydelete.c
2e2c49
+++ b/bin/tests/system/tkey/keydelete.c
2e2c49
@@ -225,12 +225,18 @@ main(int argc, char **argv) {
2e2c49
 	result = dst_key_fromnamedfile(keyname, NULL, type, mctx, &dstkey);
2e2c49
 	CHECK("dst_key_fromnamedfile", result);
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
2e2c49
-					   DNS_TSIG_HMACMD5_NAME,
2e2c49
-					   dstkey, ISC_TRUE, NULL, 0, 0,
2e2c49
-					   mctx, ring, &tsigkey);
2e2c49
-	dst_key_free(&dstkey);
2e2c49
-	CHECK("dns_tsigkey_createfromkey", result);
2e2c49
+	if (isc_md5_available()) {
2e2c49
+		result = dns_tsigkey_createfromkey(dst_key_name(dstkey),
2e2c49
+						   DNS_TSIG_HMACMD5_NAME,
2e2c49
+						   dstkey, ISC_TRUE,
2e2c49
+						   NULL, 0, 0,
2e2c49
+						   mctx, ring, &tsigkey);
2e2c49
+		dst_key_free(&dstkey);
2e2c49
+		CHECK("dns_tsigkey_createfromkey", result);
2e2c49
+	} else {
2e2c49
+		dst_key_free(&dstkey);
2e2c49
+		CHECK("MD5 was disabled", ISC_R_NOTIMPLEMENTED);
2e2c49
+	}
2e2c49
 #else
2e2c49
 	dst_key_free(&dstkey);
2e2c49
 	CHECK("MD5 was disabled", ISC_R_NOTIMPLEMENTED);
2e2c49
diff --git a/lib/bind9/check.c b/lib/bind9/check.c
2e2c49
index 3da83a7ae2..1a3d534799 100644
2e2c49
--- a/lib/bind9/check.c
2e2c49
+++ b/lib/bind9/check.c
2e2c49
@@ -21,6 +21,7 @@
2e2c49
 #include <isc/file.h>
2e2c49
 #include <isc/hex.h>
2e2c49
 #include <isc/log.h>
2e2c49
+#include <isc/md5.h>
2e2c49
 #include <isc/mem.h>
2e2c49
 #include <isc/netaddr.h>
2e2c49
 #include <isc/parseint.h>
2e2c49
@@ -2572,6 +2573,15 @@ bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
2e2c49
 	}
2e2c49
 
2e2c49
 	algorithm = cfg_obj_asstring(algobj);
2e2c49
+#ifndef PK11_MD5_DISABLE
2e2c49
+	/* Skip hmac-md5* algorithms */
2e2c49
+	if (isc_md5_available() == ISC_FALSE &&
2e2c49
+	    strncasecmp(algorithm, "hmac-md5", 8) == 0) {
2e2c49
+		cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
2e2c49
+			    "disabled algorithm '%s'", algorithm);
2e2c49
+		return (ISC_R_DISABLED);
2e2c49
+	}
2e2c49
+#endif
2e2c49
 	for (i = 0; algorithms[i].name != NULL; i++) {
2e2c49
 		len = strlen(algorithms[i].name);
2e2c49
 		if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
2e2c49
diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c
2e2c49
index 4f3d6ac55c..dbece0ac56 100644
2e2c49
--- a/lib/dns/dst_api.c
2e2c49
+++ b/lib/dns/dst_api.c
2e2c49
@@ -190,6 +190,12 @@ dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx,
2e2c49
 	dst_result_register();
2e2c49
 
2e2c49
 	memset(dst_t_func, 0, sizeof(dst_t_func));
2e2c49
+
2e2c49
+#ifdef OPENSSL
2e2c49
+	RETERR(dst__openssl_init(engine));
2e2c49
+#elif PKCS11CRYPTO
2e2c49
+	RETERR(dst__pkcs11_init(mctx, engine));
2e2c49
+#endif
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
 	RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5]));
2e2c49
 #endif
2e2c49
@@ -199,7 +205,6 @@ dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx,
2e2c49
 	RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384]));
2e2c49
 	RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512]));
2e2c49
 #ifdef OPENSSL
2e2c49
-	RETERR(dst__openssl_init(engine));
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
 	RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5],
2e2c49
 				    DST_ALG_RSAMD5));
2e2c49
@@ -233,14 +238,18 @@ dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx,
2e2c49
 	RETERR(dst__openssleddsa_init(&dst_t_func[DST_ALG_ED448]));
2e2c49
 #endif
2e2c49
 #elif PKCS11CRYPTO
2e2c49
-	RETERR(dst__pkcs11_init(mctx, engine));
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSAMD5]));
2e2c49
+	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSAMD5],
2e2c49
+				   DST_ALG_RSAMD5));
2e2c49
 #endif
2e2c49
-	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA1]));
2e2c49
-	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1]));
2e2c49
-	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA256]));
2e2c49
-	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA512]));
2e2c49
+	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA1],
2e2c49
+				   DST_ALG_RSASHA1));
2e2c49
+	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1],
2e2c49
+				   DST_ALG_NSEC3RSASHA1));
2e2c49
+	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA256],
2e2c49
+				   DST_ALG_RSASHA256));
2e2c49
+	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA512],
2e2c49
+				   DST_ALG_RSASHA512));
2e2c49
 #ifndef PK11_DSA_DISABLE
2e2c49
 	RETERR(dst__pkcs11dsa_init(&dst_t_func[DST_ALG_DSA]));
2e2c49
 	RETERR(dst__pkcs11dsa_init(&dst_t_func[DST_ALG_NSEC3DSA]));
2e2c49
diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h
2e2c49
index 640519a5ba..deb7ed4e13 100644
2e2c49
--- a/lib/dns/dst_internal.h
2e2c49
+++ b/lib/dns/dst_internal.h
2e2c49
@@ -245,7 +245,8 @@ isc_result_t dst__hmacsha384_init(struct dst_func **funcp);
2e2c49
 isc_result_t dst__hmacsha512_init(struct dst_func **funcp);
2e2c49
 isc_result_t dst__opensslrsa_init(struct dst_func **funcp,
2e2c49
 				  unsigned char algorithm);
2e2c49
-isc_result_t dst__pkcs11rsa_init(struct dst_func **funcp);
2e2c49
+isc_result_t dst__pkcs11rsa_init(struct dst_func **funcp,
2e2c49
+				 unsigned char algorithm);
2e2c49
 #ifndef PK11_DSA_DISABLE
2e2c49
 isc_result_t dst__openssldsa_init(struct dst_func **funcp);
2e2c49
 isc_result_t dst__pkcs11dsa_init(struct dst_func **funcp);
2e2c49
diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c
2e2c49
index b0e5c895c6..03f2b8ace8 100644
2e2c49
--- a/lib/dns/dst_parse.c
2e2c49
+++ b/lib/dns/dst_parse.c
2e2c49
@@ -30,6 +30,7 @@
2e2c49
 #include <isc/file.h>
2e2c49
 #include <isc/fsaccess.h>
2e2c49
 #include <isc/lex.h>
2e2c49
+#include <isc/md5.h>
2e2c49
 #include <isc/mem.h>
2e2c49
 #include <isc/print.h>
2e2c49
 #include <isc/stdtime.h>
2e2c49
@@ -393,6 +394,10 @@ check_data(const dst_private_t *priv, const unsigned int alg,
2e2c49
 	switch (alg) {
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
 	case DST_ALG_RSAMD5:
2e2c49
+		if (isc_md5_available())
2e2c49
+			return (check_rsa(priv, external));
2e2c49
+		else
2e2c49
+			return (DST_R_UNSUPPORTEDALG);
2e2c49
 #endif
2e2c49
 	case DST_ALG_RSASHA1:
2e2c49
 	case DST_ALG_NSEC3RSASHA1:
2e2c49
@@ -418,7 +423,10 @@ check_data(const dst_private_t *priv, const unsigned int alg,
2e2c49
 		return (check_eddsa(priv, external));
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
 	case DST_ALG_HMACMD5:
2e2c49
-		return (check_hmac_md5(priv, old));
2e2c49
+		if (isc_md5_available())
2e2c49
+			return (check_hmac_md5(priv, old));
2e2c49
+		else
2e2c49
+			return (DST_R_UNSUPPORTEDALG);
2e2c49
 #endif
2e2c49
 	case DST_ALG_HMACSHA1:
2e2c49
 		return (check_hmac_sha(priv, HMACSHA1_NTAGS, alg));
2e2c49
@@ -637,11 +645,13 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
2e2c49
 	}
2e2c49
 
2e2c49
 #ifdef PK11_MD5_DISABLE
2e2c49
-	check = check_data(priv, alg == DST_ALG_RSA ? DST_ALG_RSASHA1 : alg,
2e2c49
-			   ISC_TRUE, external);
2e2c49
+	if (alg == DST_ALG_RSA)
2e2c49
+		alg = DST_ALG_RSASHA1;
2e2c49
 #else
2e2c49
-	check = check_data(priv, alg, ISC_TRUE, external);
2e2c49
+	if (isc_md5_available() == ISC_FALSE && alg == DST_ALG_RSA)
2e2c49
+		alg = DST_ALG_RSASHA1;
2e2c49
 #endif
2e2c49
+	check = check_data(priv, alg, ISC_TRUE, external);
2e2c49
 	if (check < 0) {
2e2c49
 		ret = DST_R_INVALIDPRIVATEKEY;
2e2c49
 		goto fail;
2e2c49
diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c
2e2c49
index 59aa4705e5..21bfa44450 100644
2e2c49
--- a/lib/dns/hmac_link.c
2e2c49
+++ b/lib/dns/hmac_link.c
2e2c49
@@ -338,25 +338,17 @@ static dst_func_t hmacmd5_functions = {
2e2c49
 
2e2c49
 isc_result_t
2e2c49
 dst__hmacmd5_init(dst_func_t **funcp) {
2e2c49
-#ifdef HAVE_FIPS_MODE
2e2c49
 	/*
2e2c49
-	 * Problems from OpenSSL are likely from FIPS mode
2e2c49
+	 * Prevent use of incorrect crypto
2e2c49
 	 */
2e2c49
-	int fips_mode = FIPS_mode();
2e2c49
-
2e2c49
-	if (fips_mode != 0) {
2e2c49
-		UNEXPECTED_ERROR(__FILE__, __LINE__,
2e2c49
-				 "FIPS mode is %d: MD5 is only supported "
2e2c49
-				 "if the value is 0.\n"
2e2c49
-				 "Please disable either FIPS mode or MD5.",
2e2c49
-				 fips_mode);
2e2c49
+
2e2c49
+#ifndef PK11_MD5_DISABLE
2e2c49
+	if (isc_md5_available() == ISC_FALSE) {
2e2c49
+		/* Intentionally skip initialization */
2e2c49
+		return (ISC_R_SUCCESS);
2e2c49
 	}
2e2c49
 #endif
2e2c49
 
2e2c49
-	/*
2e2c49
-	 * Prevent use of incorrect crypto
2e2c49
-	 */
2e2c49
-
2e2c49
 	RUNTIME_CHECK(isc_md5_check(ISC_FALSE));
2e2c49
 	RUNTIME_CHECK(isc_hmacmd5_check(0));
2e2c49
 
2e2c49
diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c
2e2c49
index f4847bbe74..126cebca19 100644
2e2c49
--- a/lib/dns/opensslrsa_link.c
2e2c49
+++ b/lib/dns/opensslrsa_link.c
2e2c49
@@ -1801,6 +1801,12 @@ dst__opensslrsa_init(dst_func_t **funcp, unsigned char algorithm) {
2e2c49
 
2e2c49
 	if (*funcp == NULL) {
2e2c49
 		switch (algorithm) {
2e2c49
+#ifndef PK11_MD5_DISABLE
2e2c49
+		case DST_ALG_RSAMD5:
2e2c49
+			if (isc_md5_available())
2e2c49
+				*funcp = &opensslrsa_functions;
2e2c49
+			break;
2e2c49
+#endif
2e2c49
 		case DST_ALG_RSASHA256:
2e2c49
 #if defined(HAVE_EVP_SHA256) || !USE_EVP
2e2c49
 			*funcp = &opensslrsa_functions;
2e2c49
diff --git a/lib/dns/pkcs11rsa_link.c b/lib/dns/pkcs11rsa_link.c
2e2c49
index 56955203e9..af6008d4dd 100644
2e2c49
--- a/lib/dns/pkcs11rsa_link.c
2e2c49
+++ b/lib/dns/pkcs11rsa_link.c
2e2c49
@@ -94,10 +94,15 @@ pkcs11rsa_createctx_sign(dst_key_t *key, dst_context_t *dctx) {
2e2c49
 #endif
2e2c49
 
2e2c49
 	/*
2e2c49
-	 * Reject incorrect RSA key lengths.
2e2c49
+	 * Reject incorrect RSA key lengths or disabled algorithms.
2e2c49
 	 */
2e2c49
 	switch (dctx->key->key_alg) {
2e2c49
 	case DST_ALG_RSAMD5:
2e2c49
+#ifndef PK11_MD5_DISABLE
2e2c49
+		if (isc_md5_available() == ISC_FALSE)
2e2c49
+			return (ISC_R_FAILURE);
2e2c49
+#endif
2e2c49
+		/* FALLTHROUGH */
2e2c49
 	case DST_ALG_RSASHA1:
2e2c49
 	case DST_ALG_NSEC3RSASHA1:
2e2c49
 		/* From RFC 3110 */
2e2c49
@@ -634,6 +639,9 @@ pkcs11rsa_createctx(dst_key_t *key, dst_context_t *dctx) {
2e2c49
 	switch (key->key_alg) {
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
 	case DST_ALG_RSAMD5:
2e2c49
+		if (isc_md5_available() == ISC_FALSE)
2e2c49
+			return (ISC_R_FAILURE);
2e2c49
+	
2e2c49
 		mech.mechanism = CKM_MD5;
2e2c49
 		break;
2e2c49
 #endif
2e2c49
@@ -790,6 +798,9 @@ pkcs11rsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
2e2c49
 	switch (key->key_alg) {
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
 	case DST_ALG_RSAMD5:
2e2c49
+		if (isc_md5_available() == ISC_FALSE)
2e2c49
+			return (ISC_R_FAILURE);
2e2c49
+
2e2c49
 		der = md5_der;
2e2c49
 		derlen = sizeof(md5_der);
2e2c49
 		hashlen = ISC_MD5_DIGESTLENGTH;
2e2c49
@@ -1014,6 +1025,9 @@ pkcs11rsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
2e2c49
 	switch (key->key_alg) {
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
 	case DST_ALG_RSAMD5:
2e2c49
+		if (isc_md5_available() == ISC_FALSE)
2e2c49
+			return (ISC_R_FAILURE);
2e2c49
+
2e2c49
 		der = md5_der;
2e2c49
 		derlen = sizeof(md5_der);
2e2c49
 		hashlen = ISC_MD5_DIGESTLENGTH;
2e2c49
@@ -2217,11 +2231,22 @@ static dst_func_t pkcs11rsa_functions = {
2e2c49
 };
2e2c49
 
2e2c49
 isc_result_t
2e2c49
-dst__pkcs11rsa_init(dst_func_t **funcp) {
2e2c49
+dst__pkcs11rsa_init(dst_func_t **funcp, unsigned char algorithm) {
2e2c49
 	REQUIRE(funcp != NULL);
2e2c49
 
2e2c49
-	if (*funcp == NULL)
2e2c49
-		*funcp = &pkcs11rsa_functions;
2e2c49
+	if (*funcp == NULL) {
2e2c49
+		switch (algorithm) {
2e2c49
+#ifndef PK11_MD5_DISABLE
2e2c49
+			case DST_ALG_RSAMD5:
2e2c49
+				if (isc_md5_available())
2e2c49
+					*funcp = &pkcs11rsa_functions;
2e2c49
+				break;
2e2c49
+#endif
2e2c49
+			default:
2e2c49
+				*funcp = &pkcs11rsa_functions;
2e2c49
+				break;
2e2c49
+		}
2e2c49
+	}
2e2c49
 	return (ISC_R_SUCCESS);
2e2c49
 }
2e2c49
 
2e2c49
diff --git a/lib/dns/rcode.c b/lib/dns/rcode.c
2e2c49
index 937d8fc1ec..d1fa8d5870 100644
2e2c49
--- a/lib/dns/rcode.c
2e2c49
+++ b/lib/dns/rcode.c
2e2c49
@@ -14,6 +14,7 @@
2e2c49
 #include <ctype.h>
2e2c49
 
2e2c49
 #include <isc/buffer.h>
2e2c49
+#include <isc/md5.h>
2e2c49
 #include <isc/parseint.h>
2e2c49
 #include <isc/print.h>
2e2c49
 #include <isc/region.h>
2e2c49
@@ -347,17 +348,33 @@ dns_cert_totext(dns_cert_t cert, isc_buffer_t *target) {
2e2c49
 	return (dns_mnemonic_totext(cert, target, certs));
2e2c49
 }
2e2c49
 
2e2c49
+static inline struct tbl *
2e2c49
+secalgs_tbl_start() {
2e2c49
+	struct tbl *algs = secalgs;
2e2c49
+
2e2c49
+#ifndef PK11_MD5_DISABLE
2e2c49
+	if (isc_md5_available() == ISC_FALSE) {
2e2c49
+		while (algs->name != NULL &&
2e2c49
+		       algs->value == DNS_KEYALG_RSAMD5)
2e2c49
+			++algs;
2e2c49
+	}
2e2c49
+#endif
2e2c49
+	return algs;
2e2c49
+}
2e2c49
+
2e2c49
 isc_result_t
2e2c49
 dns_secalg_fromtext(dns_secalg_t *secalgp, isc_textregion_t *source) {
2e2c49
 	unsigned int value;
2e2c49
-	RETERR(dns_mnemonic_fromtext(&value, source, secalgs, 0xff));
2e2c49
+
2e2c49
+	RETERR(dns_mnemonic_fromtext(&value, source,
2e2c49
+	                             secalgs_tbl_start(), 0xff));
2e2c49
 	*secalgp = value;
2e2c49
 	return (ISC_R_SUCCESS);
2e2c49
 }
2e2c49
 
2e2c49
 isc_result_t
2e2c49
 dns_secalg_totext(dns_secalg_t secalg, isc_buffer_t *target) {
2e2c49
-	return (dns_mnemonic_totext(secalg, target, secalgs));
2e2c49
+	return (dns_mnemonic_totext(secalg, target, secalgs_tbl_start()));
2e2c49
 }
2e2c49
 
2e2c49
 void
2e2c49
diff --git a/lib/dns/tests/rsa_test.c b/lib/dns/tests/rsa_test.c
2e2c49
index 224cf5b475..44040dd8b7 100644
2e2c49
--- a/lib/dns/tests/rsa_test.c
2e2c49
+++ b/lib/dns/tests/rsa_test.c
2e2c49
@@ -19,6 +19,7 @@
2e2c49
 #include <stdio.h>
2e2c49
 #include <string.h>
2e2c49
 
2e2c49
+#include <isc/md5.h>
2e2c49
 #include <isc/util.h>
2e2c49
 #include <isc/print.h>
2e2c49
 
2e2c49
@@ -225,23 +226,25 @@ ATF_TC_BODY(isc_rsa_verify, tc) {
2e2c49
 	/* RSAMD5 */
2e2c49
 
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	key->key_alg = DST_ALG_RSAMD5;
2e2c49
+	if (isc_md5_available()) {
2e2c49
+		key->key_alg = DST_ALG_RSAMD5;
2e2c49
 
2e2c49
-	ret = dst_context_create3(key, mctx, DNS_LOGCATEGORY_DNSSEC,
2e2c49
-				  ISC_FALSE, &ctx;;
2e2c49
-	ATF_REQUIRE_EQ(ret, ISC_R_SUCCESS);
2e2c49
+		ret = dst_context_create3(key, mctx, DNS_LOGCATEGORY_DNSSEC,
2e2c49
+					  ISC_FALSE, &ctx;;
2e2c49
+		ATF_REQUIRE_EQ(ret, ISC_R_SUCCESS);
2e2c49
 
2e2c49
-	r.base = d;
2e2c49
-	r.length = 10;
2e2c49
-	ret = dst_context_adddata(ctx, &r);
2e2c49
-	ATF_REQUIRE_EQ(ret, ISC_R_SUCCESS);
2e2c49
+		r.base = d;
2e2c49
+		r.length = 10;
2e2c49
+		ret = dst_context_adddata(ctx, &r);
2e2c49
+		ATF_REQUIRE_EQ(ret, ISC_R_SUCCESS);
2e2c49
 
2e2c49
-	r.base = sigmd5;
2e2c49
-	r.length = 256;
2e2c49
-	ret = dst_context_verify(ctx, &r);
2e2c49
-	ATF_REQUIRE_EQ(ret, ISC_R_SUCCESS);
2e2c49
+		r.base = sigmd5;
2e2c49
+		r.length = 256;
2e2c49
+		ret = dst_context_verify(ctx, &r);
2e2c49
+		ATF_REQUIRE_EQ(ret, ISC_R_SUCCESS);
2e2c49
 
2e2c49
-	dst_context_destroy(&ctx;;
2e2c49
+		dst_context_destroy(&ctx;;
2e2c49
+	}
2e2c49
 #endif
2e2c49
 
2e2c49
 	/* RSASHA256 */
2e2c49
diff --git a/lib/dns/tests/tsig_test.c b/lib/dns/tests/tsig_test.c
2e2c49
index ee025c2387..c403d9954d 100644
2e2c49
--- a/lib/dns/tests/tsig_test.c
2e2c49
+++ b/lib/dns/tests/tsig_test.c
2e2c49
@@ -14,6 +14,7 @@
2e2c49
 #include <config.h>
2e2c49
 #include <atf-c.h>
2e2c49
 
2e2c49
+#include <isc/md5.h>
2e2c49
 #include <isc/mem.h>
2e2c49
 #include <isc/print.h>
2e2c49
 
2e2c49
diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c
2e2c49
index d9f68e50b1..a8edde47b5 100644
2e2c49
--- a/lib/dns/tkey.c
2e2c49
+++ b/lib/dns/tkey.c
2e2c49
@@ -242,6 +242,9 @@ compute_secret(isc_buffer_t *shared, isc_region_t *queryrandomness,
2e2c49
 	unsigned char digests[32];
2e2c49
 	unsigned int i;
2e2c49
 
2e2c49
+	if (isc_md5_available() == ISC_FALSE)
2e2c49
+		return (ISC_R_NOTIMPLEMENTED);
2e2c49
+
2e2c49
 	isc_buffer_usedregion(shared, &r);
2e2c49
 
2e2c49
 	/*
2e2c49
@@ -318,6 +321,12 @@ process_dhtkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name,
2e2c49
 	}
2e2c49
 
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
+	if (isc_md5_available() == ISC_FALSE) {
2e2c49
+		tkey_log("process_dhtkey: MD5 was disabled");
2e2c49
+		tkeyout->error = dns_tsigerror_badalg;
2e2c49
+		return (ISC_R_SUCCESS);
2e2c49
+	}
2e2c49
+
2e2c49
 	if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_HMACMD5_NAME)) {
2e2c49
 		tkey_log("process_dhtkey: algorithms other than "
2e2c49
 			 "hmac-md5 are not supported");
2e2c49
diff --git a/lib/dns/tsec.c b/lib/dns/tsec.c
2e2c49
index a367291f23..37baad7437 100644
2e2c49
--- a/lib/dns/tsec.c
2e2c49
+++ b/lib/dns/tsec.c
2e2c49
@@ -11,6 +11,7 @@
2e2c49
 
2e2c49
 #include <config.h>
2e2c49
 
2e2c49
+#include <isc/md5.h>
2e2c49
 #include <isc/mem.h>
2e2c49
 #include <isc/util.h>
2e2c49
 
2e2c49
@@ -63,7 +64,12 @@ dns_tsec_create(isc_mem_t *mctx, dns_tsectype_t type, dst_key_t *key,
2e2c49
 		switch (dst_key_alg(key)) {
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
 		case DST_ALG_HMACMD5:
2e2c49
-			algname = dns_tsig_hmacmd5_name;
2e2c49
+			if (isc_md5_available()) {
2e2c49
+				algname = dns_tsig_hmacmd5_name;
2e2c49
+			} else {
2e2c49
+				isc_mem_put(mctx, tsec, sizeof(*tsec));
2e2c49
+				return (DNS_R_BADALG);
2e2c49
+			}
2e2c49
 			break;
2e2c49
 #endif
2e2c49
 		case DST_ALG_HMACSHA1:
2e2c49
diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c
2e2c49
index bdcc581bc3..70805bb709 100644
2e2c49
--- a/lib/dns/tsig.c
2e2c49
+++ b/lib/dns/tsig.c
2e2c49
@@ -270,7 +270,8 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
2e2c49
 	(void)dns_name_downcase(&tkey->name, &tkey->name, NULL);
2e2c49
 
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) {
2e2c49
+	if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME) &&
2e2c49
+	    isc_md5_available()) {
2e2c49
 		tkey->algorithm = DNS_TSIG_HMACMD5_NAME;
2e2c49
 		if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACMD5) {
2e2c49
 			ret = DNS_R_BADALG;
2e2c49
@@ -496,7 +497,8 @@ destroyring(dns_tsig_keyring_t *ring) {
2e2c49
 static unsigned int
2e2c49
 dst_alg_fromname(dns_name_t *algorithm) {
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) {
2e2c49
+	if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME) &&
2e2c49
+	    isc_md5_available()) {
2e2c49
 		return (DST_ALG_HMACMD5);
2e2c49
 	} else
2e2c49
 #endif
2e2c49
@@ -680,7 +682,8 @@ dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
2e2c49
 		REQUIRE(secret != NULL);
2e2c49
 
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) {
2e2c49
+	if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME) &&
2e2c49
+	    isc_md5_available()) {
2e2c49
 		if (secret != NULL) {
2e2c49
 			isc_buffer_t b;
2e2c49
 
2e2c49
@@ -1280,7 +1283,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
2e2c49
 		return (ret);
2e2c49
 	if (
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	    alg == DST_ALG_HMACMD5 ||
2e2c49
+	    (alg == DST_ALG_HMACMD5 && isc_md5_available()) ||
2e2c49
 #endif
2e2c49
 	    alg == DST_ALG_HMACSHA1 ||
2e2c49
 	    alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 ||
2e2c49
@@ -1449,7 +1452,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
2e2c49
 
2e2c49
 	if (
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	    alg == DST_ALG_HMACMD5 ||
2e2c49
+	    (alg == DST_ALG_HMACMD5 && isc_md5_available()) ||
2e2c49
 #endif
2e2c49
 	    alg == DST_ALG_HMACSHA1 ||
2e2c49
 	    alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 ||
2e2c49
@@ -1590,7 +1593,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
2e2c49
 			goto cleanup_querystruct;
2e2c49
 		if (
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-			alg == DST_ALG_HMACMD5 ||
2e2c49
+			(alg == DST_ALG_HMACMD5 && isc_md5_available()) ||
2e2c49
 #endif
2e2c49
 			alg == DST_ALG_HMACSHA1 ||
2e2c49
 			alg == DST_ALG_HMACSHA224 ||
2e2c49
@@ -1769,7 +1772,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
2e2c49
 			goto cleanup_context;
2e2c49
 		if (
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-			alg == DST_ALG_HMACMD5 ||
2e2c49
+			(alg == DST_ALG_HMACMD5 && isc_md5_available()) ||
2e2c49
 #endif
2e2c49
 			alg == DST_ALG_HMACSHA1 ||
2e2c49
 			alg == DST_ALG_HMACSHA224 ||
2e2c49
diff --git a/lib/isc/include/isc/md5.h b/lib/isc/include/isc/md5.h
2e2c49
index e5f46dd9c7..9d11f9f8b6 100644
2e2c49
--- a/lib/isc/include/isc/md5.h
2e2c49
+++ b/lib/isc/include/isc/md5.h
2e2c49
@@ -89,6 +89,9 @@ isc_md5_final(isc_md5_t *ctx, unsigned char *digest);
2e2c49
 isc_boolean_t
2e2c49
 isc_md5_check(isc_boolean_t testing);
2e2c49
 
2e2c49
+isc_boolean_t
2e2c49
+isc_md5_available(void);
2e2c49
+
2e2c49
 ISC_LANG_ENDDECLS
2e2c49
 
2e2c49
 #endif /* !PK11_MD5_DISABLE */
2e2c49
diff --git a/lib/isc/md5.c b/lib/isc/md5.c
2e2c49
index 740d863b1b..aefd16478f 100644
2e2c49
--- a/lib/isc/md5.c
2e2c49
+++ b/lib/isc/md5.c
2e2c49
@@ -35,6 +35,7 @@
2e2c49
 
2e2c49
 #include <isc/assertions.h>
2e2c49
 #include <isc/md5.h>
2e2c49
+#include <isc/once.h>
2e2c49
 #include <isc/platform.h>
2e2c49
 #include <isc/safe.h>
2e2c49
 #include <isc/string.h>
2e2c49
@@ -53,6 +54,9 @@
2e2c49
 #define EVP_MD_CTX_free(ptr) EVP_MD_CTX_cleanup(ptr)
2e2c49
 #endif
2e2c49
 
2e2c49
+static isc_once_t available_once = ISC_ONCE_INIT;
2e2c49
+static isc_boolean_t available = ISC_FALSE;
2e2c49
+
2e2c49
 void
2e2c49
 isc_md5_init(isc_md5_t *ctx) {
2e2c49
 	ctx->ctx = EVP_MD_CTX_new();
2e2c49
@@ -84,8 +88,33 @@ isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
2e2c49
 	ctx->ctx = NULL;
2e2c49
 }
2e2c49
 
2e2c49
+static void
2e2c49
+do_detect_available() {
2e2c49
+	isc_md5_t local;
2e2c49
+	isc_md5_t *ctx = &local;
2e2c49
+	unsigned char digest[ISC_MD5_DIGESTLENGTH];
2e2c49
+
2e2c49
+	ctx->ctx = EVP_MD_CTX_new();
2e2c49
+	RUNTIME_CHECK(ctx->ctx != NULL);
2e2c49
+	available = ISC_TF(EVP_DigestInit(ctx->ctx, EVP_md5()) == 1);
2e2c49
+	if (available)
2e2c49
+		(void)EVP_DigestFinal(ctx->ctx, digest, NULL);
2e2c49
+	EVP_MD_CTX_free(ctx->ctx);
2e2c49
+	ctx->ctx = NULL;
2e2c49
+}
2e2c49
+
2e2c49
+isc_boolean_t
2e2c49
+isc_md5_available() {
2e2c49
+	RUNTIME_CHECK(isc_once_do(&available_once, do_detect_available)
2e2c49
+		      == ISC_R_SUCCESS);
2e2c49
+	return available;
2e2c49
+}
2e2c49
+
2e2c49
 #elif PKCS11CRYPTO
2e2c49
 
2e2c49
+static isc_once_t available_once = ISC_ONCE_INIT;
2e2c49
+static isc_boolean_t available = ISC_FALSE;
2e2c49
+
2e2c49
 void
2e2c49
 isc_md5_init(isc_md5_t *ctx) {
2e2c49
 	CK_RV rv;
2e2c49
@@ -128,6 +157,31 @@ isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
2e2c49
 	pk11_return_session(ctx);
2e2c49
 }
2e2c49
 
2e2c49
+static void
2e2c49
+do_detect_available() {
2e2c49
+	isc_md5_t local;
2e2c49
+	isc_md5_t *ctx = &local;
2e2c49
+	CK_RV rv;
2e2c49
+	CK_MECHANISM mech = { CKM_MD5, NULL, 0 };
2e2c49
+
2e2c49
+	if (pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
2e2c49
+				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS)
2e2c49
+	{
2e2c49
+		rv = pkcs_C_DigestInit(ctx->session, &mech);
2e2c49
+		isc_md5_invalidate(ctx);
2e2c49
+		available = (ISC_TF(rv == CKR_OK));
2e2c49
+	} else {
2e2c49
+		available = ISC_FALSE;
2e2c49
+	}
2e2c49
+}
2e2c49
+
2e2c49
+isc_boolean_t
2e2c49
+isc_md5_available() {
2e2c49
+	RUNTIME_CHECK(isc_once_do(&available_once, do_detect_available)
2e2c49
+		      == ISC_R_SUCCESS);
2e2c49
+	return available;
2e2c49
+}
2e2c49
+
2e2c49
 #else
2e2c49
 
2e2c49
 static void
2e2c49
@@ -337,6 +391,11 @@ isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
2e2c49
 	memmove(digest, ctx->buf, 16);
2e2c49
 	isc_safe_memwipe(ctx, sizeof(*ctx));	/* In case it's sensitive */
2e2c49
 }
2e2c49
+
2e2c49
+isc_boolean_t
2e2c49
+isc_md5_available() {
2e2c49
+	return ISC_TRUE;
2e2c49
+}
2e2c49
 #endif
2e2c49
 
2e2c49
 /*
2e2c49
diff --git a/lib/isc/pk11.c b/lib/isc/pk11.c
2e2c49
index fc75a46154..48e1031974 100644
2e2c49
--- a/lib/isc/pk11.c
2e2c49
+++ b/lib/isc/pk11.c
2e2c49
@@ -191,13 +191,12 @@ pk11_initialize(isc_mem_t *mctx, const char *engine) {
2e2c49
 	LOCK(&alloclock);
2e2c49
 	if ((mctx != NULL) && (pk11_mctx == NULL) && (allocsize == 0))
2e2c49
 		isc_mem_attach(mctx, &pk11_mctx);
2e2c49
+	UNLOCK(&alloclock);
2e2c49
+
2e2c49
+	LOCK(&sessionlock);
2e2c49
 	if (initialized) {
2e2c49
-		UNLOCK(&alloclock);
2e2c49
-		return (ISC_R_SUCCESS);
2e2c49
-	} else {
2e2c49
-		LOCK(&sessionlock);
2e2c49
-		initialized = ISC_TRUE;
2e2c49
-		UNLOCK(&alloclock);
2e2c49
+		result = ISC_R_SUCCESS;
2e2c49
+		goto unlock;
2e2c49
 	}
2e2c49
 
2e2c49
 	ISC_LIST_INIT(tokens);
2e2c49
@@ -237,6 +236,7 @@ pk11_initialize(isc_mem_t *mctx, const char *engine) {
2e2c49
 	}
2e2c49
 #endif
2e2c49
 #endif /* PKCS11CRYPTO */
2e2c49
+	initialized = ISC_TRUE;
2e2c49
 	result = ISC_R_SUCCESS;
2e2c49
  unlock:
2e2c49
 	UNLOCK(&sessionlock);
2e2c49
@@ -273,9 +273,14 @@ pk11_finalize(void) {
2e2c49
 		pk11_mem_put(token, sizeof(*token));
2e2c49
 		token = next;
2e2c49
 	}
2e2c49
+	LOCK(&alloclock);
2e2c49
 	if (pk11_mctx != NULL)
2e2c49
 		isc_mem_detach(&pk11_mctx);
2e2c49
+	UNLOCK(&alloclock);
2e2c49
+
2e2c49
+	LOCK(&sessionlock);
2e2c49
 	initialized = ISC_FALSE;
2e2c49
+	UNLOCK(&sessionlock);
2e2c49
 	return (ret);
2e2c49
 }
2e2c49
 
2e2c49
@@ -589,6 +594,8 @@ scan_slots(void) {
2e2c49
 	pk11_token_t *token;
2e2c49
 	unsigned int i;
2e2c49
 	isc_boolean_t bad;
2e2c49
+	unsigned int best_rsa_algorithms = 0;
2e2c49
+	unsigned int best_digest_algorithms = 0;
2e2c49
 
2e2c49
 	slotCount = 0;
2e2c49
 	PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, NULL_PTR, &slotCount));
2e2c49
@@ -601,6 +608,8 @@ scan_slots(void) {
2e2c49
 	PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, slotList, &slotCount));
2e2c49
 
2e2c49
 	for (i = 0; i < slotCount; i++) {
2e2c49
+		unsigned int rsa_algorithms = 0;
2e2c49
+		unsigned int digest_algorithms = 0;
2e2c49
 		slot = slotList[i];
2e2c49
 		PK11_TRACE2("slot#%u=0x%lx\n", i, slot);
2e2c49
 
2e2c49
@@ -640,11 +649,12 @@ scan_slots(void) {
2e2c49
 		if ((rv != CKR_OK) ||
2e2c49
 		    ((mechInfo.flags & CKF_SIGN) == 0) ||
2e2c49
 		    ((mechInfo.flags & CKF_VERIFY) == 0)) {
2e2c49
-#if !defined(PK11_MD5_DISABLE) && !defined(PK11_RSA_PKCS_REPLACE)
2e2c49
-			bad = ISC_TRUE;
2e2c49
-#endif
2e2c49
 			PK11_TRACEM(CKM_MD5_RSA_PKCS);
2e2c49
 		}
2e2c49
+#if !defined(PK11_MD5_DISABLE) && !defined(PK11_RSA_PKCS_REPLACE)
2e2c49
+		else
2e2c49
+			++rsa_algorithms;
2e2c49
+#endif
2e2c49
 		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA1_RSA_PKCS,
2e2c49
 					     &mechInfo);
2e2c49
 		if ((rv != CKR_OK) ||
2e2c49
@@ -687,8 +697,14 @@ scan_slots(void) {
2e2c49
 		if (bad)
2e2c49
 			goto try_dsa;
2e2c49
 		token->operations |= 1 << OP_RSA;
2e2c49
-		if (best_rsa_token == NULL)
2e2c49
+		if (best_rsa_token == NULL) {
2e2c49
+			best_rsa_token = token;
2e2c49
+			best_rsa_algorithms = rsa_algorithms;
2e2c49
+		} else if (rsa_algorithms > best_rsa_algorithms) {
2e2c49
+			pk11_mem_put(best_rsa_token, sizeof(*best_rsa_token));
2e2c49
 			best_rsa_token = token;
2e2c49
+			best_rsa_algorithms = rsa_algorithms;
2e2c49
+		}
2e2c49
 
2e2c49
 	try_dsa:
2e2c49
 		bad = ISC_FALSE;
2e2c49
@@ -756,11 +772,12 @@ scan_slots(void) {
2e2c49
 		bad = ISC_FALSE;
2e2c49
 		rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5, &mechInfo);
2e2c49
 		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
2e2c49
-#ifndef PK11_MD5_DISABLE
2e2c49
-			bad = ISC_TRUE;
2e2c49
-#endif
2e2c49
 			PK11_TRACEM(CKM_MD5);
2e2c49
 		}
2e2c49
+#ifndef PK11_MD5_DISABLE
2e2c49
+		else
2e2c49
+			++digest_algorithms;
2e2c49
+#endif
2e2c49
 		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA_1, &mechInfo);
2e2c49
 		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
2e2c49
 			bad = ISC_TRUE;
2e2c49
@@ -788,11 +805,12 @@ scan_slots(void) {
2e2c49
 		}
2e2c49
 		rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5_HMAC, &mechInfo);
2e2c49
 		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) {
2e2c49
-#if !defined(PK11_MD5_DISABLE) && !defined(PK11_MD5_HMAC_REPLACE)
2e2c49
-			bad = ISC_TRUE;
2e2c49
-#endif
2e2c49
 			PK11_TRACEM(CKM_MD5_HMAC);
2e2c49
 		}
2e2c49
+#if !defined(PK11_MD5_DISABLE) && !defined(PK11_MD5_HMAC_REPLACE)
2e2c49
+		else
2e2c49
+			++digest_algorithms;
2e2c49
+#endif
2e2c49
 		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA_1_HMAC, &mechInfo);
2e2c49
 		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) {
2e2c49
 #ifndef PK11_SHA_1_HMAC_REPLACE
2e2c49
@@ -830,8 +848,14 @@ scan_slots(void) {
2e2c49
 		}
2e2c49
 		if (!bad) {
2e2c49
 			token->operations |= 1 << OP_DIGEST;
2e2c49
-			if (digest_token == NULL)
2e2c49
+			if (digest_token == NULL) {
2e2c49
+				digest_token = token;
2e2c49
+				best_digest_algorithms = digest_algorithms;
2e2c49
+			} else if (digest_algorithms > best_digest_algorithms) {
2e2c49
+				pk11_mem_put(digest_token, sizeof(*digest_token));
2e2c49
 				digest_token = token;
2e2c49
+				best_digest_algorithms = digest_algorithms;
2e2c49
+			}
2e2c49
 		}
2e2c49
 
2e2c49
 		/* ECDSA requires digest */
2e2c49
diff --git a/lib/isc/tests/hash_test.c b/lib/isc/tests/hash_test.c
2e2c49
index 18759903be..6bc45b1ad3 100644
2e2c49
--- a/lib/isc/tests/hash_test.c
2e2c49
+++ b/lib/isc/tests/hash_test.c
2e2c49
@@ -2008,7 +2008,8 @@ ATF_TP_ADD_TCS(tp) {
2e2c49
 	 * various cryptographic hashes.
2e2c49
 	 */
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	ATF_TP_ADD_TC(tp, md5_check);
2e2c49
+	if (isc_md5_available())
2e2c49
+		ATF_TP_ADD_TC(tp, md5_check);
2e2c49
 #endif
2e2c49
 	ATF_TP_ADD_TC(tp, sha1_check);
2e2c49
 
2e2c49
@@ -2016,7 +2017,8 @@ ATF_TP_ADD_TCS(tp) {
2e2c49
 	ATF_TP_ADD_TC(tp, isc_hash_function_reverse);
2e2c49
 	ATF_TP_ADD_TC(tp, isc_hash_initializer);
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	ATF_TP_ADD_TC(tp, isc_hmacmd5);
2e2c49
+	if (isc_md5_available())
2e2c49
+		ATF_TP_ADD_TC(tp, isc_hmacmd5);
2e2c49
 #endif
2e2c49
 	ATF_TP_ADD_TC(tp, isc_hmacsha1);
2e2c49
 	ATF_TP_ADD_TC(tp, isc_hmacsha224);
2e2c49
@@ -2024,7 +2026,8 @@ ATF_TP_ADD_TCS(tp) {
2e2c49
 	ATF_TP_ADD_TC(tp, isc_hmacsha384);
2e2c49
 	ATF_TP_ADD_TC(tp, isc_hmacsha512);
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	ATF_TP_ADD_TC(tp, isc_md5);
2e2c49
+	if (isc_md5_available())
2e2c49
+		ATF_TP_ADD_TC(tp, isc_md5);
2e2c49
 #endif
2e2c49
 	ATF_TP_ADD_TC(tp, isc_sha1);
2e2c49
 	ATF_TP_ADD_TC(tp, isc_sha224);
2e2c49
diff --git a/lib/isccc/cc.c b/lib/isccc/cc.c
2e2c49
index 7225ab4a37..42b30466be 100644
2e2c49
--- a/lib/isccc/cc.c
2e2c49
+++ b/lib/isccc/cc.c
2e2c49
@@ -270,11 +270,15 @@ sign(unsigned char *data, unsigned int length, unsigned char *hmac,
2e2c49
 	switch (algorithm) {
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
 	case ISCCC_ALG_HMACMD5:
2e2c49
-		isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
2e2c49
-				 REGION_SIZE(*secret));
2e2c49
-		isc_hmacmd5_update(&ctx.hmd5, data, length);
2e2c49
-		isc_hmacmd5_sign(&ctx.hmd5, digest);
2e2c49
-		source.rend = digest + ISC_MD5_DIGESTLENGTH;
2e2c49
+		if (isc_md5_available()) {
2e2c49
+			isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
2e2c49
+					 REGION_SIZE(*secret));
2e2c49
+			isc_hmacmd5_update(&ctx.hmd5, data, length);
2e2c49
+			isc_hmacmd5_sign(&ctx.hmd5, digest);
2e2c49
+			source.rend = digest + ISC_MD5_DIGESTLENGTH;
2e2c49
+		} else {
2e2c49
+			return (ISC_R_FAILURE);
2e2c49
+		}
2e2c49
 		break;
2e2c49
 #endif
2e2c49
 
2e2c49
@@ -348,14 +352,18 @@ isccc_cc_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer,
2e2c49
 {
2e2c49
 	unsigned int hmac_base, signed_base;
2e2c49
 	isc_result_t result;
2e2c49
+	const isc_boolean_t md5 = ISC_TF(algorithm == ISCCC_ALG_HMACMD5);
2e2c49
 
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
+	if (md5 && isc_md5_available() == ISC_FALSE)
2e2c49
+		return (ISC_R_NOTIMPLEMENTED);
2e2c49
+
2e2c49
 	result = isc_buffer_reserve(buffer,
2e2c49
-				    4 + ((algorithm == ISCCC_ALG_HMACMD5) ?
2e2c49
+				    4 + ((md5) ?
2e2c49
 					 sizeof(auth_hmd5) :
2e2c49
 					 sizeof(auth_hsha)));
2e2c49
 #else
2e2c49
-	if (algorithm == ISCCC_ALG_HMACMD5)
2e2c49
+	if (md5)
2e2c49
 		return (ISC_R_NOTIMPLEMENTED);
2e2c49
 	result = isc_buffer_reserve(buffer, 4 + sizeof(auth_hsha));
2e2c49
 #endif
2e2c49
@@ -374,7 +382,7 @@ isccc_cc_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer,
2e2c49
 		 * we know what it is.
2e2c49
 		 */
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-		if (algorithm == ISCCC_ALG_HMACMD5) {
2e2c49
+		if (md5) {
2e2c49
 			hmac_base = (*buffer)->used + HMD5_OFFSET;
2e2c49
 			isc_buffer_putmem(*buffer,
2e2c49
 					  auth_hmd5, sizeof(auth_hmd5));
2e2c49
@@ -440,7 +448,7 @@ verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length,
2e2c49
 	if (!isccc_alist_alistp(_auth))
2e2c49
 		return (ISC_R_FAILURE);
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
-	if (algorithm == ISCCC_ALG_HMACMD5)
2e2c49
+	if (algorithm == ISCCC_ALG_HMACMD5 && isc_md5_available())
2e2c49
 		hmac = isccc_alist_lookup(_auth, "hmd5");
2e2c49
 	else
2e2c49
 #endif
2e2c49
@@ -455,12 +463,16 @@ verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length,
2e2c49
 	switch (algorithm) {
2e2c49
 #ifndef PK11_MD5_DISABLE
2e2c49
 	case ISCCC_ALG_HMACMD5:
2e2c49
-		isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
2e2c49
-				 REGION_SIZE(*secret));
2e2c49
-		isc_hmacmd5_update(&ctx.hmd5, data, length);
2e2c49
-		isc_hmacmd5_sign(&ctx.hmd5, digest);
2e2c49
-		source.rend = digest + ISC_MD5_DIGESTLENGTH;
2e2c49
-		break;
2e2c49
+		if (isc_md5_available()) {
2e2c49
+			isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
2e2c49
+					 REGION_SIZE(*secret));
2e2c49
+			isc_hmacmd5_update(&ctx.hmd5, data, length);
2e2c49
+			isc_hmacmd5_sign(&ctx.hmd5, digest);
2e2c49
+			source.rend = digest + ISC_MD5_DIGESTLENGTH;
2e2c49
+			break;
2e2c49
+		} else {
2e2c49
+			return (ISC_R_FAILURE);
2e2c49
+		}
2e2c49
 #endif
2e2c49
 
2e2c49
 	case ISCCC_ALG_HMACSHA1:
2e2c49
-- 
2e2c49
2.14.4
2e2c49