2c0af7
From 5f9236521f5add49669a97875b7d26cf35b28963 Mon Sep 17 00:00:00 2001
2c0af7
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
2c0af7
Date: Fri, 22 Jun 2018 14:05:18 +0200
2c0af7
Subject: [PATCH 1/2] Squashed commit of the following:
2c0af7
MIME-Version: 1.0
2c0af7
Content-Type: text/plain; charset=UTF-8
2c0af7
Content-Transfer-Encoding: 8bit
2c0af7
2c0af7
commit 3fd542379fa381b54381e07d6625ce53f9f9b1f0
2c0af7
Author: Petr Menšík <pemensik@redhat.com>
2c0af7
Date:   Thu Jun 21 12:00:35 2018 +0200
2c0af7
2c0af7
    Revert "4450.   [port]          Provide more nuanced HSM support which better matches"
2c0af7
2c0af7
    This reverts commit f3b4d031c1f714ff6e862670663aa5a18650951e.
2c0af7
2c0af7
    Revert PK11_MD5_DISABLED also from remaining files. Keep documentation
2c0af7
    changes.
2c0af7
2c0af7
commit f90934f734796595135cdd7a5008555a615dfe8e
2c0af7
Author: Petr Menšík <pemensik@redhat.com>
2c0af7
Date:   Wed Jun 20 19:31:19 2018 +0200
2c0af7
2c0af7
    Fix rndc-confgen default algorithm, report true algorithm in usage.
2c0af7
2c0af7
commit dd53212c12c6943a21a3c24d60995edd19e1d9f7
2c0af7
Author: Petr Menšík <pemensik@redhat.com>
2c0af7
Date:   Fri Feb 23 21:21:30 2018 +0100
2c0af7
2c0af7
    Cleanup only if initialization was successful
2c0af7
2c0af7
commit f163ea51c46bb22bf264a1ac983e2027e43845fa
2c0af7
Author: Petr Menšík <pemensik@redhat.com>
2c0af7
Date:   Mon Feb 5 12:19:28 2018 +0100
2c0af7
2c0af7
    Ensure dst backend is initialized first even before hmac algorithms.
2c0af7
2c0af7
commit 58751b60bd39168b7c8f817ede70473842432081
2c0af7
Author: Petr Menšík <pemensik@redhat.com>
2c0af7
Date:   Mon Feb 5 12:17:54 2018 +0100
2c0af7
2c0af7
    Skip initialization of MD5 based algorithms if not available.
2c0af7
2c0af7
commit 0572b98430d3c80f4a0b0c592b1e3bf7fde9b768
2c0af7
Author: Petr Menšík <pemensik@redhat.com>
2c0af7
Date:   Mon Feb 5 10:21:27 2018 +0100
2c0af7
2c0af7
    Change secalgs skipping to be more safe
2c0af7
2c0af7
commit 994f497a032930fce1370d507a265fbb293c66f4
2c0af7
Author: Petr Menšík <pemensik@redhat.com>
2c0af7
Date:   Wed Jan 31 18:26:11 2018 +0100
2c0af7
2c0af7
    Skip MD5 algorithm also in case of NULL name
2c0af7
2c0af7
commit abd82fbd2507c4b8f20e1ade202fd66d224fd646
2c0af7
Author: Petr Menšík <pemensik@redhat.com>
2c0af7
Date:   Wed Jan 31 16:54:29 2018 +0100
2c0af7
2c0af7
    Revert part of commit 1b5c641416eb6de7fc232fc89d31a40a4d439f3d related
2c0af7
    to SHA1.
2c0af7
2c0af7
commit b3c832d53a14a0779f598869bb99685c8e4b2bc0
2c0af7
Author: Petr Menšík <pemensik@redhat.com>
2c0af7
Date:   Wed Jan 31 11:38:12 2018 +0100
2c0af7
2c0af7
    Make MD5 behave like unknown algorithm in TSIG.
2c0af7
2c0af7
commit a64a3d6962ee93d6f8699b29bd6507dba0c244ed
2c0af7
Author: Petr Menšík <pemensik@redhat.com>
2c0af7
Date:   Tue Nov 28 20:14:37 2017 +0100
2c0af7
2c0af7
    Select token with most supported functions, instead of demanding it must support all functions
2c0af7
2c0af7
    Initialize PKCS#11 always until successfully initialized
2c0af7
2c0af7
commit db118c6368668099ea1b6e75860cc12e178afa3b
2c0af7
Author: Petr Menšík <pemensik@redhat.com>
2c0af7
Date:   Mon Jan 22 16:17:44 2018 +0100
2c0af7
2c0af7
    Handle MD5 unavailability from DST
2c0af7
2c0af7
commit 8f8824dca2f5b4d5a3a176d31ac3ee612321c4e3
2c0af7
Author: Petr Menšík <pemensik@redhat.com>
2c0af7
Date:   Mon Jan 22 14:11:16 2018 +0100
2c0af7
2c0af7
    Check runtime flag from library and applications, fail gracefully.
2c0af7
2c0af7
commit bd431384af7dcde8827e670c8749517ad677a967
2c0af7
Author: Petr Menšík <pemensik@redhat.com>
2c0af7
Date:   Mon Jan 22 08:39:08 2018 +0100
2c0af7
2c0af7
    Modify libraries to use isc_md5_available() if PK11_MD5_DISABLE is not
2c0af7
    defined.
2c0af7
    TODO: pk11.c should accept slot without MD5 support.
2c0af7
2c0af7
commit 160b13979ef3d0e92d2dd52d0987a3ec979be6cf
2c0af7
Author: Petr Menšík <pemensik@redhat.com>
2c0af7
Date:   Mon Jan 22 07:21:04 2018 +0100
2c0af7
2c0af7
    Add runtime detection whether MD5 is useable.
2c0af7
2c0af7
commit 23b27ce0f2ad496c331ae40349cc1074a1b11804
2c0af7
Author: Mark Andrews <marka@isc.org>
2c0af7
Date:   Fri Aug 19 08:25:54 2016 +1000
2c0af7
2c0af7
    4450.   [port]          Provide more nuanced HSM support which better matches
2c0af7
                            the specific PKCS11 providers capabilities. [RT #42458]
2c0af7
2c0af7
    (cherry picked from commit 8ee6f289d87851a5b898b24a64587f0e6bc225bc)
2c0af7
2c0af7
Fix compiler warnings
2c0af7
---
2c0af7
 bin/confgen/keygen.c             | 10 +++++-
2c0af7
 bin/confgen/rndc-confgen.c       | 12 ++++---
2c0af7
 bin/confgen/rndc-confgen.docbook |  3 +-
2c0af7
 bin/dig/dig.c                    |  5 ++-
2c0af7
 bin/dig/dig.docbook              |  6 ++--
2c0af7
 bin/dig/dighost.c                | 14 ++++++--
2c0af7
 bin/dnssec/dnssec-keyfromlabel.c |  9 +++++
2c0af7
 bin/dnssec/dnssec-keygen.c       | 19 +++++++++--
2c0af7
 bin/named/config.c               | 23 +++++++++++--
2c0af7
 bin/nsupdate/nsupdate.c          | 20 +++++++----
2c0af7
 bin/nsupdate/nsupdate.docbook    |  9 ++++-
2c0af7
 bin/rndc/rndc.c                  |  3 +-
2c0af7
 bin/tests/hashes/t_hashes.c      | 20 ++++++-----
2c0af7
 lib/bind9/check.c                |  8 +++++
2c0af7
 lib/dns/dst_api.c                | 23 +++++++++----
2c0af7
 lib/dns/dst_internal.h           |  3 +-
2c0af7
 lib/dns/dst_parse.c              | 12 ++++++-
2c0af7
 lib/dns/hmac_link.c              |  2 +-
2c0af7
 lib/dns/opensslrsa_link.c        |  4 +++
2c0af7
 lib/dns/pkcs11rsa_link.c         | 25 ++++++++++++--
2c0af7
 lib/dns/rcode.c                  | 19 +++++++++--
2c0af7
 lib/dns/tests/tsig_test.c        |  1 +
2c0af7
 lib/dns/tkey.c                   |  9 +++++
2c0af7
 lib/dns/tsec.c                   |  8 ++++-
2c0af7
 lib/dns/tsig.c                   | 22 +++++-------
2c0af7
 lib/isc/include/isc/md5.h        |  3 ++
2c0af7
 lib/isc/md5.c                    | 59 ++++++++++++++++++++++++++++++++
2c0af7
 lib/isc/pk11.c                   | 72 +++++++++++++++++++++++++++++++---------
2c0af7
 lib/isccc/cc.c                   | 48 ++++++++++++++++-----------
2c0af7
 29 files changed, 373 insertions(+), 98 deletions(-)
2c0af7
2c0af7
diff --git a/bin/confgen/keygen.c b/bin/confgen/keygen.c
2c0af7
index d0cdafed36..4eb027e723 100644
2c0af7
--- a/bin/confgen/keygen.c
2c0af7
+++ b/bin/confgen/keygen.c
2c0af7
@@ -28,6 +28,7 @@
2c0af7
 #include <isc/entropy.h>
2c0af7
 #include <isc/file.h>
2c0af7
 #include <isc/keyboard.h>
2c0af7
+#include <isc/md5.h>
2c0af7
 #include <isc/mem.h>
2c0af7
 #include <isc/result.h>
2c0af7
 #include <isc/string.h>
2c0af7
@@ -69,7 +70,7 @@ alg_totext(dns_secalg_t alg) {
2c0af7
  */
2c0af7
 dns_secalg_t
2c0af7
 alg_fromtext(const char *name) {
2c0af7
-	if (strcmp(name, "hmac-md5") == 0)
2c0af7
+	if (strcmp(name, "hmac-md5") == 0 && isc_md5_available())
2c0af7
 		return DST_ALG_HMACMD5;
2c0af7
 	if (strcmp(name, "hmac-sha1") == 0)
2c0af7
 		return DST_ALG_HMACSHA1;
2c0af7
@@ -126,6 +127,13 @@ generate_key(isc_mem_t *mctx, const char *randomfile, dns_secalg_t alg,
2c0af7
 
2c0af7
 	switch (alg) {
2c0af7
 	    case DST_ALG_HMACMD5:
2c0af7
+		if (isc_md5_available() == ISC_FALSE) {
2c0af7
+			fatal("unsupported algorithm %d\n", alg);
2c0af7
+		} else if (keysize < 1 || keysize > 512) {
2c0af7
+			fatal("keysize %d out of range (must be 1-512)\n",
2c0af7
+			      keysize);
2c0af7
+		}
2c0af7
+		break;
2c0af7
 	    case DST_ALG_HMACSHA1:
2c0af7
 	    case DST_ALG_HMACSHA224:
2c0af7
 	    case DST_ALG_HMACSHA256:
2c0af7
diff --git a/bin/confgen/rndc-confgen.c b/bin/confgen/rndc-confgen.c
2c0af7
index 3fd54fe2bb..c48a38f094 100644
2c0af7
--- a/bin/confgen/rndc-confgen.c
2c0af7
+++ b/bin/confgen/rndc-confgen.c
2c0af7
@@ -41,6 +41,7 @@
2c0af7
 #include <isc/file.h>
2c0af7
 #include <isc/keyboard.h>
2c0af7
 #include <isc/mem.h>
2c0af7
+#include <isc/md5.h>
2c0af7
 #include <isc/net.h>
2c0af7
 #include <isc/print.h>
2c0af7
 #include <isc/result.h>
2c0af7
@@ -66,7 +67,7 @@ const char *progname;
2c0af7
 
2c0af7
 isc_boolean_t verbose = ISC_FALSE;
2c0af7
 
2c0af7
-const char *keyfile, *keydef;
2c0af7
+const char *keyfile, *keydef, *algdef;
2c0af7
 
2c0af7
 ISC_PLATFORM_NORETURN_PRE static void
2c0af7
 usage(int status) ISC_PLATFORM_NORETURN_POST;
2c0af7
@@ -79,7 +80,7 @@ Usage:\n\
2c0af7
  %s [-a] [-b bits] [-c keyfile] [-k keyname] [-p port] [-r randomfile] \
2c0af7
 [-s addr] [-t chrootdir] [-u user]\n\
2c0af7
   -a:		 generate just the key clause and write it to keyfile (%s)\n\
2c0af7
-  -A alg:	 algorithm (default hmac-md5)\n\
2c0af7
+  -A alg:	 algorithm (default %s)\n\
2c0af7
   -b bits:	 from 1 through 512, default 256; total length of the secret\n\
2c0af7
   -c keyfile:	 specify an alternate key file (requires -a)\n\
2c0af7
   -k keyname:	 the name as it will be used  in named.conf and rndc.conf\n\
2c0af7
@@ -88,7 +89,7 @@ Usage:\n\
2c0af7
   -s addr:	 the address to which rndc should connect\n\
2c0af7
   -t chrootdir:	 write a keyfile in chrootdir as well (requires -a)\n\
2c0af7
   -u user:	 set the keyfile owner to \"user\" (requires -a)\n",
2c0af7
-		 progname, keydef);
2c0af7
+		 progname, keydef, algdef);
2c0af7
 
2c0af7
 	exit (status);
2c0af7
 }
2c0af7
@@ -124,9 +125,12 @@ main(int argc, char **argv) {
2c0af7
 	progname = program;
2c0af7
 
2c0af7
 	keyname = DEFAULT_KEYNAME;
2c0af7
-	alg = DST_ALG_HMACMD5;
2c0af7
 	serveraddr = DEFAULT_SERVER;
2c0af7
 	port = DEFAULT_PORT;
2c0af7
+	alg = DST_ALG_HMACSHA256;
2c0af7
+	if (isc_md5_available())
2c0af7
+		alg = DST_ALG_HMACMD5;
2c0af7
+	algdef = alg_totext(alg);
2c0af7
 
2c0af7
 	isc_commandline_errprint = ISC_FALSE;
2c0af7
 
2c0af7
diff --git a/bin/confgen/rndc-confgen.docbook b/bin/confgen/rndc-confgen.docbook
2c0af7
index f367b94aae..add8d7357f 100644
2c0af7
--- a/bin/confgen/rndc-confgen.docbook
2c0af7
+++ b/bin/confgen/rndc-confgen.docbook
2c0af7
@@ -136,7 +136,8 @@
2c0af7
           <para>
2c0af7
             Specifies the algorithm to use for the TSIG key.  Available
2c0af7
             choices are: hmac-md5, hmac-sha1, hmac-sha224, hmac-sha256,
2c0af7
-            hmac-sha384 and hmac-sha512.  The default is hmac-md5.
2c0af7
+            hmac-sha384 and hmac-sha512.  The default is hmac-md5 or
2c0af7
+            if MD5 was disabled hmac-sha256.
2c0af7
           </para>
2c0af7
         </listitem>
2c0af7
       </varlistentry>
2c0af7
diff --git a/bin/dig/dig.c b/bin/dig/dig.c
2c0af7
index 634ccfbfbf..4db0e6430f 100644
2c0af7
--- a/bin/dig/dig.c
2c0af7
+++ b/bin/dig/dig.c
2c0af7
@@ -25,6 +25,7 @@
2c0af7
 #include <ctype.h>
2c0af7
 
2c0af7
 #include <isc/app.h>
2c0af7
+#include <isc/md5.h>
2c0af7
 #include <isc/netaddr.h>
2c0af7
 #include <isc/parseint.h>
2c0af7
 #include <isc/print.h>
2c0af7
@@ -1426,7 +1427,9 @@ dash_option(char *option, char *next, dig_lookup_t **lookup,
2c0af7
 			ptr = ptr2;
2c0af7
 			ptr2 = ptr3;
2c0af7
 		} else  {
2c0af7
-			hmacname = DNS_TSIG_HMACMD5_NAME;
2c0af7
+			hmacname = DNS_TSIG_HMACSHA256_NAME;
2c0af7
+			if (isc_md5_available())
2c0af7
+				hmacname = DNS_TSIG_HMACMD5_NAME;
2c0af7
 			digestbits = 0;
2c0af7
 		}
2c0af7
 		strncpy(keynametext, ptr, sizeof(keynametext));
2c0af7
diff --git a/bin/dig/dig.docbook b/bin/dig/dig.docbook
2c0af7
index 028f0fcd73..6ee5bd90bc 100644
2c0af7
--- a/bin/dig/dig.docbook
2c0af7
+++ b/bin/dig/dig.docbook
2c0af7
@@ -309,9 +309,11 @@
2c0af7
       responses using transaction signatures (TSIG), specify a TSIG key file
2c0af7
       using the <option>-k</option> option.  You can also specify the TSIG
2c0af7
       key itself on the command line using the <option>-y</option> option;
2c0af7
-      <parameter>hmac</parameter> is the type of the TSIG, default HMAC-MD5,
2c0af7
+      <parameter>hmac</parameter> is the type of the TSIG,
2c0af7
       <parameter>name</parameter> is the name of the TSIG key and
2c0af7
-      <parameter>key</parameter> is the actual key.  The key is a
2c0af7
+      <parameter>key</parameter> is the actual key. If <parameter>hmac</parameter>
2c0af7
+      is not specified, the default is <literal>hmac-md5</literal>
2c0af7
+      or if MD5 was disabled <literal>hmac-sha256</literal>.  The key is a
2c0af7
       base-64
2c0af7
       encoded string, typically generated by
2c0af7
       <citerefentry>
2c0af7
diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c
2c0af7
index 3a066c68c9..3998a81a5d 100644
2c0af7
--- a/bin/dig/dighost.c
2c0af7
+++ b/bin/dig/dighost.c
2c0af7
@@ -81,6 +81,7 @@
2c0af7
 #include <isc/file.h>
2c0af7
 #include <isc/lang.h>
2c0af7
 #include <isc/log.h>
2c0af7
+#include <isc/md5.h>
2c0af7
 #include <isc/netaddr.h>
2c0af7
 #ifdef DIG_SIGCHASE
2c0af7
 #include <isc/netdb.h>
2c0af7
@@ -1025,9 +1026,10 @@ parse_hmac(const char *hmac) {
2c0af7
 
2c0af7
 	digestbits = 0;
2c0af7
 
2c0af7
-	if (strcasecmp(buf, "hmac-md5") == 0) {
2c0af7
+	if (strcasecmp(buf, "hmac-md5") == 0 && isc_md5_available()) {
2c0af7
 		hmacname = DNS_TSIG_HMACMD5_NAME;
2c0af7
-	} else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
2c0af7
+	} else if (strncasecmp(buf, "hmac-md5-", 9) == 0 &&
2c0af7
+		   isc_md5_available()) {
2c0af7
 		hmacname = DNS_TSIG_HMACMD5_NAME;
2c0af7
 		digestbits = parse_bits(&buf[9], "digest-bits [0..128]", 128);
2c0af7
 	} else if (strcasecmp(buf, "hmac-sha1") == 0) {
2c0af7
@@ -1145,7 +1147,13 @@ setup_file_key(void) {
2c0af7
 
2c0af7
 	switch (dst_key_alg(dstkey)) {
2c0af7
 	case DST_ALG_HMACMD5:
2c0af7
-		hmacname = DNS_TSIG_HMACMD5_NAME;
2c0af7
+		if (isc_md5_available()) {
2c0af7
+			hmacname = DNS_TSIG_HMACMD5_NAME;
2c0af7
+		} else {
2c0af7
+			printf(";; Couldn't create key %s: bad algorithm\n",
2c0af7
+			       keynametext);
2c0af7
+			goto failure;
2c0af7
+		}
2c0af7
 		break;
2c0af7
 	case DST_ALG_HMACSHA1:
2c0af7
 		hmacname = DNS_TSIG_HMACSHA1_NAME;
2c0af7
diff --git a/bin/dnssec/dnssec-keyfromlabel.c b/bin/dnssec/dnssec-keyfromlabel.c
2c0af7
index cc212e1ed1..a5854a1f4c 100644
2c0af7
--- a/bin/dnssec/dnssec-keyfromlabel.c
2c0af7
+++ b/bin/dnssec/dnssec-keyfromlabel.c
2c0af7
@@ -27,6 +27,7 @@
2c0af7
 #include <isc/commandline.h>
2c0af7
 #include <isc/entropy.h>
2c0af7
 #include <isc/mem.h>
2c0af7
+#include <isc/md5.h>
2c0af7
 #include <isc/region.h>
2c0af7
 #include <isc/print.h>
2c0af7
 #include <isc/string.h>
2c0af7
@@ -379,6 +380,11 @@ main(int argc, char **argv) {
2c0af7
 		if (freeit != NULL)
2c0af7
 			free(freeit);
2c0af7
 		return (1);
2c0af7
+	} else if (strcasecmp(algname, "RSAMD5") == 0 && isc_md5_available() == ISC_FALSE) {
2c0af7
+		fprintf(stderr, "The use of RSAMD5 was disabled\n");
2c0af7
+		if (freeit != NULL)
2c0af7
+			free(freeit);
2c0af7
+		return (1);
2c0af7
 	} else {
2c0af7
 		r.base = algname;
2c0af7
 		r.length = strlen(algname);
2c0af7
@@ -412,6 +418,9 @@ main(int argc, char **argv) {
2c0af7
 			fatal("invalid type %s", type);
2c0af7
 	}
2c0af7
 
2c0af7
+	if (alg == DST_ALG_RSAMD5 && isc_md5_available() == ISC_FALSE)
2c0af7
+		fatal("Key uses disabled RSAMD5");
2c0af7
+
2c0af7
 	if (nametype == NULL) {
2c0af7
 		if ((options & DST_TYPE_KEY) != 0) /* KEY */
2c0af7
 			fatal("no nametype specified");
2c0af7
diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c
2c0af7
index 97b96ee1dc..c147bb4e6c 100644
2c0af7
--- a/bin/dnssec/dnssec-keygen.c
2c0af7
+++ b/bin/dnssec/dnssec-keygen.c
2c0af7
@@ -42,6 +42,7 @@
2c0af7
 #include <isc/buffer.h>
2c0af7
 #include <isc/commandline.h>
2c0af7
 #include <isc/entropy.h>
2c0af7
+#include <isc/md5.h>
2c0af7
 #include <isc/mem.h>
2c0af7
 #include <isc/region.h>
2c0af7
 #include <isc/string.h>
2c0af7
@@ -548,9 +549,21 @@ main(int argc, char **argv) {
2c0af7
 					"\"-a RSAMD5\"\n");
2c0af7
 			INSIST(freeit == NULL);
2c0af7
 			return (1);
2c0af7
-		} else if (strcasecmp(algname, "HMAC-MD5") == 0)
2c0af7
-			alg = DST_ALG_HMACMD5;
2c0af7
-		else if (strcasecmp(algname, "HMAC-SHA1") == 0)
2c0af7
+		} else if (strcasecmp(algname, "HMAC-MD5") == 0) {
2c0af7
+			if (isc_md5_available()) {
2c0af7
+				alg = DST_ALG_HMACMD5;
2c0af7
+			} else {
2c0af7
+				fprintf(stderr,
2c0af7
+					"The use of HMAC-MD5 was disabled\n");
2c0af7
+				INSIST(freeit == NULL);
2c0af7
+				return (1);
2c0af7
+			}
2c0af7
+		} else if (strcasecmp(algname, "RSAMD5") == 0 &&
2c0af7
+			   isc_md5_available() == ISC_FALSE) {
2c0af7
+			fprintf(stderr, "The use of RSAMD5 was disabled\n");
2c0af7
+			INSIST(freeit == NULL);
2c0af7
+			return (1);
2c0af7
+		} else if (strcasecmp(algname, "HMAC-SHA1") == 0)
2c0af7
 			alg = DST_ALG_HMACSHA1;
2c0af7
 		else if (strcasecmp(algname, "HMAC-SHA224") == 0)
2c0af7
 			alg = DST_ALG_HMACSHA224;
2c0af7
diff --git a/bin/named/config.c b/bin/named/config.c
2c0af7
index 818ed3797a..22d8a85405 100644
2c0af7
--- a/bin/named/config.c
2c0af7
+++ b/bin/named/config.c
2c0af7
@@ -25,6 +25,7 @@
2c0af7
 
2c0af7
 #include <isc/buffer.h>
2c0af7
 #include <isc/log.h>
2c0af7
+#include <isc/md5.h>
2c0af7
 #include <isc/mem.h>
2c0af7
 #include <isc/parseint.h>
2c0af7
 #include <isc/region.h>
2c0af7
@@ -828,6 +829,19 @@ ns_config_getkeyalgorithm(const char *str, dns_name_t **name,
2c0af7
 	return (ns_config_getkeyalgorithm2(str, name, NULL, digestbits));
2c0af7
 }
2c0af7
 
2c0af7
+static inline int
2c0af7
+algorithms_start() {
2c0af7
+	if (isc_md5_available() == ISC_FALSE) {
2c0af7
+		int i = 0;
2c0af7
+		while (algorithms[i].str != NULL &&
2c0af7
+			algorithms[i].hmac == hmacmd5) {
2c0af7
+			i++;
2c0af7
+		}
2c0af7
+		return i;
2c0af7
+	}
2c0af7
+	return 0;
2c0af7
+}
2c0af7
+
2c0af7
 isc_result_t
2c0af7
 ns_config_getkeyalgorithm2(const char *str, dns_name_t **name,
2c0af7
 			   unsigned int *typep, isc_uint16_t *digestbits)
2c0af7
@@ -837,7 +851,7 @@ ns_config_getkeyalgorithm2(const char *str, dns_name_t **name,
2c0af7
 	isc_uint16_t bits;
2c0af7
 	isc_result_t result;
2c0af7
 
2c0af7
-	for (i = 0; algorithms[i].str != NULL; i++) {
2c0af7
+	for (i = algorithms_start(); algorithms[i].str != NULL; i++) {
2c0af7
 		len = strlen(algorithms[i].str);
2c0af7
 		if (strncasecmp(algorithms[i].str, str, len) == 0 &&
2c0af7
 		    (str[len] == '\0' ||
2c0af7
@@ -859,7 +873,12 @@ ns_config_getkeyalgorithm2(const char *str, dns_name_t **name,
2c0af7
 
2c0af7
 	if (name != NULL) {
2c0af7
 		switch (algorithms[i].hmac) {
2c0af7
-		case hmacmd5: *name = dns_tsig_hmacmd5_name; break;
2c0af7
+		case hmacmd5:
2c0af7
+			if (isc_md5_available()) {
2c0af7
+				*name = dns_tsig_hmacmd5_name; break;
2c0af7
+			} else {
2c0af7
+				return (ISC_R_NOTFOUND);
2c0af7
+			}
2c0af7
 		case hmacsha1: *name = dns_tsig_hmacsha1_name; break;
2c0af7
 		case hmacsha224: *name = dns_tsig_hmacsha224_name; break;
2c0af7
 		case hmacsha256: *name = dns_tsig_hmacsha256_name; break;
2c0af7
diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c
2c0af7
index 644e3d9fc0..336597a95d 100644
2c0af7
--- a/bin/nsupdate/nsupdate.c
2c0af7
+++ b/bin/nsupdate/nsupdate.c
2c0af7
@@ -37,6 +37,7 @@
2c0af7
 #include <isc/hash.h>
2c0af7
 #include <isc/lex.h>
2c0af7
 #include <isc/log.h>
2c0af7
+#include <isc/md5.h>
2c0af7
 #include <isc/mem.h>
2c0af7
 #include <isc/parseint.h>
2c0af7
 #include <isc/print.h>
2c0af7
@@ -440,9 +441,10 @@ parse_hmac(dns_name_t **hmac, const char *hmacstr, size_t len) {
2c0af7
 	strncpy(buf, hmacstr, len);
2c0af7
 	buf[len] = 0;
2c0af7
 
2c0af7
-	if (strcasecmp(buf, "hmac-md5") == 0) {
2c0af7
+	if (strcasecmp(buf, "hmac-md5") == 0 && isc_md5_available()) {
2c0af7
 		*hmac = DNS_TSIG_HMACMD5_NAME;
2c0af7
-	} else if (strncasecmp(buf, "hmac-md5-", 9) == 0) {
2c0af7
+	} else if (strncasecmp(buf, "hmac-md5-", 9) == 0 &&
2c0af7
+		   isc_md5_available()) {
2c0af7
 		*hmac = DNS_TSIG_HMACMD5_NAME;
2c0af7
 		result = isc_parse_uint16(&digestbits, &buf[9], 10);
2c0af7
 		if (result != ISC_R_SUCCESS || digestbits > 128)
2c0af7
@@ -538,7 +540,9 @@ setup_keystr(void) {
2c0af7
 		secretstr = n + 1;
2c0af7
 		digestbits = parse_hmac(&hmacname, keystr, s - keystr);
2c0af7
 	} else {
2c0af7
-		hmacname = DNS_TSIG_HMACMD5_NAME;
2c0af7
+		hmacname = DNS_TSIG_HMACSHA256_NAME;
2c0af7
+		if (isc_md5_available())
2c0af7
+			hmacname = DNS_TSIG_HMACMD5_NAME;
2c0af7
 		name = keystr;
2c0af7
 		n = s;
2c0af7
 	}
2c0af7
@@ -670,7 +674,8 @@ setup_keyfile(isc_mem_t *mctx, isc_log_t *lctx) {
2c0af7
 
2c0af7
 	switch (dst_key_alg(dstkey)) {
2c0af7
 	case DST_ALG_HMACMD5:
2c0af7
-		hmacname = DNS_TSIG_HMACMD5_NAME;
2c0af7
+		if (isc_md5_available())
2c0af7
+			hmacname = DNS_TSIG_HMACMD5_NAME;
2c0af7
 		break;
2c0af7
 	case DST_ALG_HMACSHA1:
2c0af7
 		hmacname = DNS_TSIG_HMACSHA1_NAME;
2c0af7
@@ -1462,8 +1467,11 @@ evaluate_key(char *cmdline) {
2c0af7
 	if (n != NULL) {
2c0af7
 		digestbits = parse_hmac(&hmacname, namestr, n - namestr);
2c0af7
 		namestr = n + 1;
2c0af7
-	} else
2c0af7
-		hmacname = DNS_TSIG_HMACMD5_NAME;
2c0af7
+	} else {
2c0af7
+		hmacname = DNS_TSIG_HMACSHA256_NAME;
2c0af7
+		if (isc_md5_available())
2c0af7
+			hmacname = DNS_TSIG_HMACMD5_NAME;
2c0af7
+	}
2c0af7
 
2c0af7
 	isc_buffer_init(&b, namestr, strlen(namestr));
2c0af7
 	isc_buffer_add(&b, strlen(namestr));
2c0af7
diff --git a/bin/nsupdate/nsupdate.docbook b/bin/nsupdate/nsupdate.docbook
2c0af7
index bbcc68110f..7d8e78f894 100644
2c0af7
--- a/bin/nsupdate/nsupdate.docbook
2c0af7
+++ b/bin/nsupdate/nsupdate.docbook
2c0af7
@@ -158,6 +158,9 @@
2c0af7
       <optional><parameter>hmac:</parameter></optional><parameter>keyname:secret.</parameter>
2c0af7
       <parameter>keyname</parameter> is the name of the key, and
2c0af7
       <parameter>secret</parameter> is the base64 encoded shared secret.
2c0af7
+      If <parameter>hmac</parameter> is not specified,
2c0af7
+      the default is <literal>hmac-md5</literal>
2c0af7
+      or if MD5 was disabled <literal>hmac-sha256</literal>.
2c0af7
       Use of the <option>-y</option> option is discouraged because the
2c0af7
       shared secret is supplied as a command line argument in clear text.
2c0af7
       This may be visible in the output from
2c0af7
@@ -371,13 +374,17 @@
2c0af7
         <varlistentry>
2c0af7
           <term>
2c0af7
               <command>key</command>
2c0af7
-              <arg choice="req">name</arg>
2c0af7
+              <arg choice="opt" rep="norepeat">hmac:</arg><arg choice="req">name</arg>
2c0af7
               <arg choice="req">secret</arg>
2c0af7
             </term>
2c0af7
           <listitem>
2c0af7
             <para>
2c0af7
               Specifies that all updates are to be TSIG-signed using the
2c0af7
               <parameter>keyname</parameter> <parameter>keysecret</parameter> pair.
2c0af7
+              If <parameter>hmac</parameter> is specified, then it sets the
2c0af7
+              signing algorithm in use; the default is
2c0af7
+              <literal>hmac-md5</literal> or if MD5 was disabled
2c0af7
+              <literal>hmac-sha256</literal>.
2c0af7
               The <command>key</command> command
2c0af7
               overrides any key specified on the command line via
2c0af7
               <option>-y</option> or <option>-k</option>.
2c0af7
diff --git a/bin/rndc/rndc.c b/bin/rndc/rndc.c
2c0af7
index 81e629f15c..0fd192d3a5 100644
2c0af7
--- a/bin/rndc/rndc.c
2c0af7
+++ b/bin/rndc/rndc.c
2c0af7
@@ -33,6 +33,7 @@
2c0af7
 #include <isc/file.h>
2c0af7
 #include <isc/log.h>
2c0af7
 #include <isc/net.h>
2c0af7
+#include <isc/md5.h>
2c0af7
 #include <isc/mem.h>
2c0af7
 #include <isc/random.h>
2c0af7
 #include <isc/socket.h>
2c0af7
@@ -607,7 +608,7 @@ parse_config(isc_mem_t *mctx, isc_log_t *log, const char *keyname,
2c0af7
 	secretstr = cfg_obj_asstring(secretobj);
2c0af7
 	algorithmstr = cfg_obj_asstring(algorithmobj);
2c0af7
 
2c0af7
-	if (strcasecmp(algorithmstr, "hmac-md5") == 0)
2c0af7
+	if (strcasecmp(algorithmstr, "hmac-md5") == 0 && isc_md5_available())
2c0af7
 		algorithm = ISCCC_ALG_HMACMD5;
2c0af7
 	else if (strcasecmp(algorithmstr, "hmac-sha1") == 0)
2c0af7
 		algorithm = ISCCC_ALG_HMACSHA1;
2c0af7
diff --git a/bin/tests/hashes/t_hashes.c b/bin/tests/hashes/t_hashes.c
2c0af7
index 47d08c572d..965271ad67 100644
2c0af7
--- a/bin/tests/hashes/t_hashes.c
2c0af7
+++ b/bin/tests/hashes/t_hashes.c
2c0af7
@@ -353,8 +353,10 @@ t_hashes(IN *in, OUT *out_sha1, OUT *out_sha224, OUT *out_md5)
2c0af7
 	t_hash("SHA1", (HASH_INIT)isc_sha1_init, (UPDATE)isc_sha1_update,
2c0af7
 	       (FINAL)isc_sha1_final, in, out_sha1);
2c0af7
 	t_sha224(in, out_sha224);
2c0af7
-	t_hash("md5", (HASH_INIT)isc_md5_init, (UPDATE)isc_md5_update,
2c0af7
-	       (FINAL)isc_md5_final, in, out_md5);
2c0af7
+	if (isc_md5_available()) {
2c0af7
+		t_hash("md5", (HASH_INIT)isc_md5_init, (UPDATE)isc_md5_update,
2c0af7
+		       (FINAL)isc_md5_final, in, out_md5);
2c0af7
+	}
2c0af7
 }
2c0af7
 
2c0af7
 
2c0af7
@@ -435,12 +437,14 @@ t1(void)
2c0af7
 	t_hashes(&abc, &abc_sha1, &abc_sha224, &abc_md5);
2c0af7
 	t_hashes(&abc_blah, &abc_blah_sha1, &abc_blah_sha224, &abc_blah_md5);
2c0af7
 
2c0af7
-	/*
2c0af7
-	 * three HMAC-md5 examples from RFC 2104
2c0af7
-	 */
2c0af7
-	t_md5hmac(&rfc2104_1, &rfc2104_1_hmac);
2c0af7
-	t_md5hmac(&rfc2104_2, &rfc2104_2_hmac);
2c0af7
-	t_md5hmac(&rfc2104_3, &rfc2104_3_hmac);
2c0af7
+	if (isc_md5_available()) {
2c0af7
+		/*
2c0af7
+		 * three HMAC-md5 examples from RFC 2104
2c0af7
+		 */
2c0af7
+		t_md5hmac(&rfc2104_1, &rfc2104_1_hmac);
2c0af7
+		t_md5hmac(&rfc2104_2, &rfc2104_2_hmac);
2c0af7
+		t_md5hmac(&rfc2104_3, &rfc2104_3_hmac);
2c0af7
+	}
2c0af7
 
2c0af7
 	/*
2c0af7
 	 * four HMAC-SHA tests from RFC 4634 starting on page 86
2c0af7
diff --git a/lib/bind9/check.c b/lib/bind9/check.c
2c0af7
index 5131b521f4..00c4b3e509 100644
2c0af7
--- a/lib/bind9/check.c
2c0af7
+++ b/lib/bind9/check.c
2c0af7
@@ -26,6 +26,7 @@
2c0af7
 #include <isc/base64.h>
2c0af7
 #include <isc/buffer.h>
2c0af7
 #include <isc/log.h>
2c0af7
+#include <isc/md5.h>
2c0af7
 #include <isc/mem.h>
2c0af7
 #include <isc/netaddr.h>
2c0af7
 #include <isc/parseint.h>
2c0af7
@@ -1895,6 +1896,13 @@ bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
2c0af7
 	}
2c0af7
 
2c0af7
 	algorithm = cfg_obj_asstring(algobj);
2c0af7
+	/* Skip hmac-md5* algorithms */
2c0af7
+	if (isc_md5_available() == ISC_FALSE &&
2c0af7
+	    strncasecmp(algorithm, "hmac-md5", 8) == 0) {
2c0af7
+		cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
2c0af7
+			    "disabled algorithm '%s'", algorithm);
2c0af7
+		return (ISC_R_DISABLED);
2c0af7
+	}
2c0af7
 	for (i = 0; algorithms[i].name != NULL; i++) {
2c0af7
 		len = strlen(algorithms[i].name);
2c0af7
 		if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
2c0af7
diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c
2c0af7
index e71f2026e5..e6375cf406 100644
2c0af7
--- a/lib/dns/dst_api.c
2c0af7
+++ b/lib/dns/dst_api.c
2c0af7
@@ -202,6 +202,12 @@ dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx,
2c0af7
 	dst_result_register();
2c0af7
 
2c0af7
 	memset(dst_t_func, 0, sizeof(dst_t_func));
2c0af7
+
2c0af7
+#ifdef OPENSSL
2c0af7
+	RETERR(dst__openssl_init(engine));
2c0af7
+#elif PKCS11CRYPTO
2c0af7
+	RETERR(dst__pkcs11_init(mctx, engine));
2c0af7
+#endif
2c0af7
 	RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5]));
2c0af7
 	RETERR(dst__hmacsha1_init(&dst_t_func[DST_ALG_HMACSHA1]));
2c0af7
 	RETERR(dst__hmacsha224_init(&dst_t_func[DST_ALG_HMACSHA224]));
2c0af7
@@ -209,7 +215,6 @@ dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx,
2c0af7
 	RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384]));
2c0af7
 	RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512]));
2c0af7
 #ifdef OPENSSL
2c0af7
-	RETERR(dst__openssl_init(engine));
2c0af7
 	RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5],
2c0af7
 				    DST_ALG_RSAMD5));
2c0af7
 	RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1],
2c0af7
@@ -233,12 +238,16 @@ dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx,
2c0af7
 	RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA384]));
2c0af7
 #endif
2c0af7
 #elif PKCS11CRYPTO
2c0af7
-	RETERR(dst__pkcs11_init(mctx, engine));
2c0af7
-	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSAMD5]));
2c0af7
-	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA1]));
2c0af7
-	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1]));
2c0af7
-	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA256]));
2c0af7
-	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA512]));
2c0af7
+	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSAMD5],
2c0af7
+				   DST_ALG_RSAMD5));
2c0af7
+	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA1],
2c0af7
+				   DST_ALG_RSASHA1));
2c0af7
+	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1],
2c0af7
+				   DST_ALG_NSEC3RSASHA1));
2c0af7
+	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA256],
2c0af7
+				   DST_ALG_RSASHA256));
2c0af7
+	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA512],
2c0af7
+				   DST_ALG_RSASHA512));
2c0af7
 	RETERR(dst__pkcs11dsa_init(&dst_t_func[DST_ALG_DSA]));
2c0af7
 	RETERR(dst__pkcs11dsa_init(&dst_t_func[DST_ALG_NSEC3DSA]));
2c0af7
 	RETERR(dst__pkcs11dh_init(&dst_t_func[DST_ALG_DH]));
2c0af7
diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h
2c0af7
index b15135e634..66d322a278 100644
2c0af7
--- a/lib/dns/dst_internal.h
2c0af7
+++ b/lib/dns/dst_internal.h
2c0af7
@@ -232,7 +232,8 @@ isc_result_t dst__hmacsha384_init(struct dst_func **funcp);
2c0af7
 isc_result_t dst__hmacsha512_init(struct dst_func **funcp);
2c0af7
 isc_result_t dst__opensslrsa_init(struct dst_func **funcp,
2c0af7
 				  unsigned char algorithm);
2c0af7
-isc_result_t dst__pkcs11rsa_init(struct dst_func **funcp);
2c0af7
+isc_result_t dst__pkcs11rsa_init(struct dst_func **funcp,
2c0af7
+				 unsigned char algorithm);
2c0af7
 isc_result_t dst__openssldsa_init(struct dst_func **funcp);
2c0af7
 isc_result_t dst__pkcs11dsa_init(struct dst_func **funcp);
2c0af7
 isc_result_t dst__openssldh_init(struct dst_func **funcp);
2c0af7
diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c
2c0af7
index ec622d9603..0e889cc740 100644
2c0af7
--- a/lib/dns/dst_parse.c
2c0af7
+++ b/lib/dns/dst_parse.c
2c0af7
@@ -40,6 +40,7 @@
2c0af7
 #include <isc/dir.h>
2c0af7
 #include <isc/fsaccess.h>
2c0af7
 #include <isc/lex.h>
2c0af7
+#include <isc/md5.h>
2c0af7
 #include <isc/mem.h>
2c0af7
 #include <isc/stdtime.h>
2c0af7
 #include <isc/string.h>
2c0af7
@@ -353,6 +354,10 @@ check_data(const dst_private_t *priv, const unsigned int alg,
2c0af7
 	/* XXXVIX this switch statement is too sparse to gen a jump table. */
2c0af7
 	switch (alg) {
2c0af7
 	case DST_ALG_RSAMD5:
2c0af7
+		if (isc_md5_available())
2c0af7
+			return (check_rsa(priv, external));
2c0af7
+		else
2c0af7
+			return (DST_R_UNSUPPORTEDALG);
2c0af7
 	case DST_ALG_RSASHA1:
2c0af7
 	case DST_ALG_NSEC3RSASHA1:
2c0af7
 	case DST_ALG_RSASHA256:
2c0af7
@@ -369,7 +374,10 @@ check_data(const dst_private_t *priv, const unsigned int alg,
2c0af7
 	case DST_ALG_ECDSA384:
2c0af7
 		return (check_ecdsa(priv, external));
2c0af7
 	case DST_ALG_HMACMD5:
2c0af7
-		return (check_hmac_md5(priv, old));
2c0af7
+		if (isc_md5_available())
2c0af7
+			return (check_hmac_md5(priv, old));
2c0af7
+		else
2c0af7
+			return (DST_R_UNSUPPORTEDALG);
2c0af7
 	case DST_ALG_HMACSHA1:
2c0af7
 		return (check_hmac_sha(priv, HMACSHA1_NTAGS, alg));
2c0af7
 	case DST_ALG_HMACSHA224:
2c0af7
@@ -587,6 +595,8 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
2c0af7
 		goto fail;
2c0af7
 	}
2c0af7
 
2c0af7
+	if (isc_md5_available() == ISC_FALSE && alg == DST_ALG_RSA)
2c0af7
+		alg = DST_ALG_RSASHA1;
2c0af7
 	check = check_data(priv, alg, ISC_TRUE, external);
2c0af7
 	if (check < 0) {
2c0af7
 		ret = DST_R_INVALIDPRIVATEKEY;
2c0af7
diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c
2c0af7
index 3ac01a8c20..6b6801af1c 100644
2c0af7
--- a/lib/dns/hmac_link.c
2c0af7
+++ b/lib/dns/hmac_link.c
2c0af7
@@ -340,7 +340,7 @@ static dst_func_t hmacmd5_functions = {
2c0af7
 isc_result_t
2c0af7
 dst__hmacmd5_init(dst_func_t **funcp) {
2c0af7
 	REQUIRE(funcp != NULL);
2c0af7
-	if (*funcp == NULL)
2c0af7
+	if (*funcp == NULL && isc_md5_available())
2c0af7
 		*funcp = &hmacmd5_functions;
2c0af7
 	return (ISC_R_SUCCESS);
2c0af7
 }
2c0af7
diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c
2c0af7
index 53c6d4bdd9..08291af016 100644
2c0af7
--- a/lib/dns/opensslrsa_link.c
2c0af7
+++ b/lib/dns/opensslrsa_link.c
2c0af7
@@ -1484,6 +1484,10 @@ dst__opensslrsa_init(dst_func_t **funcp, unsigned char algorithm) {
2c0af7
 
2c0af7
 	if (*funcp == NULL) {
2c0af7
 		switch (algorithm) {
2c0af7
+		case DST_ALG_RSAMD5:
2c0af7
+			if (isc_md5_available())
2c0af7
+				*funcp = &opensslrsa_functions;
2c0af7
+			break;
2c0af7
 		case DST_ALG_RSASHA256:
2c0af7
 #if defined(HAVE_EVP_SHA256) || !USE_EVP
2c0af7
 			*funcp = &opensslrsa_functions;
2c0af7
diff --git a/lib/dns/pkcs11rsa_link.c b/lib/dns/pkcs11rsa_link.c
2c0af7
index 010d4b64fc..6b556bcd11 100644
2c0af7
--- a/lib/dns/pkcs11rsa_link.c
2c0af7
+++ b/lib/dns/pkcs11rsa_link.c
2c0af7
@@ -89,6 +89,9 @@ pkcs11rsa_createctx_sign(dst_key_t *key, dst_context_t *dctx) {
2c0af7
 		key->key_alg == DST_ALG_RSASHA256 ||
2c0af7
 		key->key_alg == DST_ALG_RSASHA512);
2c0af7
 
2c0af7
+	if (key->key_alg == DST_ALG_RSAMD5 && isc_md5_available() == ISC_FALSE)
2c0af7
+		return (ISC_R_FAILURE);
2c0af7
+
2c0af7
 	rsa = key->keydata.pkey;
2c0af7
 
2c0af7
 	pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx,
2c0af7
@@ -216,6 +219,8 @@ pkcs11rsa_createctx_sign(dst_key_t *key, dst_context_t *dctx) {
2c0af7
 
2c0af7
 	switch (dctx->key->key_alg) {
2c0af7
 	case DST_ALG_RSAMD5:
2c0af7
+		if (isc_md5_available() == ISC_FALSE)
2c0af7
+			return (ISC_R_FAILURE);
2c0af7
 		mech.mechanism = CKM_MD5_RSA_PKCS;
2c0af7
 		break;
2c0af7
 	case DST_ALG_RSASHA1:
2c0af7
@@ -297,6 +302,9 @@ pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits,
2c0af7
 		key->key_alg == DST_ALG_RSASHA256 ||
2c0af7
 		key->key_alg == DST_ALG_RSASHA512);
2c0af7
 
2c0af7
+	if (key->key_alg == DST_ALG_RSAMD5 && isc_md5_available() == ISC_FALSE)
2c0af7
+		return (ISC_R_FAILURE);
2c0af7
+
2c0af7
 	rsa = key->keydata.pkey;
2c0af7
 
2c0af7
 	pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx,
2c0af7
@@ -350,6 +358,8 @@ pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits,
2c0af7
 
2c0af7
 	switch (dctx->key->key_alg) {
2c0af7
 	case DST_ALG_RSAMD5:
2c0af7
+		if (isc_md5_available() == ISC_FALSE)
2c0af7
+			return (ISC_R_FAILURE);
2c0af7
 		mech.mechanism = CKM_MD5_RSA_PKCS;
2c0af7
 		break;
2c0af7
 	case DST_ALG_RSASHA1:
2c0af7
@@ -1565,11 +1575,20 @@ static dst_func_t pkcs11rsa_functions = {
2c0af7
 };
2c0af7
 
2c0af7
 isc_result_t
2c0af7
-dst__pkcs11rsa_init(dst_func_t **funcp) {
2c0af7
+dst__pkcs11rsa_init(dst_func_t **funcp, unsigned char algorithm) {
2c0af7
 	REQUIRE(funcp != NULL);
2c0af7
 
2c0af7
-	if (*funcp == NULL)
2c0af7
-		*funcp = &pkcs11rsa_functions;
2c0af7
+	if (*funcp == NULL) {
2c0af7
+		switch (algorithm) {
2c0af7
+			case DST_ALG_RSAMD5:
2c0af7
+				if (isc_md5_available())
2c0af7
+					*funcp = &pkcs11rsa_functions;
2c0af7
+				break;
2c0af7
+			default:
2c0af7
+				*funcp = &pkcs11rsa_functions;
2c0af7
+				break;
2c0af7
+		}
2c0af7
+	}
2c0af7
 	return (ISC_R_SUCCESS);
2c0af7
 }
2c0af7
 
2c0af7
diff --git a/lib/dns/rcode.c b/lib/dns/rcode.c
2c0af7
index 091b3c70fb..c1251225d5 100644
2c0af7
--- a/lib/dns/rcode.c
2c0af7
+++ b/lib/dns/rcode.c
2c0af7
@@ -21,6 +21,7 @@
2c0af7
 #include <ctype.h>
2c0af7
 
2c0af7
 #include <isc/buffer.h>
2c0af7
+#include <isc/md5.h>
2c0af7
 #include <isc/parseint.h>
2c0af7
 #include <isc/print.h>
2c0af7
 #include <isc/region.h>
2c0af7
@@ -310,17 +311,31 @@ dns_cert_totext(dns_cert_t cert, isc_buffer_t *target) {
2c0af7
 	return (dns_mnemonic_totext(cert, target, certs));
2c0af7
 }
2c0af7
 
2c0af7
+static inline struct tbl *
2c0af7
+secalgs_tbl_start() {
2c0af7
+	struct tbl *algs = secalgs;
2c0af7
+
2c0af7
+	if (isc_md5_available() == ISC_FALSE) {
2c0af7
+		while (algs->name != NULL &&
2c0af7
+		       algs->value == DNS_KEYALG_RSAMD5)
2c0af7
+			++algs;
2c0af7
+	}
2c0af7
+	return algs;
2c0af7
+}
2c0af7
+
2c0af7
 isc_result_t
2c0af7
 dns_secalg_fromtext(dns_secalg_t *secalgp, isc_textregion_t *source) {
2c0af7
 	unsigned int value;
2c0af7
-	RETERR(dns_mnemonic_fromtext(&value, source, secalgs, 0xff));
2c0af7
+
2c0af7
+	RETERR(dns_mnemonic_fromtext(&value, source,
2c0af7
+	                             secalgs_tbl_start(), 0xff));
2c0af7
 	*secalgp = value;
2c0af7
 	return (ISC_R_SUCCESS);
2c0af7
 }
2c0af7
 
2c0af7
 isc_result_t
2c0af7
 dns_secalg_totext(dns_secalg_t secalg, isc_buffer_t *target) {
2c0af7
-	return (dns_mnemonic_totext(secalg, target, secalgs));
2c0af7
+	return (dns_mnemonic_totext(secalg, target, secalgs_tbl_start()));
2c0af7
 }
2c0af7
 
2c0af7
 void
2c0af7
diff --git a/lib/dns/tests/tsig_test.c b/lib/dns/tests/tsig_test.c
2c0af7
index 956e4a0469..c4b2f84837 100644
2c0af7
--- a/lib/dns/tests/tsig_test.c
2c0af7
+++ b/lib/dns/tests/tsig_test.c
2c0af7
@@ -10,6 +10,7 @@
2c0af7
 
2c0af7
 #include <config.h>
2c0af7
 #include <atf-c.h>
2c0af7
+#include <isc/md5.h>
2c0af7
 #include <isc/mem.h>
2c0af7
 
2c0af7
 #include <dns/rdatalist.h>
2c0af7
diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c
2c0af7
index 7343b4c26f..59a78c8dca 100644
2c0af7
--- a/lib/dns/tkey.c
2c0af7
+++ b/lib/dns/tkey.c
2c0af7
@@ -230,6 +230,9 @@ compute_secret(isc_buffer_t *shared, isc_region_t *queryrandomness,
2c0af7
 	unsigned char digests[32];
2c0af7
 	unsigned int i;
2c0af7
 
2c0af7
+	if (isc_md5_available() == ISC_FALSE)
2c0af7
+		return (ISC_R_NOTIMPLEMENTED);
2c0af7
+
2c0af7
 	isc_buffer_usedregion(shared, &r);
2c0af7
 
2c0af7
 	/*
2c0af7
@@ -298,6 +301,12 @@ process_dhtkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name,
2c0af7
 		return (DNS_R_REFUSED);
2c0af7
 	}
2c0af7
 
2c0af7
+	if (isc_md5_available() == ISC_FALSE) {
2c0af7
+		tkey_log("process_dhtkey: MD5 was disabled");
2c0af7
+		tkeyout->error = dns_tsigerror_badalg;
2c0af7
+		return (ISC_R_SUCCESS);
2c0af7
+	}
2c0af7
+
2c0af7
 	if (!dns_name_equal(&tkeyin->algorithm, DNS_TSIG_HMACMD5_NAME)) {
2c0af7
 		tkey_log("process_dhtkey: algorithms other than "
2c0af7
 			 "hmac-md5 are not supported");
2c0af7
diff --git a/lib/dns/tsec.c b/lib/dns/tsec.c
2c0af7
index bfa6195d0d..fad645668c 100644
2c0af7
--- a/lib/dns/tsec.c
2c0af7
+++ b/lib/dns/tsec.c
2c0af7
@@ -18,6 +18,7 @@
2c0af7
 
2c0af7
 #include <config.h>
2c0af7
 
2c0af7
+#include <isc/md5.h>
2c0af7
 #include <isc/mem.h>
2c0af7
 
2c0af7
 #include <dns/tsec.h>
2c0af7
@@ -66,7 +67,12 @@ dns_tsec_create(isc_mem_t *mctx, dns_tsectype_t type, dst_key_t *key,
2c0af7
 	case dns_tsectype_tsig:
2c0af7
 		switch (dst_key_alg(key)) {
2c0af7
 		case DST_ALG_HMACMD5:
2c0af7
-			algname = dns_tsig_hmacmd5_name;
2c0af7
+			if (isc_md5_available()) {
2c0af7
+				algname = dns_tsig_hmacmd5_name;
2c0af7
+			} else {
2c0af7
+				isc_mem_put(mctx, tsec, sizeof(*tsec));
2c0af7
+				return (DNS_R_BADALG);
2c0af7
+			}
2c0af7
 			break;
2c0af7
 		case DST_ALG_HMACSHA1:
2c0af7
 			algname = dns_tsig_hmacsha1_name;
2c0af7
diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c
2c0af7
index 325c901f93..804ef821f0 100644
2c0af7
--- a/lib/dns/tsig.c
2c0af7
+++ b/lib/dns/tsig.c
2c0af7
@@ -24,6 +24,7 @@
2c0af7
 
2c0af7
 #include <isc/buffer.h>
2c0af7
 #include <isc/mem.h>
2c0af7
+#include <isc/md5.h>
2c0af7
 #include <isc/print.h>
2c0af7
 #include <isc/refcount.h>
2c0af7
 #include <isc/serial.h>
2c0af7
@@ -316,7 +317,7 @@ dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
2c0af7
 		goto cleanup_key;
2c0af7
 	(void)dns_name_downcase(&tkey->name, &tkey->name, NULL);
2c0af7
 
2c0af7
-	if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) {
2c0af7
+	if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME) && isc_md5_available()) {
2c0af7
 		tkey->algorithm = DNS_TSIG_HMACMD5_NAME;
2c0af7
 		if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACMD5) {
2c0af7
 			ret = DNS_R_BADALG;
2c0af7
@@ -539,7 +540,7 @@ destroyring(dns_tsig_keyring_t *ring) {
2c0af7
 
2c0af7
 static unsigned int
2c0af7
 dst_alg_fromname(dns_name_t *algorithm) {
2c0af7
-	if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) {
2c0af7
+	if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME) && isc_md5_available()) {
2c0af7
 		return (DST_ALG_HMACMD5);
2c0af7
 	} else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) {
2c0af7
 		return (DST_ALG_HMACSHA1);
2c0af7
@@ -724,7 +725,7 @@ dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
2c0af7
 	if (length > 0)
2c0af7
 		REQUIRE(secret != NULL);
2c0af7
 
2c0af7
-	if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) {
2c0af7
+	if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME) && isc_md5_available()) {
2c0af7
 		if (secret != NULL) {
2c0af7
 			isc_buffer_t b;
2c0af7
 
2c0af7
@@ -1322,7 +1323,8 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
2c0af7
 	ret = dst_key_sigsize(key, &siglen);
2c0af7
 	if (ret != ISC_R_SUCCESS)
2c0af7
 		return (ret);
2c0af7
-	if (alg == DST_ALG_HMACMD5 || alg == DST_ALG_HMACSHA1 ||
2c0af7
+	if ((alg == DST_ALG_HMACMD5 && isc_md5_available()) ||
2c0af7
+	    alg == DST_ALG_HMACSHA1 ||
2c0af7
 	    alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 ||
2c0af7
 	    alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512)
2c0af7
 	{
2c0af7
@@ -1484,9 +1486,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
2c0af7
 	}
2c0af7
 
2c0af7
 	if (
2c0af7
-#ifndef PK11_MD5_DISABLE
2c0af7
-	    alg == DST_ALG_HMACMD5 ||
2c0af7
-#endif
2c0af7
+	    (alg == DST_ALG_HMACMD5 && isc_md5_available()) ||
2c0af7
 	    alg == DST_ALG_HMACSHA1 ||
2c0af7
 	    alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 ||
2c0af7
 	    alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512)
2c0af7
@@ -1626,9 +1626,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
2c0af7
 		if (ret != ISC_R_SUCCESS)
2c0af7
 			goto cleanup_querystruct;
2c0af7
 		if (
2c0af7
-#ifndef PK11_MD5_DISABLE
2c0af7
-			alg == DST_ALG_HMACMD5 ||
2c0af7
-#endif
2c0af7
+			(alg == DST_ALG_HMACMD5 && isc_md5_available()) ||
2c0af7
 			alg == DST_ALG_HMACSHA1 ||
2c0af7
 			alg == DST_ALG_HMACSHA224 ||
2c0af7
 			alg == DST_ALG_HMACSHA256 ||
2c0af7
@@ -1801,9 +1799,7 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
2c0af7
 		if (ret != ISC_R_SUCCESS)
2c0af7
 			goto cleanup_context;
2c0af7
 		if (
2c0af7
-#ifndef PK11_MD5_DISABLE
2c0af7
-			alg == DST_ALG_HMACMD5 ||
2c0af7
-#endif
2c0af7
+			(alg == DST_ALG_HMACMD5 && isc_md5_available()) ||
2c0af7
 			alg == DST_ALG_HMACSHA1 ||
2c0af7
 			alg == DST_ALG_HMACSHA224 ||
2c0af7
 			alg == DST_ALG_HMACSHA256 ||
2c0af7
diff --git a/lib/isc/include/isc/md5.h b/lib/isc/include/isc/md5.h
2c0af7
index a2e00b382a..d4c2b8ab48 100644
2c0af7
--- a/lib/isc/include/isc/md5.h
2c0af7
+++ b/lib/isc/include/isc/md5.h
2c0af7
@@ -83,6 +83,9 @@ isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len);
2c0af7
 void
2c0af7
 isc_md5_final(isc_md5_t *ctx, unsigned char *digest);
2c0af7
 
2c0af7
+isc_boolean_t
2c0af7
+isc_md5_available(void);
2c0af7
+
2c0af7
 ISC_LANG_ENDDECLS
2c0af7
 
2c0af7
 #endif /* ISC_MD5_H */
2c0af7
diff --git a/lib/isc/md5.c b/lib/isc/md5.c
2c0af7
index 2e3cf9a4a3..a5113df4b8 100644
2c0af7
--- a/lib/isc/md5.c
2c0af7
+++ b/lib/isc/md5.c
2c0af7
@@ -38,6 +38,7 @@
2c0af7
 
2c0af7
 #include <isc/assertions.h>
2c0af7
 #include <isc/md5.h>
2c0af7
+#include <isc/once.h>
2c0af7
 #include <isc/platform.h>
2c0af7
 #include <isc/string.h>
2c0af7
 #include <isc/types.h>
2c0af7
@@ -51,6 +52,9 @@
2c0af7
 
2c0af7
 #ifdef ISC_PLATFORM_OPENSSLHASH
2c0af7
 
2c0af7
+static isc_once_t available_once = ISC_ONCE_INIT;
2c0af7
+static isc_boolean_t available = ISC_FALSE;
2c0af7
+
2c0af7
 void
2c0af7
 isc_md5_init(isc_md5_t *ctx) {
2c0af7
 	EVP_DigestInit(ctx, EVP_md5());
2c0af7
@@ -71,8 +75,33 @@ isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
2c0af7
 	EVP_DigestFinal(ctx, digest, NULL);
2c0af7
 }
2c0af7
 
2c0af7
+static void
2c0af7
+do_detect_available() {
2c0af7
+	isc_md5_t local;
2c0af7
+	isc_md5_t *ctx = &local;
2c0af7
+	unsigned char digest[ISC_MD5_DIGESTLENGTH];
2c0af7
+
2c0af7
+	ctx->ctx = EVP_MD_CTX_new();
2c0af7
+	RUNTIME_CHECK(ctx->ctx != NULL);
2c0af7
+	available = ISC_TF(EVP_DigestInit(ctx->ctx, EVP_md5()) == 1);
2c0af7
+	if (available)
2c0af7
+		(void)EVP_DigestFinal(ctx->ctx, digest, NULL);
2c0af7
+	EVP_MD_CTX_free(ctx->ctx);
2c0af7
+	ctx->ctx = NULL;
2c0af7
+}
2c0af7
+
2c0af7
+isc_boolean_t
2c0af7
+isc_md5_available() {
2c0af7
+	RUNTIME_CHECK(isc_once_do(&available_once, do_detect_available)
2c0af7
+		      == ISC_R_SUCCESS);
2c0af7
+	return available;
2c0af7
+}
2c0af7
+
2c0af7
 #elif PKCS11CRYPTO
2c0af7
 
2c0af7
+static isc_once_t available_once = ISC_ONCE_INIT;
2c0af7
+static isc_boolean_t available = ISC_FALSE;
2c0af7
+
2c0af7
 void
2c0af7
 isc_md5_init(isc_md5_t *ctx) {
2c0af7
 	CK_RV rv;
2c0af7
@@ -115,6 +144,31 @@ isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
2c0af7
 	pk11_return_session(ctx);
2c0af7
 }
2c0af7
 
2c0af7
+static void
2c0af7
+do_detect_available() {
2c0af7
+	isc_md5_t local;
2c0af7
+	isc_md5_t *ctx = &local;
2c0af7
+	CK_RV rv;
2c0af7
+	CK_MECHANISM mech = { CKM_MD5, NULL, 0 };
2c0af7
+
2c0af7
+	if (pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
2c0af7
+				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS)
2c0af7
+	{
2c0af7
+		rv = pkcs_C_DigestInit(ctx->session, &mech);
2c0af7
+		isc_md5_invalidate(ctx);
2c0af7
+		available = (ISC_TF(rv == CKR_OK));
2c0af7
+	} else {
2c0af7
+		available = ISC_FALSE;
2c0af7
+	}
2c0af7
+}
2c0af7
+
2c0af7
+isc_boolean_t
2c0af7
+isc_md5_available() {
2c0af7
+	RUNTIME_CHECK(isc_once_do(&available_once, do_detect_available)
2c0af7
+		      == ISC_R_SUCCESS);
2c0af7
+	return available;
2c0af7
+}
2c0af7
+
2c0af7
 #else
2c0af7
 
2c0af7
 static void
2c0af7
@@ -324,4 +378,9 @@ isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
2c0af7
 	memcpy(digest, ctx->buf, 16);
2c0af7
 	memset(ctx, 0, sizeof(isc_md5_t));	/* In case it's sensitive */
2c0af7
 }
2c0af7
+
2c0af7
+isc_boolean_t
2c0af7
+isc_md5_available() {
2c0af7
+	return ISC_TRUE;
2c0af7
+}
2c0af7
 #endif
2c0af7
diff --git a/lib/isc/pk11.c b/lib/isc/pk11.c
2c0af7
index de4479b7b0..6cce70f0cf 100644
2c0af7
--- a/lib/isc/pk11.c
2c0af7
+++ b/lib/isc/pk11.c
2c0af7
@@ -139,6 +139,8 @@
2c0af7
 #define PK11_NO_LOGERR 1
2c0af7
 #endif
2c0af7
 
2c0af7
+LIBISC_EXTERNAL_DATA isc_boolean_t pk11_verbose_init = ISC_FALSE;
2c0af7
+
2c0af7
 static isc_once_t once = ISC_ONCE_INIT;
2c0af7
 static isc_mem_t *pk11_mctx = NULL;
2c0af7
 static isc_int32_t allocsize = 0;
2c0af7
@@ -283,13 +285,12 @@ pk11_initialize(isc_mem_t *mctx, const char *engine) {
2c0af7
 	LOCK(&alloclock);
2c0af7
 	if ((mctx != NULL) && (pk11_mctx == NULL) && (allocsize == 0))
2c0af7
 		isc_mem_attach(mctx, &pk11_mctx);
2c0af7
+	UNLOCK(&alloclock);
2c0af7
+
2c0af7
+	LOCK(&sessionlock);
2c0af7
 	if (initialized) {
2c0af7
-		UNLOCK(&alloclock);
2c0af7
-		return (ISC_R_SUCCESS);
2c0af7
-	} else {
2c0af7
-		LOCK(&sessionlock);
2c0af7
-		initialized = ISC_TRUE;
2c0af7
-		UNLOCK(&alloclock);
2c0af7
+		result = ISC_R_SUCCESS;
2c0af7
+		goto unlock;
2c0af7
 	}
2c0af7
 
2c0af7
 	ISC_LIST_INIT(tokens);
2c0af7
@@ -327,6 +328,7 @@ pk11_initialize(isc_mem_t *mctx, const char *engine) {
2c0af7
 	}
2c0af7
 #endif
2c0af7
 #endif /* PKCS11CRYPTO */
2c0af7
+	initialized = ISC_TRUE;
2c0af7
 	result = ISC_R_SUCCESS;
2c0af7
  unlock:
2c0af7
 	UNLOCK(&sessionlock);
2c0af7
@@ -363,9 +365,14 @@ pk11_finalize(void) {
2c0af7
 		pk11_mem_put(token, sizeof(*token));
2c0af7
 		token = next;
2c0af7
 	}
2c0af7
+	LOCK(&alloclock);
2c0af7
 	if (pk11_mctx != NULL)
2c0af7
 		isc_mem_detach(&pk11_mctx);
2c0af7
+	UNLOCK(&alloclock);
2c0af7
+
2c0af7
+	LOCK(&sessionlock);
2c0af7
 	initialized = ISC_FALSE;
2c0af7
+	UNLOCK(&sessionlock);
2c0af7
 	return (ret);
2c0af7
 }
2c0af7
 
2c0af7
@@ -655,6 +662,15 @@ token_login(pk11_session_t *sp) {
2c0af7
 	return (ret);
2c0af7
 }
2c0af7
 
2c0af7
+#define PK11_TRACE(fmt) \
2c0af7
+	if (pk11_verbose_init) fprintf(stderr, fmt)
2c0af7
+#define PK11_TRACE1(fmt, arg) \
2c0af7
+	if (pk11_verbose_init) fprintf(stderr, fmt, arg)
2c0af7
+#define PK11_TRACE2(fmt, arg1, arg2) \
2c0af7
+	if (pk11_verbose_init) fprintf(stderr, fmt, arg1, arg2)
2c0af7
+#define PK11_TRACEM(mech) \
2c0af7
+	if (pk11_verbose_init) fprintf(stderr, #mech ": 0x%lx\n", rv)
2c0af7
+
2c0af7
 static void
2c0af7
 choose_slots(void) {
2c0af7
 	CK_MECHANISM_INFO mechInfo;
2c0af7
@@ -665,6 +681,8 @@ choose_slots(void) {
2c0af7
 	CK_ULONG slotCount;
2c0af7
 	pk11_token_t *token;
2c0af7
 	unsigned int i;
2c0af7
+	unsigned int best_rsa_algorithms = 0;
2c0af7
+	unsigned int best_digest_algorithms = 0;
2c0af7
 
2c0af7
 	slotCount = 0;
2c0af7
 	PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, NULL_PTR, &slotCount));
2c0af7
@@ -676,6 +694,8 @@ choose_slots(void) {
2c0af7
 	PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, slotList, &slotCount));
2c0af7
 
2c0af7
 	for (i = 0; i < slotCount; i++) {
2c0af7
+		unsigned int rsa_algorithms = 0;
2c0af7
+		unsigned int digest_algorithms = 0;
2c0af7
 		slot = slotList[i];
2c0af7
 
2c0af7
 		rv = pkcs_C_GetTokenInfo(slot, &tokenInfo);
2c0af7
@@ -708,8 +728,11 @@ choose_slots(void) {
2c0af7
 					     &mechInfo);
2c0af7
 		if ((rv != CKR_OK) ||
2c0af7
 		    ((mechInfo.flags & CKF_SIGN) == 0) ||
2c0af7
-		    ((mechInfo.flags & CKF_VERIFY) == 0))
2c0af7
-			goto try_dsa;
2c0af7
+		    ((mechInfo.flags & CKF_VERIFY) == 0)) {
2c0af7
+			PK11_TRACEM(CKM_MD5_RSA_PKCS);
2c0af7
+		}
2c0af7
+		else
2c0af7
+			++rsa_algorithms;
2c0af7
 		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA1_RSA_PKCS,
2c0af7
 					     &mechInfo);
2c0af7
 		if ((rv != CKR_OK) ||
2c0af7
@@ -729,8 +752,14 @@ choose_slots(void) {
2c0af7
 		    ((mechInfo.flags & CKF_VERIFY) == 0))
2c0af7
 			goto try_dsa;
2c0af7
 		token->operations |= 1 << OP_RSA;
2c0af7
-		if (best_rsa_token == NULL)
2c0af7
+		if (best_rsa_token == NULL) {
2c0af7
 			best_rsa_token = token;
2c0af7
+			best_rsa_algorithms = rsa_algorithms;
2c0af7
+		} else if (rsa_algorithms > best_rsa_algorithms) {
2c0af7
+			pk11_mem_put(best_rsa_token, sizeof(*best_rsa_token));
2c0af7
+			best_rsa_token = token;
2c0af7
+			best_rsa_algorithms = rsa_algorithms;
2c0af7
+		}
2c0af7
 
2c0af7
 	try_dsa:
2c0af7
 		rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_PARAMETER_GEN,
2c0af7
@@ -773,8 +802,11 @@ choose_slots(void) {
2c0af7
 
2c0af7
 	try_digest:
2c0af7
 		rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5, &mechInfo);
2c0af7
-		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
2c0af7
-			continue;
2c0af7
+		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) {
2c0af7
+			PK11_TRACEM(CKM_MD5);
2c0af7
+		}
2c0af7
+		else
2c0af7
+			++digest_algorithms;
2c0af7
 		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA_1, &mechInfo);
2c0af7
 		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
2c0af7
 			continue;
2c0af7
@@ -792,13 +824,15 @@ choose_slots(void) {
2c0af7
 			continue;
2c0af7
 #ifdef PKCS11CRYPTOWITHHMAC
2c0af7
 		rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5_HMAC, &mechInfo);
2c0af7
-		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
2c0af7
-			continue;
2c0af7
+		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) {
2c0af7
+			PK11_TRACEM(CKM_MD5_HMAC);
2c0af7
+		}
2c0af7
+		else
2c0af7
+			++digest_algorithms;
2c0af7
 #endif
2c0af7
 		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA_1_HMAC, &mechInfo);
2c0af7
 		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
2c0af7
 			continue;
2c0af7
-		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA224_HMAC, &mechInfo);
2c0af7
 		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
2c0af7
 			continue;
2c0af7
 		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256_HMAC, &mechInfo);
2c0af7
@@ -811,8 +845,14 @@ choose_slots(void) {
2c0af7
 		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
2c0af7
 			continue;
2c0af7
 		token->operations |= 1 << OP_DIGEST;
2c0af7
-		if (digest_token == NULL)
2c0af7
-			digest_token = token;
2c0af7
+			if (digest_token == NULL) {
2c0af7
+				digest_token = token;
2c0af7
+				best_digest_algorithms = digest_algorithms;
2c0af7
+			} else if (digest_algorithms > best_digest_algorithms) {
2c0af7
+				pk11_mem_put(digest_token, sizeof(*digest_token));
2c0af7
+				digest_token = token;
2c0af7
+				best_digest_algorithms = digest_algorithms;
2c0af7
+			}
2c0af7
 
2c0af7
 		/* ECDSA requires digest */
2c0af7
 		rv = pkcs_C_GetMechanismInfo(slot, CKM_EC_KEY_PAIR_GEN,
2c0af7
diff --git a/lib/isccc/cc.c b/lib/isccc/cc.c
2c0af7
index 9428374cc1..ca3cff27c9 100644
2c0af7
--- a/lib/isccc/cc.c
2c0af7
+++ b/lib/isccc/cc.c
2c0af7
@@ -254,11 +254,15 @@ sign(unsigned char *data, unsigned int length, unsigned char *hmac,
2c0af7
 
2c0af7
 	switch (algorithm) {
2c0af7
 	case ISCCC_ALG_HMACMD5:
2c0af7
-		isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
2c0af7
-				 REGION_SIZE(*secret));
2c0af7
-		isc_hmacmd5_update(&ctx.hmd5, data, length);
2c0af7
-		isc_hmacmd5_sign(&ctx.hmd5, digest);
2c0af7
-		source.rend = digest + ISC_MD5_DIGESTLENGTH;
2c0af7
+		if (isc_md5_available()) {
2c0af7
+			isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
2c0af7
+					 REGION_SIZE(*secret));
2c0af7
+			isc_hmacmd5_update(&ctx.hmd5, data, length);
2c0af7
+			isc_hmacmd5_sign(&ctx.hmd5, digest);
2c0af7
+			source.rend = digest + ISC_MD5_DIGESTLENGTH;
2c0af7
+		} else {
2c0af7
+			return (ISC_R_FAILURE);
2c0af7
+		}
2c0af7
 		break;
2c0af7
 
2c0af7
 	case ISCCC_ALG_HMACSHA1:
2c0af7
@@ -329,14 +333,14 @@ isccc_cc_towire(isccc_sexpr_t *alist, isccc_region_t *target,
2c0af7
 {
2c0af7
 	unsigned char *hmac_rstart, *signed_rstart;
2c0af7
 	isc_result_t result;
2c0af7
+	const isc_boolean_t md5 = ISC_TF(algorithm == ISCCC_ALG_HMACMD5);
2c0af7
 
2c0af7
-	if (algorithm == ISCCC_ALG_HMACMD5) {
2c0af7
-		if (REGION_SIZE(*target) < 4 + sizeof(auth_hmd5))
2c0af7
-			return (ISC_R_NOSPACE);
2c0af7
-	} else {
2c0af7
-		if (REGION_SIZE(*target) < 4 + sizeof(auth_hsha))
2c0af7
-			return (ISC_R_NOSPACE);
2c0af7
-	}
2c0af7
+	if (md5 && isc_md5_available() == ISC_FALSE)
2c0af7
+		return (ISC_R_NOTIMPLEMENTED);
2c0af7
+	if (REGION_SIZE(*target) < 4 + ((md5) ?
2c0af7
+				 sizeof(auth_hmd5) :
2c0af7
+				 sizeof(auth_hsha)))
2c0af7
+		return (ISC_R_NOSPACE);
2c0af7
 
2c0af7
 	/*
2c0af7
 	 * Emit protocol version.
2c0af7
@@ -348,7 +352,7 @@ isccc_cc_towire(isccc_sexpr_t *alist, isccc_region_t *target,
2c0af7
 		 * We'll replace the zeros with the real signature once
2c0af7
 		 * we know what it is.
2c0af7
 		 */
2c0af7
-		if (algorithm == ISCCC_ALG_HMACMD5) {
2c0af7
+		if (md5) {
2c0af7
 			hmac_rstart = target->rstart + HMD5_OFFSET;
2c0af7
 			PUT_MEM(auth_hmd5, sizeof(auth_hmd5), target->rstart);
2c0af7
 		} else {
2c0af7
@@ -404,7 +408,7 @@ verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length,
2c0af7
 	_auth = isccc_alist_lookup(alist, "_auth");
2c0af7
 	if (!isccc_alist_alistp(_auth))
2c0af7
 		return (ISC_R_FAILURE);
2c0af7
-	if (algorithm == ISCCC_ALG_HMACMD5)
2c0af7
+	if (algorithm == ISCCC_ALG_HMACMD5 && isc_md5_available())
2c0af7
 		hmac = isccc_alist_lookup(_auth, "hmd5");
2c0af7
 	else
2c0af7
 		hmac = isccc_alist_lookup(_auth, "hsha");
2c0af7
@@ -417,12 +421,16 @@ verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length,
2c0af7
 	target.rstart = digestb64;
2c0af7
 	switch (algorithm) {
2c0af7
 	case ISCCC_ALG_HMACMD5:
2c0af7
-		isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
2c0af7
-				 REGION_SIZE(*secret));
2c0af7
-		isc_hmacmd5_update(&ctx.hmd5, data, length);
2c0af7
-		isc_hmacmd5_sign(&ctx.hmd5, digest);
2c0af7
-		source.rend = digest + ISC_MD5_DIGESTLENGTH;
2c0af7
-		break;
2c0af7
+		if (isc_md5_available()) {
2c0af7
+			isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
2c0af7
+					 REGION_SIZE(*secret));
2c0af7
+			isc_hmacmd5_update(&ctx.hmd5, data, length);
2c0af7
+			isc_hmacmd5_sign(&ctx.hmd5, digest);
2c0af7
+			source.rend = digest + ISC_MD5_DIGESTLENGTH;
2c0af7
+			break;
2c0af7
+		} else {
2c0af7
+			return (ISC_R_FAILURE);
2c0af7
+		}
2c0af7
 
2c0af7
 	case ISCCC_ALG_HMACSHA1:
2c0af7
 		isc_hmacsha1_init(&ctx.hsha, secret->rstart,
2c0af7
-- 
2c0af7
2.14.4
2c0af7