diff --git a/.bind.metadata b/.bind.metadata
index 519659e..5e29fe2 100644
--- a/.bind.metadata
+++ b/.bind.metadata
@@ -1,2 +1,2 @@
 d7be390e6c2546f37a7280e1975e1cd134565f62 SOURCES/bind-9.9.4.tar.gz
-8f72710c243b713ba56930e0348cd0157716574e SOURCES/config-12.tar.bz2
+3320c2bd77776079111603b7d266cc7ce7dcbd28 SOURCES/config-13.tar.bz2
diff --git a/.gitignore b/.gitignore
index f21f248..800c33e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
 SOURCES/bind-9.9.4.tar.gz
-SOURCES/config-12.tar.bz2
+SOURCES/config-13.tar.bz2
diff --git a/SOURCES/bind-9.3.2-redhat_doc.patch b/SOURCES/bind-9.3.2-redhat_doc.patch
index 791b95f..6aafac2 100644
--- a/SOURCES/bind-9.3.2-redhat_doc.patch
+++ b/SOURCES/bind-9.3.2-redhat_doc.patch
@@ -1,6 +1,6 @@
 --- bind-9.4.0/bin/named/named.8.redhat_doc	2007-01-30 01:23:44.000000000 +0100
 +++ bind-9.4.0/bin/named/named.8	2007-03-12 15:39:19.000000000 +0100
-@@ -205,6 +205,63 @@
+@@ -205,6 +205,57 @@
  \fI/var/run/named/named.pid\fR
  .RS 4
  The default process\-id file.
@@ -55,12 +55,6 @@
 +See the documentation for the various SDB modules in /usr/share/doc/bind-sdb-*/ .
 +.br
 +.PP
-+\fBRed Hat system-config-bind:\fR
-+.PP
-+Red Hat provides the system-config-bind GUI to configure named.conf and zone
-+database files. Run the "system-config-bind" command and access the manual
-+by selecting the Help menu.
-+.PP
  .RE
  .SH "SEE ALSO"
  .PP
diff --git a/SOURCES/bind-9.5-sdb.patch b/SOURCES/bind-9.5-sdb.patch
index 270ec9e..99475e6 100644
--- a/SOURCES/bind-9.5-sdb.patch
+++ b/SOURCES/bind-9.5-sdb.patch
@@ -1,30 +1,30 @@
-diff -up bind-9.9.3rc1/bin/Makefile.in.sdb bind-9.9.3rc1/bin/Makefile.in
---- bind-9.9.3rc1/bin/Makefile.in.sdb	2013-04-05 00:21:21.000000000 +0200
-+++ bind-9.9.3rc1/bin/Makefile.in	2013-04-16 15:21:22.286944331 +0200
+diff -up bind-9.9.4-P2/bin/Makefile.in.sdb bind-9.9.4-P2/bin/Makefile.in
+--- bind-9.9.4-P2/bin/Makefile.in.sdb	2013-12-20 01:28:28.000000000 +0100
++++ bind-9.9.4-P2/bin/Makefile.in	2014-07-22 10:29:23.940233449 +0200
 @@ -19,8 +19,8 @@ srcdir =	@srcdir@
  VPATH =		@srcdir@
  top_srcdir =	@top_srcdir@
  
--SUBDIRS =	named rndc dig dnssec tools tests nsupdate \
+-SUBDIRS =	named named-pkcs11 rndc dig dnssec dnssec-pkcs11 tools tests nsupdate \
 -		check confgen @PYTHON_TOOLS@ @PKCS11_TOOLS@
-+SUBDIRS =	named named-sdb rndc dig dnssec tools tests nsupdate \
++SUBDIRS =	named named-pkcs11 named-sdb rndc dig dnssec dnssec-pkcs11 tools tests nsupdate \
 +		check confgen @PYTHON_TOOLS@ @PKCS11_TOOLS@ sdb_tools
  TARGETS =
  
  @BIND9_MAKE_RULES@
-diff -up bind-9.9.3rc1/bin/named/Makefile.in.sdb bind-9.9.3rc1/bin/named/Makefile.in
---- bind-9.9.3rc1/bin/named/Makefile.in.sdb	2013-04-16 15:21:22.102944727 +0200
-+++ bind-9.9.3rc1/bin/named/Makefile.in	2013-04-16 15:21:22.286944331 +0200
-@@ -49,7 +49,7 @@ CINCLUDES =	-I${srcdir}/include -I${srcd
+diff -up bind-9.9.4-P2/bin/named/Makefile.in.sdb bind-9.9.4-P2/bin/named/Makefile.in
+--- bind-9.9.4-P2/bin/named/Makefile.in.sdb	2014-07-22 10:29:23.873233351 +0200
++++ bind-9.9.4-P2/bin/named/Makefile.in	2014-07-22 10:30:43.247348398 +0200
+@@ -52,7 +52,7 @@ CINCLUDES =	-I${srcdir}/include -I${srcd
  		${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} \
  		${DLZDRIVER_INCLUDES} ${DBDRIVER_INCLUDES} @DST_OPENSSL_INC@
  
--CDEFINES =      @CONTRIB_DLZ@ @USE_PKCS11@ @USE_OPENSSL@
-+CDEFINES =      @USE_PKCS11@ @USE_OPENSSL@
+-CDEFINES =      @CONTRIB_DLZ@ @CRYPTO@
++CDEFINES =      @CRYPTO@
  
  CWARNINGS =
  
-@@ -73,11 +73,11 @@ DEPLIBS =	${LWRESDEPLIBS} ${DNSDEPLIBS}
+@@ -79,11 +79,11 @@ DEPLIBS =	${LWRESDEPLIBS} ${DNSDEPLIBS}
  
  LIBS =		${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \
  		${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} \
@@ -38,7 +38,7 @@ diff -up bind-9.9.3rc1/bin/named/Makefile.in.sdb bind-9.9.3rc1/bin/named/Makefil
  
  SUBDIRS =	unix
  
-@@ -90,8 +90,7 @@ OBJS =		builtin.@O@ client.@O@ config.@O
+@@ -96,8 +96,7 @@ OBJS =		builtin.@O@ client.@O@ config.@O
  		tkeyconf.@O@ tsigconf.@O@ update.@O@ xfrout.@O@ \
  		zoneconf.@O@ \
  		lwaddr.@O@ lwresd.@O@ lwdclient.@O@ lwderror.@O@ lwdgabn.@O@ \
@@ -48,7 +48,7 @@ diff -up bind-9.9.3rc1/bin/named/Makefile.in.sdb bind-9.9.3rc1/bin/named/Makefil
  
  UOBJS =		unix/os.@O@ unix/dlz_dlopen_driver.@O@
  
-@@ -104,8 +103,7 @@ SRCS =		builtin.c client.c config.c cont
+@@ -110,8 +109,7 @@ SRCS =		builtin.c client.c config.c cont
  		tkeyconf.c tsigconf.c update.c xfrout.c \
  		zoneconf.c \
  		lwaddr.c lwresd.c lwdclient.c lwderror.c lwdgabn.c \
@@ -58,7 +58,7 @@ diff -up bind-9.9.3rc1/bin/named/Makefile.in.sdb bind-9.9.3rc1/bin/named/Makefil
  
  MANPAGES =	named.8 lwresd.8 named.conf.5
  
-@@ -180,7 +178,5 @@ install:: named@EXEEXT@ lwresd@EXEEXT@ i
+@@ -187,7 +185,5 @@ install:: named@EXEEXT@ lwresd@EXEEXT@ i
  	${INSTALL_DATA} ${srcdir}/lwresd.8 ${DESTDIR}${mandir}/man8
  	${INSTALL_DATA} ${srcdir}/named.conf.5 ${DESTDIR}${mandir}/man5
  
@@ -66,9 +66,9 @@ diff -up bind-9.9.3rc1/bin/named/Makefile.in.sdb bind-9.9.3rc1/bin/named/Makefil
 -
  named-symtbl.@O@: named-symtbl.c
  	${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c named-symtbl.c
-diff -up bind-9.9.3rc1/bin/named-sdb/main.c.sdb bind-9.9.3rc1/bin/named-sdb/main.c
---- bind-9.9.3rc1/bin/named-sdb/main.c.sdb	2013-04-16 15:21:22.249944411 +0200
-+++ bind-9.9.3rc1/bin/named-sdb/main.c	2013-04-16 15:21:22.287944329 +0200
+diff -up bind-9.9.4-P2/bin/named-sdb/main.c.sdb bind-9.9.4-P2/bin/named-sdb/main.c
+--- bind-9.9.4-P2/bin/named-sdb/main.c.sdb	2014-07-22 10:29:23.919233417 +0200
++++ bind-9.9.4-P2/bin/named-sdb/main.c	2014-07-22 10:29:23.940233449 +0200
 @@ -83,6 +83,9 @@
   * Include header files for database drivers here.
   */
@@ -79,7 +79,7 @@ diff -up bind-9.9.3rc1/bin/named-sdb/main.c.sdb bind-9.9.3rc1/bin/named-sdb/main
  
  #ifdef CONTRIB_DLZ
  /*
-@@ -808,6 +811,10 @@ setup(void) {
+@@ -814,6 +817,10 @@ setup(void) {
  		ns_main_earlyfatal("isc_app_start() failed: %s",
  				   isc_result_totext(result));
  
@@ -90,7 +90,7 @@ diff -up bind-9.9.3rc1/bin/named-sdb/main.c.sdb bind-9.9.3rc1/bin/named-sdb/main
  	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
  		      ISC_LOG_NOTICE, "starting %s %s%s", ns_g_product,
  		      ns_g_version, saved_command_line);
-@@ -920,6 +927,57 @@ setup(void) {
+@@ -926,6 +933,57 @@ setup(void) {
  				   isc_result_totext(result));
  #endif
  
@@ -148,7 +148,7 @@ diff -up bind-9.9.3rc1/bin/named-sdb/main.c.sdb bind-9.9.3rc1/bin/named-sdb/main
  	ns_server_create(ns_g_mctx, &ns_g_server);
  }
  
-@@ -951,6 +1009,10 @@ cleanup(void) {
+@@ -957,6 +1015,10 @@ cleanup(void) {
  
  	dns_name_destroy();
  
@@ -159,10 +159,10 @@ diff -up bind-9.9.3rc1/bin/named-sdb/main.c.sdb bind-9.9.3rc1/bin/named-sdb/main
  	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
  		      ISC_LOG_NOTICE, "exiting");
  	ns_log_shutdown();
-diff -up bind-9.9.3rc1/bin/named-sdb/Makefile.in.sdb bind-9.9.3rc1/bin/named-sdb/Makefile.in
---- bind-9.9.3rc1/bin/named-sdb/Makefile.in.sdb	2013-04-16 15:21:22.243944424 +0200
-+++ bind-9.9.3rc1/bin/named-sdb/Makefile.in	2013-04-16 15:21:22.287944329 +0200
-@@ -32,10 +32,10 @@ top_srcdir =	@top_srcdir@
+diff -up bind-9.9.4-P2/bin/named-sdb/Makefile.in.sdb bind-9.9.4-P2/bin/named-sdb/Makefile.in
+--- bind-9.9.4-P2/bin/named-sdb/Makefile.in.sdb	2014-07-22 10:29:23.917233415 +0200
++++ bind-9.9.4-P2/bin/named-sdb/Makefile.in	2014-07-22 10:29:23.941233449 +0200
+@@ -34,10 +34,10 @@ top_srcdir =	@top_srcdir@
  #
  # Add database drivers here.
  #
@@ -176,7 +176,7 @@ diff -up bind-9.9.3rc1/bin/named-sdb/Makefile.in.sdb bind-9.9.3rc1/bin/named-sdb
  
  DLZ_DRIVER_DIR =	${top_srcdir}/contrib/dlz/drivers
  
-@@ -81,7 +81,7 @@ NOSYMLIBS =	${LWRESLIBS} ${DNSLIBS} ${BI
+@@ -87,7 +87,7 @@ NOSYMLIBS =	${LWRESLIBS} ${DNSLIBS} ${BI
  
  SUBDIRS =	unix
  
@@ -185,7 +185,7 @@ diff -up bind-9.9.3rc1/bin/named-sdb/Makefile.in.sdb bind-9.9.3rc1/bin/named-sdb
  
  OBJS =		builtin.@O@ client.@O@ config.@O@ control.@O@ \
  		controlconf.@O@ interfacemgr.@O@ \
-@@ -139,7 +139,7 @@ config.@O@: config.c bind.keys.h
+@@ -146,7 +146,7 @@ config.@O@: config.c bind.keys.h
  		-DNS_SYSCONFDIR=\"${sysconfdir}\" \
  		-c ${srcdir}/config.c
  
@@ -194,7 +194,7 @@ diff -up bind-9.9.3rc1/bin/named-sdb/Makefile.in.sdb bind-9.9.3rc1/bin/named-sdb
  	export MAKE_SYMTABLE="yes"; \
  	export BASEOBJS="${OBJS} ${UOBJS}"; \
  	${FINALBUILDCMD}
-@@ -170,15 +170,9 @@ statschannel.@O@: bind9.xsl.h bind9.ver3
+@@ -177,15 +177,9 @@ statschannel.@O@: bind9.xsl.h bind9.ver3
  
  installdirs:
  	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir}
@@ -212,12 +212,12 @@ diff -up bind-9.9.3rc1/bin/named-sdb/Makefile.in.sdb bind-9.9.3rc1/bin/named-sdb
  
  @DLZ_DRIVER_RULES@
  
-diff -up bind-9.9.3rc1/configure.in.sdb bind-9.9.3rc1/configure.in
---- bind-9.9.3rc1/configure.in.sdb	2013-04-16 15:21:22.208944499 +0200
-+++ bind-9.9.3rc1/configure.in	2013-04-16 15:21:19.395950103 +0200
-@@ -3651,12 +3651,15 @@ AC_CONFIG_FILES([
- 	bin/dnssec/Makefile
- 	bin/named/Makefile
+diff -up bind-9.9.4-P2/configure.in.sdb bind-9.9.4-P2/configure.in
+--- bind-9.9.4-P2/configure.in.sdb	2014-07-22 10:29:23.909233403 +0200
++++ bind-9.9.4-P2/configure.in	2014-07-22 10:29:23.942233450 +0200
+@@ -3900,12 +3900,15 @@ AC_CONFIG_FILES([
+ 	bin/named-pkcs11/Makefile
+ 	bin/named-pkcs11/unix/Makefile
  	bin/named/unix/Makefile
 +	bin/named-sdb/Makefile
 +	bin/named-sdb/unix/Makefile
diff --git a/SOURCES/bind-9.9-allow_external_dnskey.patch b/SOURCES/bind-9.9-allow_external_dnskey.patch
new file mode 100644
index 0000000..37b3d9f
--- /dev/null
+++ b/SOURCES/bind-9.9-allow_external_dnskey.patch
@@ -0,0 +1,1727 @@
+From 0c91911b4d1e872b87eaf6431ed47fe24d18dd43 Mon Sep 17 00:00:00 2001
+From: Mark Andrews <marka@isc.org>
+Date: Wed, 4 Sep 2013 13:53:02 +1000
+Subject: [PATCH] 3642.   [func]          Allow externally generated DNSKEY to
+ be imported                         into the DNSKEY management framework.  A
+ new tool                         dnssec-importkey is used to this. [RT
+ #34698]
+
+---
+ CHANGES                                |   4 +
+ bin/dnssec/.gitignore                  |   1 +
+ bin/dnssec/Makefile.in                 |   8 +-
+ bin/dnssec/dnssec-importkey.8          | 112 +++++++++
+ bin/dnssec/dnssec-importkey.c          | 399 +++++++++++++++++++++++++++++++++
+ bin/dnssec/dnssec-importkey.docbook    | 185 +++++++++++++++
+ bin/dnssec/dnssec-importkey.html       | 112 +++++++++
+ bin/dnssec/dnssec-settime.c            |   4 +-
+ bin/tests/system/conf.sh.in            |   1 +
+ bin/tests/system/inline/clean.sh       |   3 +
+ bin/tests/system/inline/ns1/root.db.in |   3 +
+ bin/tests/system/inline/ns3/named.conf |   8 +
+ bin/tests/system/inline/ns3/sign.sh    |  29 +++
+ bin/tests/system/inline/setup.sh       |   1 +
+ bin/tests/system/inline/tests.sh       |  17 +-
+ lib/dns/dnssec.c                       |  96 ++++----
+ lib/dns/dst_api.c                      |  10 +
+ lib/dns/dst_internal.h                 |   1 +
+ lib/dns/dst_parse.c                    |  63 ++++--
+ lib/dns/dst_result.c                   |   2 +-
+ lib/dns/include/dns/master.h           |   1 +
+ lib/dns/include/dst/dst.h              |   6 +
+ lib/dns/master.c                       |   4 +-
+ lib/dns/openssldsa_link.c              |  19 ++
+ lib/dns/opensslecdsa_link.c            |  53 +++--
+ lib/dns/opensslgost_link.c             |  27 ++-
+ lib/dns/opensslrsa_link.c              |  18 +-
+ lib/dns/zone.c                         |   4 +
+ 28 files changed, 1108 insertions(+), 83 deletions(-)
+ create mode 100644 bin/dnssec/dnssec-importkey.8
+ create mode 100644 bin/dnssec/dnssec-importkey.c
+ create mode 100644 bin/dnssec/dnssec-importkey.docbook
+ create mode 100644 bin/dnssec/dnssec-importkey.html
+
+diff --git a/bin/dnssec/Makefile.in b/bin/dnssec/Makefile.in
+index 4f8bceb..ecb0fae 100644
+--- a/bin/dnssec/Makefile.in
++++ b/bin/dnssec/Makefile.in
+@@ -45,13 +45,13 @@ NOSYMLIBS =	${DNSLIBS} ${ISCNOSYMLIBS} @LIBS@
+ TARGETS =	dnssec-keygen@EXEEXT@ dnssec-signzone@EXEEXT@ \
+ 		dnssec-keyfromlabel@EXEEXT@ dnssec-dsfromkey@EXEEXT@ \
+ 		dnssec-revoke@EXEEXT@ dnssec-settime@EXEEXT@ \
+-		dnssec-verify@EXEEXT@
++		dnssec-verify@EXEEXT@ dnssec-importkey@EXEEXT@
+ 
+ OBJS =		dnssectool.@O@
+ 
+ SRCS =		dnssec-dsfromkey.c dnssec-keyfromlabel.c dnssec-keygen.c \
+ 		dnssec-revoke.c dnssec-settime.c dnssec-signzone.c \
+-		dnssec-verify.c dnssectool.c
++		dnssec-verify.c dnssec-importkey.c dnssectool.c 
+ 
+ MANPAGES =	dnssec-dsfromkey.8 dnssec-keyfromlabel.8 dnssec-keygen.8 \
+ 		dnssec-revoke.8 dnssec-settime.8 dnssec-signzone.8 \
+@@ -102,6 +102,10 @@ dnssec-settime@EXEEXT@: dnssec-settime.@O@ ${OBJS} ${DEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ 	dnssec-settime.@O@ ${OBJS} ${LIBS}
+ 
++dnssec-importkey@EXEEXT@: dnssec-importkey.@O@ ${OBJS} ${DEPLIBS}
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
++	dnssec-importkey.@O@ ${OBJS} ${LIBS}
++
+ doc man:: ${MANOBJS}
+ 
+ docclean manclean maintainer-clean::
+diff --git a/bin/dnssec/dnssec-importkey.8 b/bin/dnssec/dnssec-importkey.8
+new file mode 100644
+index 0000000..33a3ef4
+--- /dev/null
++++ b/bin/dnssec/dnssec-importkey.8
+@@ -0,0 +1,112 @@
++.\" Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
++.\" 
++.\" Permission to use, copy, modify, and/or distribute this software for any
++.\" purpose with or without fee is hereby granted, provided that the above
++.\" copyright notice and this permission notice appear in all copies.
++.\" 
++.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++.\" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++.\" AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++.\" LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++.\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++.\" PERFORMANCE OF THIS SOFTWARE.
++.\"
++.\" $Id$
++.\"
++.hy 0
++.ad l
++'\" t
++.\"     Title: dnssec-importkey
++.\"    Author: [see the "AUTHOR" section]
++.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
++.\"      Date: August 30, 2013
++.\"    Manual: BIND9
++.\"    Source: BIND9
++.\"  Language: English
++.\"
++.TH "DNSSEC\-IMPORTKEY" "8" "August 30, 2013" "BIND9" "BIND9"
++.\" -----------------------------------------------------------------
++.\" * Define some portability stuff
++.\" -----------------------------------------------------------------
++.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++.\" http://bugs.debian.org/507673
++.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
++.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++.ie \n(.g .ds Aq \(aq
++.el       .ds Aq '
++.\" -----------------------------------------------------------------
++.\" * set default formatting
++.\" -----------------------------------------------------------------
++.\" disable hyphenation
++.nh
++.\" disable justification (adjust text to left margin only)
++.ad l
++.\" -----------------------------------------------------------------
++.\" * MAIN CONTENT STARTS HERE *
++.\" -----------------------------------------------------------------
++.SH "NAME"
++dnssec-importkey \- Import DNSKEY records from external systems so they can be managed\&.
++.SH "SYNOPSIS"
++.HP 17
++\fBdnssec\-importkey\fR [\fB\-f\ \fR\fB\fIfilename\fR\fR] [\fB\-K\ \fR\fB\fIdirectory\fR\fR] [\fB\-P\ \fR\fB\fIdate/offset\fR\fR] [\fB\-D\ \fR\fB\fIdate/offset\fR\fR] [\fB\-h\fR] [\fB\-v\ \fR\fB\fIlevel\fR\fR] [\fBkeyname\fR]
++.SH "DESCRIPTION"
++.PP
++\fBdnssec\-importkey\fR
++read a DNSKEY record and generated a \&.key/\&.private key pair\&. Publication (\fB\-P\fR) and deletions (\fB\-D\fR) times can be set for the key\&.
++.SH "OPTIONS"
++.PP
++\-f \fIfilename\fR
++.RS 4
++Filename to read the key from\&.
++.RE
++.PP
++\-K \fIdirectory\fR
++.RS 4
++Sets the directory in which the key files are to reside\&.
++.RE
++.PP
++\-L \fIttl\fR
++.RS 4
++Sets the default TTL to use for this key when it is converted into a DNSKEY RR\&. If the key is imported into a zone, this is the TTL that will be used for it, unless there was already a DNSKEY RRset in place, in which case the existing TTL would take precedence\&. importkey the default TTL to
++0
++or
++none
++removes it\&.
++.RE
++.PP
++\-h
++.RS 4
++Emit usage message and exit\&.
++.RE
++.PP
++\-v \fIlevel\fR
++.RS 4
++Sets the debugging level\&.
++.RE
++.SH "TIMING OPTIONS"
++.PP
++Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS\&. If the argument begins with a \*(Aq+\*(Aq or \*(Aq\-\*(Aq, it is interpreted as an offset from the present time\&. For convenience, if such an offset is followed by one of the suffixes \*(Aqy\*(Aq, \*(Aqmo\*(Aq, \*(Aqw\*(Aq, \*(Aqd\*(Aq, \*(Aqh\*(Aq, or \*(Aqmi\*(Aq, then the offset is computed in years (defined as 365 24\-hour days, ignoring leap years), months (defined as 30 24\-hour days), weeks, days, hours, or minutes, respectively\&. Without a suffix, the offset is computed in seconds\&. To unset a date, use \*(Aqnone\*(Aq\&.
++.PP
++\-P \fIdate/offset\fR
++.RS 4
++Sets the date on which a key is to be published to the zone\&. After that date, the key will be included in the zone but will not be used to sign it\&.
++.RE
++.PP
++\-D \fIdate/offset\fR
++.RS 4
++Sets the date on which the key is to be deleted\&. After that date, the key will no longer be included in the zone\&. (It may remain in the key repository, however\&.)
++.RE
++.SH "SEE ALSO"
++.PP
++\fBdnssec-keygen\fR(8),
++\fBdnssec-signzone\fR(8),
++BIND 9 Administrator Reference Manual,
++RFC 5011\&.
++.SH "AUTHOR"
++.PP
++Internet Systems Consortium
++.SH "COPYRIGHT"
++.br
++Copyright \(co 2013 Internet Systems Consortium, Inc. ("ISC")
++.br
+diff --git a/bin/dnssec/dnssec-importkey.c b/bin/dnssec/dnssec-importkey.c
+new file mode 100644
+index 0000000..3491828
+--- /dev/null
++++ b/bin/dnssec/dnssec-importkey.c
+@@ -0,0 +1,399 @@
++/*
++ * Copyright (C) 2008-2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*! \file */
++
++#include <config.h>
++
++#include <stdlib.h>
++
++#include <isc/buffer.h>
++#include <isc/commandline.h>
++#include <isc/entropy.h>
++#include <isc/hash.h>
++#include <isc/mem.h>
++#include <isc/print.h>
++#include <isc/string.h>
++#include <isc/util.h>
++
++#include <dns/callbacks.h>
++#include <dns/db.h>
++#include <dns/dbiterator.h>
++#include <dns/ds.h>
++#include <dns/fixedname.h>
++#include <dns/keyvalues.h>
++#include <dns/log.h>
++#include <dns/master.h>
++#include <dns/name.h>
++#include <dns/rdata.h>
++#include <dns/rdataclass.h>
++#include <dns/rdataset.h>
++#include <dns/rdatasetiter.h>
++#include <dns/rdatatype.h>
++#include <dns/result.h>
++
++#include <dst/dst.h>
++
++#include "dnssectool.h"
++
++#ifndef PATH_MAX
++#define PATH_MAX 1024   /* AIX, WIN32, and others don't define this. */
++#endif
++
++const char *program = "dnssec-importkey";
++int verbose;
++
++static dns_rdataclass_t rdclass;
++static dns_fixedname_t	fixed;
++static dns_name_t	*name = NULL;
++static isc_mem_t	*mctx = NULL;
++static isc_boolean_t	setpub = ISC_FALSE, setdel = ISC_FALSE;
++static isc_stdtime_t	pub = 0, del = 0;
++
++static isc_result_t
++initname(char *setname) {
++	isc_result_t result;
++	isc_buffer_t buf;
++
++	dns_fixedname_init(&fixed);
++	name = dns_fixedname_name(&fixed);
++
++	isc_buffer_init(&buf, setname, strlen(setname));
++	isc_buffer_add(&buf, strlen(setname));
++	result = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL);
++	return (result);
++}
++
++static void
++db_load_from_stream(dns_db_t *db, FILE *fp) {
++	isc_result_t result;
++	dns_rdatacallbacks_t callbacks;
++
++	dns_rdatacallbacks_init(&callbacks);
++	result = dns_db_beginload(db, &callbacks.add, &callbacks.add_private);
++	if (result != ISC_R_SUCCESS)
++		fatal("dns_db_beginload failed: %s", isc_result_totext(result));
++
++	result = dns_master_loadstream(fp, name, name, rdclass, 0,
++				       &callbacks, mctx);
++	if (result != ISC_R_SUCCESS)
++		fatal("can't load from input: %s", isc_result_totext(result));
++
++	result = dns_db_endload(db, &callbacks.add_private);
++	if (result != ISC_R_SUCCESS)
++		fatal("dns_db_endload failed: %s", isc_result_totext(result));
++}
++
++static isc_result_t
++loadset(const char *filename, dns_rdataset_t *rdataset) {
++	isc_result_t	 result;
++	dns_db_t	 *db = NULL;
++	dns_dbnode_t	 *node = NULL;
++	char setname[DNS_NAME_FORMATSIZE];
++
++	dns_name_format(name, setname, sizeof(setname));
++
++	result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone,
++			       rdclass, 0, NULL, &db);
++	if (result != ISC_R_SUCCESS)
++		fatal("can't create database");
++
++	if (strcmp(filename, "-") == 0) {
++		db_load_from_stream(db, stdin);
++		filename = "input";
++	} else {
++		result = dns_db_load3(db, filename, dns_masterformat_text,
++				      DNS_MASTER_NOTTL);
++		if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
++			fatal("can't load %s: %s", filename,
++			      isc_result_totext(result));
++	}
++
++	result = dns_db_findnode(db, name, ISC_FALSE, &node);
++	if (result != ISC_R_SUCCESS)
++		fatal("can't find %s node in %s", setname, filename);
++
++	result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey,
++				     0, 0, rdataset, NULL);
++
++	if (result == ISC_R_NOTFOUND)
++		fatal("no DNSKEY RR for %s in %s", setname, filename);
++	else if (result != ISC_R_SUCCESS)
++		fatal("dns_db_findrdataset");
++
++	if (node != NULL)
++		dns_db_detachnode(db, &node);
++	if (db != NULL)
++		dns_db_detach(&db);
++	return (result);
++}
++
++static void
++loadkey(char *filename, unsigned char *key_buf, unsigned int key_buf_size,
++	dns_rdata_t *rdata)
++{
++	isc_result_t  result;
++	dst_key_t     *key = NULL;
++	isc_buffer_t  keyb;
++	isc_region_t  r;
++
++	dns_rdata_init(rdata);
++
++	isc_buffer_init(&keyb, key_buf, key_buf_size);
++
++	result = dst_key_fromnamedfile(filename, NULL, DST_TYPE_PUBLIC,
++				       mctx, &key);
++	if (result != ISC_R_SUCCESS)
++		fatal("invalid keyfile name %s: %s",
++		      filename, isc_result_totext(result));
++
++	if (verbose > 2) {
++		char keystr[DST_KEY_FORMATSIZE];
++
++		dst_key_format(key, keystr, sizeof(keystr));
++		fprintf(stderr, "%s: %s\n", program, keystr);
++	}
++
++	result = dst_key_todns(key, &keyb);
++	if (result != ISC_R_SUCCESS)
++		fatal("can't decode key");
++
++	isc_buffer_usedregion(&keyb, &r);
++	dns_rdata_fromregion(rdata, dst_key_class(key),
++			     dns_rdatatype_dnskey, &r);
++
++	rdclass = dst_key_class(key);
++
++	dns_fixedname_init(&fixed);
++	name = dns_fixedname_name(&fixed);
++	result = dns_name_copy(dst_key_name(key), name, NULL);
++	if (result != ISC_R_SUCCESS)
++		fatal("can't copy name");
++
++	dst_key_free(&key);
++}
++
++static void
++emit(const char *dir, dns_rdata_t *rdata) {
++	isc_result_t result;
++	char keystr[DST_KEY_FORMATSIZE];
++	char newname[1024];
++	isc_buffer_t buf;
++	dst_key_t *key = NULL;
++
++	isc_buffer_init(&buf, rdata->data, rdata->length);
++	isc_buffer_add(&buf, rdata->length);
++	result = dst_key_fromdns(name, rdclass, &buf, mctx, &key);
++	if (result != ISC_R_SUCCESS) {
++		fatal("dst_key_fromdns: %s", isc_result_totext(result));
++	}
++
++	dst_key_setexternal(key, ISC_TRUE);
++	if (setpub)
++		dst_key_settime(key, DST_TIME_PUBLISH, pub);
++	if (setdel)
++		dst_key_settime(key, DST_TIME_DELETE, del);
++
++	isc_buffer_init(&buf, newname, sizeof(newname));
++	result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf);
++	if (result != ISC_R_SUCCESS) {
++		fatal("Failed to build public key filename: %s",
++		      isc_result_totext(result));
++	}
++
++	result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
++				dir);
++	if (result != ISC_R_SUCCESS) {
++		dst_key_format(key, keystr, sizeof(keystr));
++		fatal("Failed to write key %s: %s", keystr,
++		      isc_result_totext(result));
++	}
++
++	printf("%s\n", newname);
++
++	isc_buffer_clear(&buf);
++	result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf);
++	if (result != ISC_R_SUCCESS) {
++		fatal("Failed to build private key filename: %s",
++		      isc_result_totext(result));
++	}
++	printf("%s\n", newname);
++	dst_key_free(&key);
++}
++
++ISC_PLATFORM_NORETURN_PRE static void
++usage(void) ISC_PLATFORM_NORETURN_POST;
++
++static void
++usage(void) {
++	fprintf(stderr, "Usage:\n");
++	fprintf(stderr,	"    %s options [-K dir] file\n\n", program);
++	fprintf(stderr, "Version: %s\n", VERSION);
++	fprintf(stderr, "Options:\n");
++	fprintf(stderr, "    -v <verbose level>\n");
++	fprintf(stderr, "    -K <directory>: directory in which to store "
++			"the keyset files\n");
++	fprintf(stderr, "    -f file: read keyset from zone file\n");
++
++	exit (-1);
++}
++
++int
++main(int argc, char **argv) {
++	char		*classname = NULL;
++	char		*filename = NULL, *dir = NULL, *namestr;
++	char		*endp;
++	int		ch;
++	isc_result_t	result;
++	isc_log_t	*log = NULL;
++	isc_entropy_t	*ectx = NULL;
++	dns_rdataset_t	rdataset;
++	dns_rdata_t	rdata;
++	isc_stdtime_t   now;
++
++	dns_rdata_init(&rdata);
++	isc_stdtime_get(&now);
++
++	if (argc == 1)
++		usage();
++
++	result = isc_mem_create(0, 0, &mctx);
++	if (result != ISC_R_SUCCESS)
++		fatal("out of memory");
++
++	dns_result_register();
++
++	isc_commandline_errprint = ISC_FALSE;
++
++	while ((ch = isc_commandline_parse(argc, argv, "D:f:hK:P:v:")) != -1) {
++		switch (ch) {
++                case 'D':
++                        if (setdel)
++                                fatal("-D specified more than once");
++
++			setdel = ISC_TRUE;
++			del = strtotime(isc_commandline_argument, now, now);
++			break;
++		case 'K':
++			dir = isc_commandline_argument;
++			if (strlen(dir) == 0U)
++				fatal("directory must be non-empty string");
++			break;
++                case 'P':
++                        if (setpub)
++                                fatal("-P specified more than once");
++
++			setpub = ISC_TRUE;
++			pub = strtotime(isc_commandline_argument, now, now);
++                        break;
++		case 'f':
++			filename = isc_commandline_argument;
++			break;
++		case 'v':
++			verbose = strtol(isc_commandline_argument, &endp, 0);
++			if (*endp != '\0')
++				fatal("-v must be followed by a number");
++			break;
++		case '?':
++			if (isc_commandline_option != '?')
++				fprintf(stderr, "%s: invalid argument -%c\n",
++					program, isc_commandline_option);
++			/* FALLTHROUGH */
++		case 'h':
++			usage();
++
++		default:
++			fprintf(stderr, "%s: unhandled option -%c\n",
++				program, isc_commandline_option);
++			exit(1);
++		}
++	}
++
++	rdclass = strtoclass(classname);
++
++	if (argc < isc_commandline_index + 1 && filename == NULL)
++		fatal("the key file name was not specified");
++	if (argc > isc_commandline_index + 1)
++		fatal("extraneous arguments");
++
++	if (ectx == NULL)
++		setup_entropy(mctx, NULL, &ectx);
++	result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
++	if (result != ISC_R_SUCCESS)
++		fatal("could not initialize hash");
++	result = dst_lib_init(mctx, ectx,
++			      ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY);
++	if (result != ISC_R_SUCCESS)
++		fatal("could not initialize dst: %s",
++		      isc_result_totext(result));
++	isc_entropy_stopcallbacksources(ectx);
++
++	setup_logging(verbose, mctx, &log);
++
++	dns_rdataset_init(&rdataset);
++
++	if (filename != NULL) {
++		if (argc < isc_commandline_index + 1 && filename != NULL) {
++			/* using zone name as the zone file name */
++			namestr = filename;
++		} else
++			namestr = argv[isc_commandline_index];
++
++		result = initname(namestr);
++		if (result != ISC_R_SUCCESS)
++			fatal("could not initialize name %s", namestr);
++
++		result = loadset(filename, &rdataset);
++
++		if (result != ISC_R_SUCCESS)
++			fatal("could not load DNSKEY set: %s\n",
++			      isc_result_totext(result));
++
++		for (result = dns_rdataset_first(&rdataset);
++		     result == ISC_R_SUCCESS;
++		     result = dns_rdataset_next(&rdataset)) {
++
++			dns_rdata_init(&rdata);
++			dns_rdataset_current(&rdataset, &rdata);
++			emit(dir, &rdata);
++		}
++	} else {
++		unsigned char key_buf[DST_KEY_MAXSIZE];
++
++		loadkey(argv[isc_commandline_index], key_buf,
++			DST_KEY_MAXSIZE, &rdata);
++
++		emit(dir, &rdata);
++	}
++
++	if (dns_rdataset_isassociated(&rdataset))
++		dns_rdataset_disassociate(&rdataset);
++	cleanup_logging(&log);
++	dst_lib_destroy();
++	isc_hash_destroy();
++	cleanup_entropy(&ectx);
++	dns_name_destroy();
++	if (verbose > 10)
++		isc_mem_stats(mctx, stdout);
++	isc_mem_destroy(&mctx);
++
++	fflush(stdout);
++	if (ferror(stdout)) {
++		fprintf(stderr, "write error\n");
++		return (1);
++	} else
++		return (0);
++}
+diff --git a/bin/dnssec/dnssec-importkey.docbook b/bin/dnssec/dnssec-importkey.docbook
+new file mode 100644
+index 0000000..b8d160c
+--- /dev/null
++++ b/bin/dnssec/dnssec-importkey.docbook
+@@ -0,0 +1,185 @@
++<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++               "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
++               [<!ENTITY mdash "&#8212;">]>
++<!--
++ - Copyright (C) 2009-2011  Internet Systems Consortium, Inc. ("ISC")
++ -
++ - Permission to use, copy, modify, and/or distribute this software for any
++ - purpose with or without fee is hereby granted, provided that the above
++ - copyright notice and this permission notice appear in all copies.
++ -
++ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ - AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ - PERFORMANCE OF THIS SOFTWARE.
++-->
++
++<!-- $Id: dnssec-importkey.docbook,v 1.15 2011/11/03 20:21:37 each Exp $ -->
++<refentry id="man.dnssec-importkey">
++  <refentryinfo>
++    <date>August 30, 2013</date>
++  </refentryinfo>
++
++  <refmeta>
++    <refentrytitle><application>dnssec-importkey</application></refentrytitle>
++    <manvolnum>8</manvolnum>
++    <refmiscinfo>BIND9</refmiscinfo>
++  </refmeta>
++
++  <refnamediv>
++    <refname><application>dnssec-importkey</application></refname>
++    <refpurpose>Import DNSKEY records from external systems so they can be managed.</refpurpose>
++  </refnamediv>
++
++  <docinfo>
++    <copyright>
++      <year>2013</year>
++      <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
++    </copyright>
++  </docinfo>
++
++  <refsynopsisdiv>
++    <cmdsynopsis>
++      <command>dnssec-importkey</command>
++      <arg><option>-f <replaceable class="parameter">filename</replaceable></option></arg>
++      <arg><option>-K <replaceable class="parameter">directory</replaceable></option></arg>
++      <arg><option>-P <replaceable class="parameter">date/offset</replaceable></option></arg>
++      <arg><option>-D <replaceable class="parameter">date/offset</replaceable></option></arg>
++      <arg><option>-h</option></arg>
++      <arg><option>-v <replaceable class="parameter">level</replaceable></option></arg>
++      <arg><option>keyname</option></arg>
++    </cmdsynopsis>
++  </refsynopsisdiv>
++
++  <refsect1>
++    <title>DESCRIPTION</title>
++    <para><command>dnssec-importkey</command>
++      read a DNSKEY record and generated a .key/.private key pair.
++      Publication (<option>-P</option>) and deletions (<option>-D</option>)
++      times can be set for the key.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>OPTIONS</title>
++
++    <variablelist>
++      <varlistentry>
++	<term>-f <replaceable class="parameter">filename</replaceable></term>
++        <listitem>
++	  <para>
++	    Filename to read the key from.
++	  </para>
++        </listitem>
++      </varlistentry>
++  
++      <varlistentry>
++        <term>-K <replaceable class="parameter">directory</replaceable></term>
++        <listitem>
++          <para>
++            Sets the directory in which the key files are to reside.
++          </para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term>-L <replaceable class="parameter">ttl</replaceable></term>
++        <listitem>
++          <para>
++            Sets the default TTL to use for this key when it is converted
++            into a DNSKEY RR.  If the key is imported into a zone,
++            this is the TTL that will be used for it, unless there was
++            already a DNSKEY RRset in place, in which case the existing TTL
++            would take precedence.  importkey the default TTL to
++            <literal>0</literal> or <literal>none</literal> removes it.
++          </para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++	<term>-h</term>
++        <listitem>
++	  <para>
++	    Emit usage message and exit.
++	  </para>
++        </listitem>
++      </varlistentry>
++  
++      <varlistentry>
++        <term>-v <replaceable class="parameter">level</replaceable></term>
++        <listitem>
++          <para>
++            Sets the debugging level.
++          </para>
++        </listitem>
++      </varlistentry>
++
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>TIMING OPTIONS</title>
++    <para>
++      Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS.
++      If the argument begins with a '+' or '-', it is interpreted as
++      an offset from the present time.  For convenience, if such an offset
++      is followed by one of the suffixes 'y', 'mo', 'w', 'd', 'h', or 'mi',
++      then the offset is computed in years (defined as 365 24-hour days,
++      ignoring leap years), months (defined as 30 24-hour days), weeks,
++      days, hours, or minutes, respectively.  Without a suffix, the offset
++      is computed in seconds.  To unset a date, use 'none'.
++    </para>
++
++    <variablelist>
++      <varlistentry>
++        <term>-P <replaceable class="parameter">date/offset</replaceable></term>
++        <listitem>
++          <para>
++            Sets the date on which a key is to be published to the zone.
++            After that date, the key will be included in the zone but will
++            not be used to sign it.
++          </para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term>-D <replaceable class="parameter">date/offset</replaceable></term>
++        <listitem>
++          <para>
++            Sets the date on which the key is to be deleted.  After that
++            date, the key will no longer be included in the zone.  (It
++            may remain in the key repository, however.)
++          </para>
++        </listitem>
++      </varlistentry>
++
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>SEE ALSO</title>
++    <para><citerefentry>
++        <refentrytitle>dnssec-keygen</refentrytitle><manvolnum>8</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++        <refentrytitle>dnssec-signzone</refentrytitle><manvolnum>8</manvolnum>
++      </citerefentry>,
++      <citetitle>BIND 9 Administrator Reference Manual</citetitle>,
++      <citetitle>RFC 5011</citetitle>.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>AUTHOR</title>
++    <para><corpauthor>Internet Systems Consortium</corpauthor>
++    </para>
++  </refsect1>
++
++</refentry><!--
++ - Local variables:
++ - mode: sgml
++ - End:
++-->
+diff --git a/bin/dnssec/dnssec-importkey.html b/bin/dnssec/dnssec-importkey.html
+new file mode 100644
+index 0000000..f74be50
+--- /dev/null
++++ b/bin/dnssec/dnssec-importkey.html
+@@ -0,0 +1,112 @@
++<!--
++ - Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
++ - 
++ - Permission to use, copy, modify, and/or distribute this software for any
++ - purpose with or without fee is hereby granted, provided that the above
++ - copyright notice and this permission notice appear in all copies.
++ - 
++ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ - PERFORMANCE OF THIS SOFTWARE.
++-->
++<!-- $Id$ -->
++<html>
++<head>
++<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
++<title>dnssec-importkey</title>
++<meta name="generator" content="DocBook XSL Stylesheets V1.78.1">
++</head>
++<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry">
++<a name="man.dnssec-importkey"></a><div class="titlepage"></div>
++<div class="refnamediv">
++<h2>Name</h2>
++<p><span class="application">dnssec-importkey</span> &#8212; Import DNSKEY records from external systems so they can be managed.</p>
++</div>
++<div class="refsynopsisdiv">
++<h2>Synopsis</h2>
++<div class="cmdsynopsis"><p><code class="command">dnssec-importkey</code>  [<code class="option">-f <em class="replaceable"><code>filename</code></em></code>] [<code class="option">-K <em class="replaceable"><code>directory</code></em></code>] [<code class="option">-P <em class="replaceable"><code>date/offset</code></em></code>] [<code class="option">-D <em class="replaceable"><code>date/offset</code></em></code>] [<code class="option">-h</code>] [<code class="option">-v <em class="replaceable"><code>level</code></em></code>] [<code class="option">keyname</code>]</p></div>
++</div>
++<div class="refsect1">
++<a name="idp5321760"></a><h2>DESCRIPTION</h2>
++<p><span class="command"><strong>dnssec-importkey</strong></span>
++      read a DNSKEY record and generated a .key/.private key pair.
++      Publication (<code class="option">-P</code>) and deletions (<code class="option">-D</code>)
++      times can be set for the key.
++    </p>
++</div>
++<div class="refsect1">
++<a name="idp5324080"></a><h2>OPTIONS</h2>
++<div class="variablelist"><dl class="variablelist">
++<dt><span class="term">-f <em class="replaceable"><code>filename</code></em></span></dt>
++<dd><p>
++	    Filename to read the key from.
++	  </p></dd>
++<dt><span class="term">-K <em class="replaceable"><code>directory</code></em></span></dt>
++<dd><p>
++            Sets the directory in which the key files are to reside.
++          </p></dd>
++<dt><span class="term">-L <em class="replaceable"><code>ttl</code></em></span></dt>
++<dd><p>
++            Sets the default TTL to use for this key when it is converted
++            into a DNSKEY RR.  If the key is imported into a zone,
++            this is the TTL that will be used for it, unless there was
++            already a DNSKEY RRset in place, in which case the existing TTL
++            would take precedence.  importkey the default TTL to
++            <code class="literal">0</code> or <code class="literal">none</code> removes it.
++          </p></dd>
++<dt><span class="term">-h</span></dt>
++<dd><p>
++	    Emit usage message and exit.
++	  </p></dd>
++<dt><span class="term">-v <em class="replaceable"><code>level</code></em></span></dt>
++<dd><p>
++            Sets the debugging level.
++          </p></dd>
++</dl></div>
++</div>
++<div class="refsect1">
++<a name="idp5336224"></a><h2>TIMING OPTIONS</h2>
++<p>
++      Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS.
++      If the argument begins with a '+' or '-', it is interpreted as
++      an offset from the present time.  For convenience, if such an offset
++      is followed by one of the suffixes 'y', 'mo', 'w', 'd', 'h', or 'mi',
++      then the offset is computed in years (defined as 365 24-hour days,
++      ignoring leap years), months (defined as 30 24-hour days), weeks,
++      days, hours, or minutes, respectively.  Without a suffix, the offset
++      is computed in seconds.  To unset a date, use 'none'.
++    </p>
++<div class="variablelist"><dl class="variablelist">
++<dt><span class="term">-P <em class="replaceable"><code>date/offset</code></em></span></dt>
++<dd><p>
++            Sets the date on which a key is to be published to the zone.
++            After that date, the key will be included in the zone but will
++            not be used to sign it.
++          </p></dd>
++<dt><span class="term">-D <em class="replaceable"><code>date/offset</code></em></span></dt>
++<dd><p>
++            Sets the date on which the key is to be deleted.  After that
++            date, the key will no longer be included in the zone.  (It
++            may remain in the key repository, however.)
++          </p></dd>
++</dl></div>
++</div>
++<div class="refsect1">
++<a name="idp5342816"></a><h2>SEE ALSO</h2>
++<p><span class="citerefentry"><span class="refentrytitle">dnssec-keygen</span>(8)</span>,
++      <span class="citerefentry"><span class="refentrytitle">dnssec-signzone</span>(8)</span>,
++      <em class="citetitle">BIND 9 Administrator Reference Manual</em>,
++      <em class="citetitle">RFC 5011</em>.
++    </p>
++</div>
++<div class="refsect1">
++<a name="idp5346704"></a><h2>AUTHOR</h2>
++<p><span class="corpauthor">Internet Systems Consortium</span>
++    </p>
++</div>
++</div></body>
++</html>
+diff --git a/bin/dnssec/dnssec-settime.c b/bin/dnssec/dnssec-settime.c
+index 4c88a07..108d803 100644
+--- a/bin/dnssec/dnssec-settime.c
++++ b/bin/dnssec/dnssec-settime.c
+@@ -370,7 +370,7 @@ main(int argc, char **argv) {
+ 		if (result != ISC_R_SUCCESS)
+ 			fatal("Invalid keyfile %s: %s",
+ 			      filename, isc_result_totext(result));
+-		if (!dst_key_isprivate(prevkey))
++		if (!dst_key_isprivate(prevkey) && !dst_key_isexternal(prevkey))
+ 			fatal("%s is not a private key", filename);
+ 
+ 		name = dst_key_name(prevkey);
+@@ -462,7 +462,7 @@ main(int argc, char **argv) {
+ 		fatal("Invalid keyfile %s: %s",
+ 		      filename, isc_result_totext(result));
+ 
+-	if (!dst_key_isprivate(key))
++	if (!dst_key_isprivate(key) && !dst_key_isexternal(key))
+ 		fatal("%s is not a private key", filename);
+ 
+ 	dst_key_format(key, keystr, sizeof(keystr));
+diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in
+index 60f22f8..b15853d 100644
+--- a/bin/tests/system/conf.sh.in
++++ b/bin/tests/system/conf.sh.in
+@@ -43,6 +43,7 @@ SIGNER=$TOP/bin/dnssec/dnssec-signzone
+ REVOKE=$TOP/bin/dnssec/dnssec-revoke
+ SETTIME=$TOP/bin/dnssec/dnssec-settime
+ DSFROMKEY=$TOP/bin/dnssec/dnssec-dsfromkey
++IMPORTKEY=$TOP/bin/dnssec/dnssec-importkey
+ CHECKDS=$TOP/bin/python/dnssec-checkds
+ COVERAGE=$TOP/bin/python/dnssec-coverage
+ CHECKZONE=$TOP/bin/check/named-checkzone
+diff --git a/bin/tests/system/inline/clean.sh b/bin/tests/system/inline/clean.sh
+index 8ef3e2c..412031a 100644
+--- a/bin/tests/system/inline/clean.sh
++++ b/bin/tests/system/inline/clean.sh
+@@ -60,6 +60,9 @@ rm -f ns3/retransfer.bk
+ rm -f ns3/retransfer.bk.jnl
+ rm -f ns3/retransfer.bk.signed
+ rm -f ns3/retransfer.bk.signed.jnl
++rm -f ns3/externalkey.db
++rm -f ns3/externalkey.db.signed
++rm -f ns3/externalkey.db.signed.jnl
+ rm -f ns4/K*
+ rm -f ns4/noixfr.db
+ rm -f ns4/noixfr.db.jnl
+diff --git a/bin/tests/system/inline/ns1/root.db.in b/bin/tests/system/inline/ns1/root.db.in
+index 8d3af51..a08db51 100644
+--- a/bin/tests/system/inline/ns1/root.db.in
++++ b/bin/tests/system/inline/ns1/root.db.in
+@@ -50,3 +50,6 @@ ns3.retransfer.		A	10.53.0.3
+ 
+ nsec3.			NS	ns3.nsec3.
+ ns3.nsec3.		A	10.53.0.3
++
++externalkey.		NS	ns3.externalkey.
++ns3.externalkey.	A	10.53.0.3
+diff --git a/bin/tests/system/inline/ns3/named.conf b/bin/tests/system/inline/ns3/named.conf
+index a17384c..7c23edd 100644
+--- a/bin/tests/system/inline/ns3/named.conf
++++ b/bin/tests/system/inline/ns3/named.conf
+@@ -103,3 +103,11 @@ zone "nsec3" {
+ 	allow-update { any; };
+ 	file "nsec3.db";
+ };
++
++zone "externalkey" {
++	type master;
++	inline-signing yes;
++	auto-dnssec maintain;
++	allow-update { any; };
++	file "externalkey.db";
++};
+diff --git a/bin/tests/system/inline/ns3/sign.sh b/bin/tests/system/inline/ns3/sign.sh
+index bbd11af..f695973 100644
+--- a/bin/tests/system/inline/ns3/sign.sh
++++ b/bin/tests/system/inline/ns3/sign.sh
+@@ -92,3 +92,32 @@ do
+ 	keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 768 -n zone $zone`
+ 	keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -n zone -f KSK $zone`
+ done
++
++zone=externalkey
++rm -f K${zone}.+*+*.key
++rm -f K${zone}.+*+*.private
++
++for alg in ECDSAP256SHA256 NSEC3RSASHA1 DSA ECCGOST
++do
++
++if test $alg = ECCGOST
++then
++	sh ../../gost/prereq.sh 2> /dev/null || continue
++fi
++
++k1=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone -f KSK $zone`
++k2=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone`
++k3=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone`
++k4=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone`
++keyname=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone`
++keyname=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone -f KSK $zone`
++$DSFROMKEY -T 1200 $keyname >> ../ns1/root.db
++rm -f ${k3}.* ${k4}.*
++
++#
++# Convert k1 and k2 in to External Keys.
++rm -f $k1.private 
++$IMPORTKEY -P now -D now+3600 -f $k1.key $zone
++rm -f $k2.private 
++$IMPORTKEY -f $k2.key $zone
++done
+diff --git a/bin/tests/system/inline/setup.sh b/bin/tests/system/inline/setup.sh
+index 9fa42ab..adee4ff 100644
+--- a/bin/tests/system/inline/setup.sh
++++ b/bin/tests/system/inline/setup.sh
+@@ -29,6 +29,7 @@ cp ns3/master.db.in ns3/dynamic.db
+ cp ns3/master.db.in ns3/updated.db
+ cp ns3/master.db.in ns3/expired.db
+ cp ns3/master.db.in ns3/nsec3.db
++cp ns3/master.db.in ns3/externalkey.db
+ 
+ touch ns4/trusted.conf
+ cp ns4/noixfr.db.in ns4/noixfr.db
+diff --git a/bin/tests/system/inline/tests.sh b/bin/tests/system/inline/tests.sh
+index 7e2e3d2..8acdee2 100644
+--- a/bin/tests/system/inline/tests.sh
++++ b/bin/tests/system/inline/tests.sh
+@@ -809,7 +809,22 @@ $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 addzone test-$zone \
+ $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 delzone test-$zone
+ done
+ 
+-if [ $ret != 0 ]; then echo "I:failed"; fi
++n=`expr $n + 1`
++echo "I:testing adding external keys to a inline zone ($n)"
++ret=0
++$DIG $DIGOPTS @10.53.0.3 -p 5300 dnskey externalkey > dig.out.ns3.test$n
++for alg in 3 7 12 13
++do
++if test $alg = 12 
++then
++	sh ../gost/prereq.sh 2>/dev/null || continue;
++fi
++
++dnskeys=`grep "IN.DNSKEY.25[67] [0-9]* $alg " dig.out.ns3.test$n | wc -l`
++rrsigs=`grep "RRSIG.DNSKEY $alg " dig.out.ns3.test$n | wc -l`
++test ${dnskeys:-0} -eq 3 || { echo "I: failed $alg (dnskeys ${dnskeys:-0})"; ret=1; }
++test ${rrsigs:-0} -eq 2 || { echo "I: failed $alg (rrsigs ${rrsigs:-0})"; ret=1; }
++done
+ status=`expr $status + $ret`
+ 
+ exit $status
+diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c
+index a1c5c69..cf97404 100644
+--- a/lib/dns/dnssec.c
++++ b/lib/dns/dnssec.c
+@@ -684,6 +684,7 @@ dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
+ 	isc_stdtime_get(&now);
+ 
+ 	*nkeys = 0;
++	memset(keys, 0, sizeof(*keys) * maxkeys);
+ 	dns_rdataset_init(&rdataset);
+ 	RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
+ 				   &rdataset, NULL));
+@@ -1312,9 +1313,9 @@ dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
+ 	isc_dir_t dir;
+ 	dns_dnsseckey_t *key = NULL;
+ 	dst_key_t *dstkey = NULL;
+-	char namebuf[DNS_NAME_FORMATSIZE], *p;
++	char namebuf[DNS_NAME_FORMATSIZE];
+ 	isc_buffer_t b;
+-	unsigned int len;
++	unsigned int len, i;
+ 	isc_stdtime_t now;
+ 
+ 	REQUIRE(keylist != NULL);
+@@ -1334,49 +1335,62 @@ dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
+ 	isc_stdtime_get(&now);
+ 
+ 	while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
+-		if (dir.entry.name[0] == 'K' &&
+-		    dir.entry.length > len + 1 &&
+-		    dir.entry.name[len + 1] == '+' &&
+-		    strncasecmp(dir.entry.name + 1, namebuf, len) == 0) {
+-			p = strrchr(dir.entry.name, '.');
+-			if (p != NULL && strcmp(p, ".private") != 0)
+-				continue;
++		if (dir.entry.name[0] != 'K' ||
++		    dir.entry.length < len + 1 ||
++		    dir.entry.name[len + 1] != '+' ||
++		    strncasecmp(dir.entry.name + 1, namebuf, len) != 0)
++			continue;
++
++		for (i = len + 1 + 1; i < dir.entry.length ; i++)
++			if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9')
++				break;
++
++		if (i == len + 1 + 1 || i >= dir.entry.length ||
++		    dir.entry.name[i] != '+')
++			continue;
++
++		for (i++ ; i < dir.entry.length ; i++)
++			if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9')
++				break;
+ 
+-			dstkey = NULL;
+-			result = dst_key_fromnamedfile(dir.entry.name,
+-						       directory,
+-						       DST_TYPE_PUBLIC |
+-						       DST_TYPE_PRIVATE,
+-						       mctx, &dstkey);
+-
+-			if (result != ISC_R_SUCCESS) {
+-				isc_log_write(dns_lctx,
+-					      DNS_LOGCATEGORY_GENERAL,
+-					      DNS_LOGMODULE_DNSSEC,
+-					      ISC_LOG_WARNING,
+-					      "dns_dnssec_findmatchingkeys: "
+-					      "error reading key file %s: %s",
+-					      dir.entry.name,
+-					      isc_result_totext(result));
++		if (strcmp(dir.entry.name + i, ".private") != 0)
+ 				continue;
+-			}
+ 
+-			RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
+-			key->source = dns_keysource_repository;
+-			get_hints(key, now);
++		dstkey = NULL;
++		result = dst_key_fromnamedfile(dir.entry.name,
++					       directory,
++					       DST_TYPE_PUBLIC |
++					       DST_TYPE_PRIVATE,
++					       mctx, &dstkey);
+ 
+-			if (key->legacy) {
+-				dns_dnsseckey_destroy(mctx, &key);
+-			} else {
+-				ISC_LIST_APPEND(list, key, link);
+-				key = NULL;
+-			}
++		if (result != ISC_R_SUCCESS) {
++			isc_log_write(dns_lctx,
++				      DNS_LOGCATEGORY_GENERAL,
++				      DNS_LOGMODULE_DNSSEC,
++				      ISC_LOG_WARNING,
++				      "dns_dnssec_findmatchingkeys: "
++				      "error reading key file %s: %s",
++				      dir.entry.name,
++				      isc_result_totext(result));
++			continue;
++		}
++
++		RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
++		key->source = dns_keysource_repository;
++		get_hints(key, now);
++
++		if (key->legacy) {
++			dns_dnsseckey_destroy(mctx, &key);
++		} else {
++			ISC_LIST_APPEND(list, key, link);
++			key = NULL;
+ 		}
+ 	}
+ 
+-	if (!ISC_LIST_EMPTY(list))
++	if (!ISC_LIST_EMPTY(list)) {
++		result = ISC_R_SUCCESS;
+ 		ISC_LIST_APPENDLIST(*keylist, list, link);
+-	else
++	} else
+ 		result = ISC_R_NOTFOUND;
+ 
+  failure:
+@@ -1794,7 +1808,13 @@ dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
+ 		for (key2 = ISC_LIST_HEAD(*keys);
+ 		     key2 != NULL;
+ 		     key2 = ISC_LIST_NEXT(key2, link)) {
+-			if (dst_key_pubcompare(key1->key, key2->key,
++			int f1 = dst_key_flags(key1->key);
++			int f2 = dst_key_flags(key2->key);
++			int nr1 = f1 & ~DNS_KEYFLAG_REVOKE;
++			int nr2 = f2 & ~DNS_KEYFLAG_REVOKE;
++			if (nr1 == nr2 &&
++			    dst_key_alg(key1->key) == dst_key_alg(key2->key) &&
++			    dst_key_pubcompare(key1->key, key2->key,
+ 					       ISC_TRUE)) {
+ 				int r1, r2;
+ 				r1 = dst_key_flags(key1->key) &
+diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c
+index c310be5..4c174f3 100644
+--- a/lib/dns/dst_api.c
++++ b/lib/dns/dst_api.c
+@@ -448,6 +448,16 @@ dst_key_tofile(const dst_key_t *key, int type, const char *directory) {
+ 		return (ISC_R_SUCCESS);
+ }
+ 
++void
++dst_key_setexternal(dst_key_t *key, isc_boolean_t value) {
++	key->external = value;
++}
++
++isc_boolean_t
++dst_key_isexternal(dst_key_t *key) {
++	return (key->external);
++}
++
+ isc_result_t
+ dst_key_fromfile(dns_name_t *name, dns_keytag_t id,
+ 		 unsigned int alg, int type, const char *directory,
+diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h
+index 48ce9b8..49ca424 100644
+--- a/lib/dns/dst_internal.h
++++ b/lib/dns/dst_internal.h
+@@ -128,6 +128,7 @@ struct dst_key {
+ 	isc_boolean_t	numset[DST_MAX_NUMERIC + 1]; /*%< data set? */
+ 	isc_boolean_t 	inactive;      /*%< private key not present as it is
+ 					    inactive */
++	isc_boolean_t 	external;      /*%< external key */
+ 
+ 	int		fmt_major;     /*%< private key format, major version */
+ 	int		fmt_minor;     /*%< private key format, minor version */
+diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c
+index ca43cb3..6348cc1 100644
+--- a/lib/dns/dst_parse.c
++++ b/lib/dns/dst_parse.c
+@@ -178,14 +178,18 @@ find_numericdata(const char *s) {
+ }
+ 
+ static int
+-check_rsa(const dst_private_t *priv) {
++check_rsa(const dst_private_t *priv, isc_boolean_t external) {
+ 	int i, j;
+ 	isc_boolean_t have[RSA_NTAGS];
+ 	isc_boolean_t ok;
+ 	unsigned int mask;
+ 
++	if (external)
++		return ((priv->nelements == 0) ? 0 : -1);
++
+ 	for (i = 0; i < RSA_NTAGS; i++)
+ 		have[i] = ISC_FALSE;
++
+ 	for (j = 0; j < priv->nelements; j++) {
+ 		for (i = 0; i < RSA_NTAGS; i++)
+ 			if (priv->elements[j].tag == TAG(DST_ALG_RSAMD5, i))
+@@ -231,10 +235,15 @@ check_dh(const dst_private_t *priv) {
+ }
+ 
+ static int
+-check_dsa(const dst_private_t *priv) {
++check_dsa(const dst_private_t *priv, isc_boolean_t external) {
+ 	int i, j;
++
++	if (external)
++		return ((priv->nelements == 0)? 0 : -1);
++
+ 	if (priv->nelements != DSA_NTAGS)
+ 		return (-1);
++
+ 	for (i = 0; i < DSA_NTAGS; i++) {
+ 		for (j = 0; j < priv->nelements; j++)
+ 			if (priv->elements[j].tag == TAG(DST_ALG_DSA, i))
+@@ -246,7 +255,11 @@ check_dsa(const dst_private_t *priv) {
+ }
+ 
+ static int
+-check_gost(const dst_private_t *priv) {
++check_gost(const dst_private_t *priv, isc_boolean_t external) {
++
++	if (external)
++		return ((priv->nelements == 0)? 0 : -1);
++
+ 	if (priv->nelements != GOST_NTAGS)
+ 		return (-1);
+ 	if (priv->elements[0].tag != TAG(DST_ALG_ECCGOST, 0))
+@@ -255,7 +268,11 @@ check_gost(const dst_private_t *priv) {
+ }
+ 
+ static int
+-check_ecdsa(const dst_private_t *priv) {
++check_ecdsa(const dst_private_t *priv, isc_boolean_t external) {
++
++	if (external)
++		return ((priv->nelements == 0) ? 0 : -1);
++
+ 	if (priv->nelements != ECDSA_NTAGS)
+ 		return (-1);
+ 	if (priv->elements[0].tag != TAG(DST_ALG_ECDSA256, 0))
+@@ -309,7 +326,7 @@ check_hmac_sha(const dst_private_t *priv, unsigned int ntags,
+ 
+ static int
+ check_data(const dst_private_t *priv, const unsigned int alg,
+-	   isc_boolean_t old)
++	   isc_boolean_t old, isc_boolean_t external)
+ {
+ 	/* XXXVIX this switch statement is too sparse to gen a jump table. */
+ 	switch (alg) {
+@@ -318,17 +335,17 @@ check_data(const dst_private_t *priv, const unsigned int alg,
+ 	case DST_ALG_NSEC3RSASHA1:
+ 	case DST_ALG_RSASHA256:
+ 	case DST_ALG_RSASHA512:
+-		return (check_rsa(priv));
++		return (check_rsa(priv, external));
+ 	case DST_ALG_DH:
+ 		return (check_dh(priv));
+ 	case DST_ALG_DSA:
+ 	case DST_ALG_NSEC3DSA:
+-		return (check_dsa(priv));
++		return (check_dsa(priv, external));
+ 	case DST_ALG_ECCGOST:
+-		return (check_gost(priv));
++		return (check_gost(priv, external));
+ 	case DST_ALG_ECDSA256:
+ 	case DST_ALG_ECDSA384:
+-		return (check_ecdsa(priv));
++		return (check_ecdsa(priv, external));
+ 	case DST_ALG_HMACMD5:
+ 		return (check_hmac_md5(priv, old));
+ 	case DST_ALG_HMACSHA1:
+@@ -372,6 +389,7 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
+ 	unsigned int opt = ISC_LEXOPT_EOL;
+ 	isc_stdtime_t when;
+ 	isc_result_t ret;
++	isc_boolean_t external = ISC_FALSE;
+ 
+ 	REQUIRE(priv != NULL);
+ 
+@@ -467,9 +485,15 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
+ 
+ 		if (token.type != isc_tokentype_string) {
+ 			ret = DST_R_INVALIDPRIVATEKEY;
++			NEXTTOKEN(lex, opt, &token);
+ 			goto fail;
+ 		}
+ 
++		if (strcmp(DST_AS_STR(token), "External:") == 0) {
++			external = ISC_TRUE;
++			goto next;
++		}
++
+ 		/* Numeric metadata */
+ 		tag = find_numericdata(DST_AS_STR(token));
+ 		if (tag >= 0) {
+@@ -534,8 +558,14 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
+ 		READLINE(lex, opt, &token);
+ 		data = NULL;
+ 	}
++
+  done:
+-	check = check_data(priv, alg, ISC_TRUE);
++	if (external && priv->nelements != 0) {
++		ret = DST_R_INVALIDPRIVATEKEY;
++		goto fail;
++	}
++
++	check = check_data(priv, alg, ISC_TRUE, external);
+ 	if (check < 0) {
+ 		ret = DST_R_INVALIDPRIVATEKEY;
+ 		goto fail;
+@@ -544,6 +574,8 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
+ 		goto fail;
+ 	}
+ 
++	key->external = external;
++
+ 	return (ISC_R_SUCCESS);
+ 
+ fail:
+@@ -573,7 +605,7 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
+ 
+ 	REQUIRE(priv != NULL);
+ 
+-	ret = check_data(priv, dst_key_alg(key), ISC_FALSE);
++	ret = check_data(priv, dst_key_alg(key), ISC_FALSE, key->external);
+ 	if (ret < 0)
+ 		return (DST_R_INVALIDPRIVATEKEY);
+ 	else if (ret != ISC_R_SUCCESS)
+@@ -691,6 +723,9 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
+ 	       fprintf(fp, "%s %.*s\n", s, (int)r.length, r.base);
+ 	}
+ 
++	if (key->external)
++	       fprintf(fp, "External:\n");
++
+ 	/* Add the metadata tags */
+ 	if (major > 1 || (major == 1 && minor >= 3)) {
+ 		for (i = 0; i < NUMERIC_NTAGS; i++) {
+@@ -706,14 +741,14 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
+ 
+ 			isc_buffer_init(&b, buffer, sizeof(buffer));
+ 			result = dns_time32_totext(when, &b);
+-		       if (result != ISC_R_SUCCESS) {
++			if (result != ISC_R_SUCCESS) {
+ 			       fclose(fp);
+ 			       return (DST_R_INVALIDPRIVATEKEY);
+-		       }
++			}
+ 
+ 			isc_buffer_usedregion(&b, &r);
+ 
+-		       fprintf(fp, "%s %.*s\n", timetags[i], (int)r.length,
++			fprintf(fp, "%s %.*s\n", timetags[i], (int)r.length,
+ 				r.base);
+ 		}
+ 	}
+diff --git a/lib/dns/dst_result.c b/lib/dns/dst_result.c
+index 297e809..30aa1fa 100644
+--- a/lib/dns/dst_result.c
++++ b/lib/dns/dst_result.c
+@@ -35,7 +35,7 @@ static const char *text[DST_R_NRESULTS] = {
+ 	"illegal operation for a null key",	/*%< 3 */
+ 	"public key is invalid",		/*%< 4 */
+ 	"private key is invalid",		/*%< 5 */
+-	"UNUSED6",				/*%< 6 */
++	"external key",				/*%< 6 */
+ 	"error occurred writing key to disk",	/*%< 7 */
+ 	"invalid algorithm specific parameter",	/*%< 8 */
+ 	"UNUSED9",				/*%< 9 */
+diff --git a/lib/dns/include/dns/master.h b/lib/dns/include/dns/master.h
+index 6abcb7e..931e930 100644
+--- a/lib/dns/include/dns/master.h
++++ b/lib/dns/include/dns/master.h
+@@ -57,6 +57,7 @@
+ 
+ #define DNS_MASTER_RESIGN	0x00002000
+ #define DNS_MASTER_KEY	 	0x00004000	/*%< Loading a key zone master file. */
++#define DNS_MASTER_NOTTL	0x00008000	/*%< Don't require ttl. */
+ 
+ ISC_LANG_BEGINDECLS
+ 
+diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h
+index 6ce3a0c..8676d1a 100644
+--- a/lib/dns/include/dst/dst.h
++++ b/lib/dns/include/dst/dst.h
+@@ -953,6 +953,12 @@ dst_key_setinactive(dst_key_t *key, isc_boolean_t inactive);
+  *	'key' to be valid.
+  */
+ 
++void
++dst_key_setexternal(dst_key_t *key, isc_boolean_t value);
++
++isc_boolean_t
++dst_key_isexternal(dst_key_t *key);
++
+ ISC_LANG_ENDDECLS
+ 
+ #endif /* DST_DST_H */
+diff --git a/lib/dns/master.c b/lib/dns/master.c
+index aa8f1ac..1a2c84a 100644
+--- a/lib/dns/master.c
++++ b/lib/dns/master.c
+@@ -592,9 +592,9 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx,
+ 		isc_lex_setcomments(lctx->lex, ISC_LEXCOMMENT_DNSMASTERFILE);
+ 	}
+ 
+-	lctx->ttl_known = ISC_FALSE;
++	lctx->ttl_known = ISC_TF((options & DNS_MASTER_NOTTL) != 0);
+ 	lctx->ttl = 0;
+-	lctx->default_ttl_known = ISC_FALSE;
++	lctx->default_ttl_known = lctx->ttl_known;
+ 	lctx->default_ttl = 0;
+ 	lctx->warn_1035 = ISC_TRUE;	/* XXX Argument? */
+ 	lctx->warn_tcr = ISC_TRUE;	/* XXX Argument? */
+diff --git a/lib/dns/openssldsa_link.c b/lib/dns/openssldsa_link.c
+index 8bea1c0..a24baae 100644
+--- a/lib/dns/openssldsa_link.c
++++ b/lib/dns/openssldsa_link.c
+@@ -522,6 +522,11 @@ openssldsa_tofile(const dst_key_t *key, const char *directory) {
+ 
+ 	if (key->keydata.dsa == NULL)
+ 		return (DST_R_NULLKEY);
++	
++	if (key->external) {
++		priv.nelements = 0;
++		return (dst__privstruct_writefile(key, &priv, directory));
++	}
+ 
+ 	dsa = key->keydata.dsa;
+ 
+@@ -569,6 +574,7 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ #define DST_RET(a) {ret = a; goto err;}
+ 
+ 	UNUSED(pub);
++
+ 	/* read private key file */
+ 	ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv);
+ 	if (ret != ISC_R_SUCCESS)
+@@ -607,6 +613,19 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	}
+ 	dst__privstruct_free(&priv, mctx);
+ 
++	if (key->external) {
++		if (pub == NULL)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		dsa->q = pub->keydata.dsa->q;
++		pub->keydata.dsa->q = NULL;
++		dsa->p = pub->keydata.dsa->p;
++		pub->keydata.dsa->p = NULL;
++		dsa->g = pub->keydata.dsa->g;
++		pub->keydata.dsa->g =  NULL;
++		dsa->pub_key = pub->keydata.dsa->pub_key;
++		pub->keydata.dsa->pub_key = NULL;
++	}
++
+ 	key->key_size = BN_num_bits(dsa->p);
+ 
+ 	return (ISC_R_SUCCESS);
+diff --git a/lib/dns/opensslecdsa_link.c b/lib/dns/opensslecdsa_link.c
+index c3f5061..7eff9a0 100644
+--- a/lib/dns/opensslecdsa_link.c
++++ b/lib/dns/opensslecdsa_link.c
+@@ -453,6 +453,11 @@ opensslecdsa_tofile(const dst_key_t *key, const char *directory) {
+ 	if (key->keydata.pkey == NULL)
+ 		return (DST_R_NULLKEY);
+ 
++	if (key->external) {
++		priv.nelements = 0;
++		return (dst__privstruct_writefile(key, &priv, directory));
++	}
++
+ 	pkey = key->keydata.pkey;
+ 	eckey = EVP_PKEY_get1_EC_KEY(pkey);
+ 	if (eckey == NULL)
+@@ -514,8 +519,9 @@ static isc_result_t
+ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	dst_private_t priv;
+ 	isc_result_t ret;
+-	EVP_PKEY *pkey;
+-	EC_KEY *eckey = NULL;
++	EVP_PKEY *pkey, *pubpkey;
++	EC_KEY *eckey = NULL, *pubeckey = NULL;
++	const EC_POINT *pubkey;
+ 	BIGNUM *privkey;
+ 	int group_nid;
+ 	isc_mem_t *mctx = key->mctx;
+@@ -537,17 +543,36 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	if (ret != ISC_R_SUCCESS)
+ 		goto err;
+ 
+-	privkey = BN_bin2bn(priv.elements[0].data,
+-			    priv.elements[0].length, NULL);
+-	if (privkey == NULL)
+-		DST_RET(ISC_R_NOMEMORY);
+-	if (!EC_KEY_set_private_key(eckey, privkey))
+-		DST_RET(ISC_R_NOMEMORY);
+-	if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS)
+-		DST_RET(DST_R_INVALIDPRIVATEKEY);
+-	dst__privstruct_free(&priv, mctx);
+-	memset(&priv, 0, sizeof(priv));
+-
++	if (key->external) {
++		/*
++		 * Copy the public key to this new key.
++		 */
++		if (pub == NULL)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		pubpkey = pub->keydata.pkey;
++		pubeckey = EVP_PKEY_get1_EC_KEY(pubpkey);
++		if (pubeckey == NULL)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		pubkey = EC_KEY_get0_public_key(pubeckey);
++		if (pubkey == NULL)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		if (EC_KEY_set_public_key(eckey, pubkey) != 1)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		if (EC_KEY_check_key(eckey) != 1)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++	} else {
++		privkey = BN_bin2bn(priv.elements[0].data,
++				    priv.elements[0].length, NULL);
++		if (privkey == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++		if (!EC_KEY_set_private_key(eckey, privkey))
++			DST_RET(ISC_R_NOMEMORY);
++		if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		dst__privstruct_free(&priv, mctx);
++		memset(&priv, 0, sizeof(priv));
++	}
++ 
+ 	pkey = EVP_PKEY_new();
+ 	if (pkey == NULL)
+ 		DST_RET (ISC_R_NOMEMORY);
+@@ -561,6 +586,8 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+  err:
+ 	if (eckey != NULL)
+ 		EC_KEY_free(eckey);
++	if (pubeckey != NULL)
++		EC_KEY_free(pubeckey);
+ 	dst__privstruct_free(&priv, mctx);
+ 	memset(&priv, 0, sizeof(priv));
+ 	return (ret);
+diff --git a/lib/dns/opensslgost_link.c b/lib/dns/opensslgost_link.c
+index 1ce4405..325a7c0 100644
+--- a/lib/dns/opensslgost_link.c
++++ b/lib/dns/opensslgost_link.c
+@@ -296,6 +296,11 @@ opensslgost_tofile(const dst_key_t *key, const char *directory) {
+ 	if (key->keydata.pkey == NULL)
+ 		return (DST_R_NULLKEY);
+ 
++	if (key->external) {
++		priv.nelements = 0;
++		return (dst__privstruct_writefile(key, &priv, directory));
++	}
++
+ 	pkey = key->keydata.pkey;
+ 
+ 	len = i2d_PrivateKey(pkey, NULL);
+@@ -337,13 +342,21 @@ opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	if (ret != ISC_R_SUCCESS)
+ 		return (ret);
+ 
+-	INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1);
+-	p = priv.elements[0].data;
+-	if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
+-			   (long) priv.elements[0].length) == NULL)
+-		DST_RET(dst__openssl_toresult2("d2i_PrivateKey",
+-					       DST_R_INVALIDPRIVATEKEY));
+-	key->keydata.pkey = pkey;
++	if (key->external) {
++		INSIST(priv.nelements == 0);
++		if (pub == NULL)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		key->keydata.pkey = pub->keydata.pkey;
++		pub->keydata.pkey = NULL;
++	} else {
++		INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1);
++		p = priv.elements[0].data;
++		if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
++				   (long) priv.elements[0].length) == NULL)
++			DST_RET(dst__openssl_toresult2("d2i_PrivateKey",
++						     DST_R_INVALIDPRIVATEKEY));
++		key->keydata.pkey = pkey;
++	}
+ 	key->key_size = EVP_PKEY_bits(pkey);
+ 	dst__privstruct_free(&priv, mctx);
+ 	memset(&priv, 0, sizeof(priv));
+diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c
+index fa7412c..894c7ae 100644
+--- a/lib/dns/opensslrsa_link.c
++++ b/lib/dns/opensslrsa_link.c
+@@ -1048,8 +1048,14 @@ opensslrsa_tofile(const dst_key_t *key, const char *directory) {
+ 		return (DST_R_NULLKEY);
+ 	rsa = key->keydata.rsa;
+ #endif
+-
+ 	memset(bufs, 0, sizeof(bufs));
++
++	if (key->external) {
++		priv.nelements = 0;
++		result = dst__privstruct_writefile(key, &priv, directory);
++		goto fail;
++	}
++
+ 	for (i = 0; i < 8; i++) {
+ 		bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(rsa->n));
+ 		if (bufs[i] == NULL) {
+@@ -1205,6 +1211,9 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	if (ret != ISC_R_SUCCESS)
+ 		goto err;
+ 
++	if (key->external && priv.nelements != 0)
++		DST_RET(DST_R_INVALIDPRIVATEKEY);
++
+ 	for (i = 0; i < priv.nelements; i++) {
+ 		switch (priv.elements[i].tag) {
+ 		case TAG_RSA_ENGINE:
+@@ -1217,6 +1226,7 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 			break;
+ 		}
+ 	}
++
+ 	/*
+ 	 * Is this key is stored in a HSM?
+ 	 * See if we can fetch it.
+@@ -1328,8 +1338,10 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 
+ 	if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS)
+ 		DST_RET(DST_R_INVALIDPRIVATEKEY);
+-	if (BN_num_bits(rsa->e) > RSA_MAX_PUBEXP_BITS)
+-		DST_RET(ISC_R_RANGE);
++	if (!key->external) {
++		if (BN_num_bits(rsa->e) > RSA_MAX_PUBEXP_BITS)
++			DST_RET(ISC_R_RANGE);
++	}
+ 	key->key_size = BN_num_bits(rsa->n);
+ 	if (pubrsa != NULL)
+ 		RSA_free(pubrsa);
+diff --git a/lib/dns/zone.c b/lib/dns/zone.c
+index daf495b..b82ad58 100644
+--- a/lib/dns/zone.c
++++ b/lib/dns/zone.c
+@@ -5545,6 +5545,7 @@ find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
+ 	const char *directory = dns_zone_getkeydirectory(zone);
+ 
+ 	CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
++	memset(keys, 0, sizeof(*keys) * maxkeys);
+ 	result = dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db),
+ 					  directory, mctx, maxkeys, keys,
+ 					  nkeys);
+@@ -13132,6 +13133,7 @@ sync_secure_db(dns_zone_t *seczone, dns_db_t *secdb,
+ 
+ static void
+ receive_secure_serial(isc_task_t *task, isc_event_t *event) {
++	static char me[] = "receive_secure_serial";
+ 	isc_result_t result;
+ 	dns_journal_t *rjournal = NULL;
+ 	isc_uint32_t start, end;
+@@ -13147,6 +13149,8 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) {
+ 	end = ((struct secure_event *)event)->serial;
+ 	isc_event_free(&event);
+ 
++	ENTER;
++
+ 	LOCK_ZONE(zone);
+ 
+ 	dns_diff_init(zone->mctx, &diff);
+-- 
+1.9.3
+
diff --git a/SOURCES/bind-9.9-dist-native-pkcs11.patch b/SOURCES/bind-9.9-dist-native-pkcs11.patch
new file mode 100644
index 0000000..f12312b
--- /dev/null
+++ b/SOURCES/bind-9.9-dist-native-pkcs11.patch
@@ -0,0 +1,771 @@
+From 28f61b8a12da4a8dd10dccaefe8e50fc8605b87e Mon Sep 17 00:00:00 2001
+From: Tomas Hozza <thozza@redhat.com>
+Date: Mon, 22 Sep 2014 16:44:29 +0200
+Subject: [PATCH] Distributing native PKCS#11 BIND and utils
+
+Signed-off-by: Tomas Hozza <thozza@redhat.com>
+---
+ bin/Makefile.in                   |  2 +-
+ bin/dnssec-pkcs11/Makefile.in     | 40 +++++++++++------------
+ bin/dnssec/Makefile.in            |  2 +-
+ bin/named-pkcs11/Makefile.in      | 40 +++++++++--------------
+ bin/named/Makefile.in             |  2 +-
+ bin/pkcs11/Makefile.in            |  6 ++--
+ configure.in                      | 68 +++++++++++++++++++++++++++++++--------
+ lib/Makefile.in                   |  2 +-
+ lib/dns-pkcs11/Makefile.in        | 24 +++++++-------
+ lib/export/Makefile.in            |  2 +-
+ lib/export/dns-pkcs11/Makefile.in | 26 +++++++--------
+ lib/export/isc-pkcs11/Makefile.in | 18 +++++------
+ lib/isc-pkcs11/Makefile.in        | 24 +++++++-------
+ make/includes.in                  | 10 ++++++
+ 14 files changed, 154 insertions(+), 112 deletions(-)
+
+diff --git a/bin/Makefile.in b/bin/Makefile.in
+index 87ca5b2..187ec23 100644
+--- a/bin/Makefile.in
++++ b/bin/Makefile.in
+@@ -19,7 +19,7 @@ srcdir =	@srcdir@
+ VPATH =		@srcdir@
+ top_srcdir =	@top_srcdir@
+ 
+-SUBDIRS =	named rndc dig dnssec tools tests nsupdate \
++SUBDIRS =	named named-pkcs11 rndc dig dnssec dnssec-pkcs11 tools tests nsupdate \
+ 		check confgen @PYTHON_TOOLS@ @PKCS11_TOOLS@
+ TARGETS =
+ 
+diff --git a/bin/dnssec-pkcs11/Makefile.in b/bin/dnssec-pkcs11/Makefile.in
+index 64e1846..7846662 100644
+--- a/bin/dnssec-pkcs11/Makefile.in
++++ b/bin/dnssec-pkcs11/Makefile.in
+@@ -23,18 +23,18 @@ top_srcdir =	@top_srcdir@
+ 
+ @BIND9_MAKE_INCLUDES@
+ 
+-CINCLUDES =	${DNS_INCLUDES} ${ISC_INCLUDES}
++CINCLUDES =	${DNS_PKCS11_INCLUDES} ${ISC_PKCS11_INCLUDES}
+ 
+ CDEFINES =	-DVERSION=\"${VERSION}\" @USE_PKCS11@ @PKCS11_ENGINE@ \
+-		@CRYPTO@ -DPK11_LIB_LOCATION=\"@PKCS11_PROVIDER@\"
++		@CRYPTO_PK11@ -DPK11_LIB_LOCATION=\"@PKCS11_PROVIDER@\"
+ CWARNINGS =
+ 
+-DNSLIBS =	../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
+-ISCLIBS =	../../lib/isc/libisc.@A@
+-ISCNOSYMLIBS =	../../lib/isc/libisc-nosymtbl.@A@
++DNSLIBS =	../../lib/dns-pkcs11/libdns-pkcs11.@A@ @DNS_CRYPTO_PK11_LIBS@
++ISCLIBS =	../../lib/isc-pkcs11/libisc-pkcs11.@A@
++ISCNOSYMLIBS =	../../lib/isc-pkcs11/libisc-pkcs11-nosymtbl.@A@
+ 
+-DNSDEPLIBS =	../../lib/dns/libdns.@A@
+-ISCDEPLIBS =	../../lib/isc/libisc.@A@
++DNSDEPLIBS =	../../lib/dns-pkcs11/libdns-pkcs11.@A@
++ISCDEPLIBS =	../../lib/isc-pkcs11/libisc-pkcs11.@A@
+ 
+ DEPLIBS =	${DNSDEPLIBS} ${ISCDEPLIBS}
+ 
+@@ -43,10 +43,10 @@ LIBS =		${DNSLIBS} ${ISCLIBS} @LIBS@
+ NOSYMLIBS =	${DNSLIBS} ${ISCNOSYMLIBS} @LIBS@
+ 
+ # Alphabetically
+-TARGETS =	dnssec-keygen@EXEEXT@ dnssec-signzone@EXEEXT@ \
+-		dnssec-keyfromlabel@EXEEXT@ dnssec-dsfromkey@EXEEXT@ \
+-		dnssec-revoke@EXEEXT@ dnssec-settime@EXEEXT@ \
+-		dnssec-verify@EXEEXT@ dnssec-importkey@EXEEXT@
++TARGETS =	dnssec-keygen-pkcs11@EXEEXT@ dnssec-signzone-pkcs11@EXEEXT@ \
++		dnssec-keyfromlabel-pkcs11@EXEEXT@ dnssec-dsfromkey-pkcs11@EXEEXT@ \
++		dnssec-revoke-pkcs11@EXEEXT@ dnssec-settime-pkcs11@EXEEXT@ \
++		dnssec-verify-pkcs11@EXEEXT@ dnssec-importkey-pkcs11@EXEEXT@
+ 
+ OBJS =		dnssectool.@O@
+ 
+@@ -67,15 +67,15 @@ MANOBJS =	${MANPAGES} ${HTMLPAGES}
+ 
+ @BIND9_MAKE_RULES@
+ 
+-dnssec-dsfromkey@EXEEXT@: dnssec-dsfromkey.@O@ ${OBJS} ${DEPLIBS}
++dnssec-dsfromkey-pkcs11@EXEEXT@: dnssec-dsfromkey.@O@ ${OBJS} ${DEPLIBS}
+ 	export BASEOBJS="dnssec-dsfromkey.@O@ ${OBJS}"; \
+ 	${FINALBUILDCMD}
+ 
+-dnssec-keyfromlabel@EXEEXT@: dnssec-keyfromlabel.@O@ ${OBJS} ${DEPLIBS}
++dnssec-keyfromlabel-pkcs11@EXEEXT@: dnssec-keyfromlabel.@O@ ${OBJS} ${DEPLIBS}
+ 	export BASEOBJS="dnssec-keyfromlabel.@O@ ${OBJS}"; \
+ 	${FINALBUILDCMD}
+ 
+-dnssec-keygen@EXEEXT@: dnssec-keygen.@O@ ${OBJS} ${DEPLIBS}
++dnssec-keygen-pkcs11@EXEEXT@: dnssec-keygen.@O@ ${OBJS} ${DEPLIBS}
+ 	export BASEOBJS="dnssec-keygen.@O@ ${OBJS}"; \
+ 	${FINALBUILDCMD}
+ 
+@@ -83,7 +83,7 @@ dnssec-signzone.@O@: dnssec-signzone.c
+ 	${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -DVERSION=\"${VERSION}\" \
+ 		-c ${srcdir}/dnssec-signzone.c
+ 
+-dnssec-signzone@EXEEXT@: dnssec-signzone.@O@ ${OBJS} ${DEPLIBS}
++dnssec-signzone-pkcs11@EXEEXT@: dnssec-signzone.@O@ ${OBJS} ${DEPLIBS}
+ 	export BASEOBJS="dnssec-signzone.@O@ ${OBJS}"; \
+ 	${FINALBUILDCMD}
+ 
+@@ -91,19 +91,19 @@ dnssec-verify.@O@: dnssec-verify.c
+ 	${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -DVERSION=\"${VERSION}\" \
+ 		-c ${srcdir}/dnssec-verify.c
+ 
+-dnssec-verify@EXEEXT@: dnssec-verify.@O@ ${OBJS} ${DEPLIBS}
++dnssec-verify-pkcs11@EXEEXT@: dnssec-verify.@O@ ${OBJS} ${DEPLIBS}
+ 	export BASEOBJS="dnssec-verify.@O@ ${OBJS}"; \
+ 	${FINALBUILDCMD}
+ 
+-dnssec-revoke@EXEEXT@: dnssec-revoke.@O@ ${OBJS} ${DEPLIBS}
++dnssec-revoke-pkcs11@EXEEXT@: dnssec-revoke.@O@ ${OBJS} ${DEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ 	dnssec-revoke.@O@ ${OBJS} ${LIBS}
+ 
+-dnssec-settime@EXEEXT@: dnssec-settime.@O@ ${OBJS} ${DEPLIBS}
++dnssec-settime-pkcs11@EXEEXT@: dnssec-settime.@O@ ${OBJS} ${DEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ 	dnssec-settime.@O@ ${OBJS} ${LIBS}
+ 
+-dnssec-importkey@EXEEXT@: dnssec-importkey.@O@ ${OBJS} ${DEPLIBS}
++dnssec-importkey-pkcs11@EXEEXT@: dnssec-importkey.@O@ ${OBJS} ${DEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ 	dnssec-importkey.@O@ ${OBJS} ${LIBS}
+ 
+@@ -114,11 +114,9 @@ docclean manclean maintainer-clean::
+ 
+ installdirs:
+ 	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir}
+-	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man8
+ 
+ install:: ${TARGETS} installdirs
+ 	for t in ${TARGETS}; do ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} $$t ${DESTDIR}${sbindir}; done
+-	for m in ${MANPAGES}; do ${INSTALL_DATA} ${srcdir}/$$m ${DESTDIR}${mandir}/man8; done
+ 
+ clean distclean::
+ 	rm -f ${TARGETS}
+diff --git a/bin/dnssec/Makefile.in b/bin/dnssec/Makefile.in
+index 64e1846..cfb5628 100644
+--- a/bin/dnssec/Makefile.in
++++ b/bin/dnssec/Makefile.in
+@@ -25,7 +25,7 @@ top_srcdir =	@top_srcdir@
+ 
+ CINCLUDES =	${DNS_INCLUDES} ${ISC_INCLUDES}
+ 
+-CDEFINES =	-DVERSION=\"${VERSION}\" @USE_PKCS11@ @PKCS11_ENGINE@ \
++CDEFINES =	-DVERSION=\"${VERSION}\" \
+ 		@CRYPTO@ -DPK11_LIB_LOCATION=\"@PKCS11_PROVIDER@\"
+ CWARNINGS =
+ 
+diff --git a/bin/named-pkcs11/Makefile.in b/bin/named-pkcs11/Makefile.in
+index cd65777..be791ca 100644
+--- a/bin/named-pkcs11/Makefile.in
++++ b/bin/named-pkcs11/Makefile.in
+@@ -47,26 +47,26 @@ DLZDRIVER_INCLUDES =	@DLZ_DRIVER_INCLUDES@
+ DLZDRIVER_LIBS =	@DLZ_DRIVER_LIBS@
+ 
+ CINCLUDES =	-I${srcdir}/include -I${srcdir}/unix/include -I. \
+-		${LWRES_INCLUDES} ${DNS_INCLUDES} ${BIND9_INCLUDES} \
+-		${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} \
++		${LWRES_INCLUDES} ${DNS_PKCS11_INCLUDES} ${BIND9_INCLUDES} \
++		${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_PKCS11_INCLUDES} \
+ 		${DLZDRIVER_INCLUDES} ${DBDRIVER_INCLUDES} @DST_OPENSSL_INC@
+ 
+-CDEFINES =      @CONTRIB_DLZ@ @USE_PKCS11@ @PKCS11_ENGINE@ @CRYPTO@
++CDEFINES =      @USE_PKCS11@ @PKCS11_ENGINE@ @CRYPTO_PK11@
+ 
+ CWARNINGS =
+ 
+-DNSLIBS =	../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
++DNSLIBS =	../../lib/dns-pkcs11/libdns-pkcs11.@A@ @DNS_CRYPTO_LIBS@
+ ISCCFGLIBS =	../../lib/isccfg/libisccfg.@A@
+ ISCCCLIBS =	../../lib/isccc/libisccc.@A@
+-ISCLIBS =	../../lib/isc/libisc.@A@
++ISCLIBS =	../../lib/isc-pkcs11/libisc-pkcs11.@A@
+ ISCNOSYMLIBS =	../../lib/isc/libisc-nosymtbl.@A@
+ LWRESLIBS =	../../lib/lwres/liblwres.@A@
+ BIND9LIBS =	../../lib/bind9/libbind9.@A@
+ 
+-DNSDEPLIBS =	../../lib/dns/libdns.@A@
++DNSDEPLIBS =	../../lib/dns-pkcs11/libdns-pkcs11.@A@
+ ISCCFGDEPLIBS =	../../lib/isccfg/libisccfg.@A@
+ ISCCCDEPLIBS =	../../lib/isccc/libisccc.@A@
+-ISCDEPLIBS =	../../lib/isc/libisc.@A@
++ISCDEPLIBS =	../../lib/isc-pkcs11/libisc-pkcs11.@A@
+ LWRESDEPLIBS =	../../lib/lwres/liblwres.@A@
+ BIND9DEPLIBS =	../../lib/bind9/libbind9.@A@
+ 
+@@ -75,15 +75,15 @@ DEPLIBS =	${LWRESDEPLIBS} ${DNSDEPLIBS} ${BIND9DEPLIBS} \
+ 
+ LIBS =		${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \
+ 		${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} \
+-		${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBS@
++		@LIBS@
+ 
+ NOSYMLIBS =	${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \
+ 		${ISCCFGLIBS} ${ISCCCLIBS} ${ISCNOSYMLIBS} \
+-		${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBS@
++		@LIBS@
+ 
+ SUBDIRS =	unix
+ 
+-TARGETS =	named@EXEEXT@ lwresd@EXEEXT@
++TARGETS =	named-pkcs11@EXEEXT@
+ 
+ OBJS =		builtin.@O@ client.@O@ config.@O@ control.@O@ \
+ 		controlconf.@O@ interfacemgr.@O@ \
+@@ -92,8 +92,7 @@ OBJS =		builtin.@O@ client.@O@ config.@O@ control.@O@ \
+ 		tkeyconf.@O@ tsigconf.@O@ update.@O@ xfrout.@O@ \
+ 		zoneconf.@O@ \
+ 		lwaddr.@O@ lwresd.@O@ lwdclient.@O@ lwderror.@O@ lwdgabn.@O@ \
+-		lwdgnba.@O@ lwdgrbn.@O@ lwdnoop.@O@ lwsearch.@O@ \
+-		${DLZDRIVER_OBJS} ${DBDRIVER_OBJS}
++		lwdgnba.@O@ lwdgrbn.@O@ lwdnoop.@O@ lwsearch.@O@
+ 
+ UOBJS =		unix/os.@O@ unix/dlz_dlopen_driver.@O@
+ 
+@@ -106,8 +105,7 @@ SRCS =		builtin.c client.c config.c control.c \
+ 		tkeyconf.c tsigconf.c update.c xfrout.c \
+ 		zoneconf.c \
+ 		lwaddr.c lwresd.c lwdclient.c lwderror.c lwdgabn.c \
+-		lwdgnba.c lwdgrbn.c lwdnoop.c lwsearch.c \
+-		${DLZDRIVER_SRCS} ${DBDRIVER_SRCS}
++		lwdgnba.c lwdgrbn.c lwdnoop.c lwsearch.c
+ 
+ MANPAGES =	named.8 lwresd.8 named.conf.5
+ 
+@@ -142,7 +140,7 @@ config.@O@: config.c bind.keys.h
+ 		-DNS_SYSCONFDIR=\"${sysconfdir}\" \
+ 		-c ${srcdir}/config.c
+ 
+-named@EXEEXT@: ${OBJS} ${UOBJS} ${DEPLIBS}
++named-pkcs11@EXEEXT@: ${OBJS} ${UOBJS} ${DEPLIBS}
+ 	export MAKE_SYMTABLE="yes"; \
+ 	export BASEOBJS="${OBJS} ${UOBJS}"; \
+ 	${FINALBUILDCMD}
+@@ -173,15 +171,9 @@ statschannel.@O@: bind9.xsl.h bind9.ver3.xsl.h
+ 
+ installdirs:
+ 	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir}
+-	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man5
+-	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man8
+-
+-install:: named@EXEEXT@ lwresd@EXEEXT@ installdirs
+-	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named@EXEEXT@ ${DESTDIR}${sbindir}
+-	(cd ${DESTDIR}${sbindir}; rm -f lwresd@EXEEXT@; @LN@ named@EXEEXT@ lwresd@EXEEXT@)
+-	${INSTALL_DATA} ${srcdir}/named.8 ${DESTDIR}${mandir}/man8
+-	${INSTALL_DATA} ${srcdir}/lwresd.8 ${DESTDIR}${mandir}/man8
+-	${INSTALL_DATA} ${srcdir}/named.conf.5 ${DESTDIR}${mandir}/man5
++
++install:: named-pkcs11@EXEEXT@ installdirs
++	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named-pkcs11@EXEEXT@ ${DESTDIR}${sbindir}
+ 
+ @DLZ_DRIVER_RULES@
+ 
+diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in
+index cd65777..a5d46b6 100644
+--- a/bin/named/Makefile.in
++++ b/bin/named/Makefile.in
+@@ -51,7 +51,7 @@ CINCLUDES =	-I${srcdir}/include -I${srcdir}/unix/include -I. \
+ 		${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} \
+ 		${DLZDRIVER_INCLUDES} ${DBDRIVER_INCLUDES} @DST_OPENSSL_INC@
+ 
+-CDEFINES =      @CONTRIB_DLZ@ @USE_PKCS11@ @PKCS11_ENGINE@ @CRYPTO@
++CDEFINES =      @CONTRIB_DLZ@ @CRYPTO@
+ 
+ CWARNINGS =
+ 
+diff --git a/bin/pkcs11/Makefile.in b/bin/pkcs11/Makefile.in
+index 15d3fb5..32cc753 100644
+--- a/bin/pkcs11/Makefile.in
++++ b/bin/pkcs11/Makefile.in
+@@ -20,13 +20,13 @@ top_srcdir =	@top_srcdir@
+ 
+ @BIND9_MAKE_INCLUDES@
+ 
+-CINCLUDES =	${ISC_INCLUDES}
++CINCLUDES =	${ISC_PKCS11_INCLUDES}
+ 
+ CDEFINES =
+ 
+-ISCLIBS =	../../lib/isc/libisc.@A@
++ISCLIBS =	../../lib/isc-pkcs11/libisc-pkcs11.@A@
+ 
+-ISCDEPLIBS =	../../lib/isc/libisc.@A@
++ISCDEPLIBS =	../../lib/isc-pkcs11/libisc-pkcs11.@A@
+ 
+ DEPLIBS =	${ISCDEPLIBS}
+ 
+diff --git a/configure.in b/configure.in
+index d4dc6fd..2fbcfcb 100644
+--- a/configure.in
++++ b/configure.in
+@@ -656,10 +656,10 @@ AC_ARG_WITH(pkcs11,
+ openssldirs="/usr /usr/local /usr/local/ssl /usr/pkg /usr/sfw"
+ if test "$use_openssl" = "auto"
+ then
+-    if test "$want_native_pkcs11" = "yes"
+-    then
+-        use_openssl="native_pkcs11"
+-    else
++#    if test "$want_native_pkcs11" = "yes"
++#    then
++#        use_openssl="native_pkcs11"
++#    else
+ 	    for d in $openssldirs
+     	do
+ 	    	if test -f $d/include/openssl/opensslv.h
+@@ -668,7 +668,7 @@ then
+     			break
+ 		    fi
+     	done
+-    fi
++#    fi
+ fi
+ OPENSSL_ECDSA=""
+ OPENSSL_GOST=""
+@@ -727,11 +727,11 @@ case "$use_openssl" in
+ If you don't want OpenSSL, use --without-openssl])
+ 		;;
+ 	*)
+-		if test "$want_native_pkcs11" = "yes"
+-		then
+-                        AC_MSG_RESULT()
+-			AC_MSG_ERROR([OpenSSL and native PKCS11 cannot be used together.])
+-		fi
++#		if test "$want_native_pkcs11" = "yes"
++#		then
++#                        AC_MSG_RESULT()
++#			AC_MSG_ERROR([OpenSSL and native PKCS11 cannot be used together.])
++#		fi
+ 		if test "$use_openssl" = "yes"
+ 		then
+ 			# User did not specify a path - guess it
+@@ -1011,6 +1011,7 @@ AC_SUBST(OPENSSL_ECDSA)
+ AC_SUBST(OPENSSL_GOST)
+ 
+ DNS_CRYPTO_LIBS="$DNS_CRYPTO_LIBS $DNS_OPENSSL_LIBS"
++DNS_CRYPTO_PK11_LIBS="$DNS_CRYPTO_LIBS"
+ 
+ #
+ # Use OpenSSL for hash functions
+@@ -1192,7 +1193,7 @@ case "$use_pkcs11" in
+ esac
+ AC_SUBST(PKCS11_PROVIDER)
+ 
+-
++CRYPTO_PK11=""
+ PKCS11_ECDSA=""
+ PKCS11_GOST=""
+ AC_MSG_CHECKING(for native PKCS11)
+@@ -1200,7 +1201,7 @@ AC_MSG_CHECKING(for native PKCS11)
+ case "$want_native_pkcs11" in
+ 	yes)
+ 		AC_MSG_RESULT(using native PKCS11 crypto)
+-		CRYPTO="-DPKCS11CRYPTO"
++		CRYPTO_PK11="-DPKCS11CRYPTO"
+ 		PKCS11LINKOBJS='${PKCS11LINKOBJS}'
+ 		PKCS11LINKSRCS='${PKCS11LINKSRCS}'
+                 PKCS11_TEST=pkcs11
+@@ -1237,6 +1238,7 @@ esac
+ AC_SUBST(PKCS11LINKOBJS)
+ AC_SUBST(PKCS11LINKSRCS)
+ AC_SUBST(CRYPTO)
++AC_SUBST(CRYPTO_PK11)
+ AC_SUBST(PKCS11_ECDSA)
+ AC_SUBST(PKCS11_GOST)
+ AC_SUBST(PKCS11_TEST)
+@@ -1435,12 +1437,13 @@ AC_SUBST(USE_GSSAPI)
+ AC_SUBST(DST_GSSAPI_INC)
+ AC_SUBST(DNS_GSSAPI_LIBS)
+ DNS_CRYPTO_LIBS="$DNS_GSSAPI_LIBS $DNS_CRYPTO_LIBS"
+-
++DNS_CRYPTO_PK11_LIBS="$DNS_GSSAPI_LIBS $DNS_CRYPTO_PK11_LIBS"
+ #
+ # Applications linking with libdns also need to link with these libraries.
+ #
+ 
+ AC_SUBST(DNS_CRYPTO_LIBS)
++AC_SUBST(DNS_CRYPTO_PK11_LIBS)
+ 
+ #
+ # was --with-randomdev specified?
+@@ -3918,7 +3921,10 @@ AC_CONFIG_FILES([
+ 	bin/confgen/unix/Makefile
+ 	bin/dig/Makefile
+ 	bin/dnssec/Makefile
++	bin/dnssec-pkcs11/Makefile
+ 	bin/named/Makefile
++	bin/named-pkcs11/Makefile
++	bin/named-pkcs11/unix/Makefile
+ 	bin/named/unix/Makefile
+ 	bin/nsupdate/Makefile
+ 	bin/pkcs11/Makefile
+@@ -3998,11 +4004,19 @@ AC_CONFIG_FILES([
+ 	lib/dns/include/dns/Makefile
+ 	lib/dns/include/dst/Makefile
+ 	lib/dns/tests/Makefile
++	lib/dns-pkcs11/Makefile
++	lib/dns-pkcs11/include/Makefile
++	lib/dns-pkcs11/include/dns/Makefile
++	lib/dns-pkcs11/include/dst/Makefile
+ 	lib/export/Makefile
+ 	lib/export/dns/Makefile
+ 	lib/export/dns/include/Makefile
+ 	lib/export/dns/include/dns/Makefile
+ 	lib/export/dns/include/dst/Makefile
++	lib/export/dns-pkcs11/Makefile
++	lib/export/dns-pkcs11/include/Makefile
++	lib/export/dns-pkcs11/include/dns/Makefile
++	lib/export/dns-pkcs11/include/dst/Makefile
+ 	lib/export/irs/Makefile
+ 	lib/export/irs/include/Makefile
+ 	lib/export/irs/include/irs/Makefile
+@@ -4016,6 +4030,16 @@ AC_CONFIG_FILES([
+ 	lib/export/isc/unix/Makefile
+ 	lib/export/isc/unix/include/Makefile
+ 	lib/export/isc/unix/include/isc/Makefile
++	lib/export/isc-pkcs11/$thread_dir/Makefile
++	lib/export/isc-pkcs11/$thread_dir/include/Makefile
++	lib/export/isc-pkcs11/$thread_dir/include/isc/Makefile
++	lib/export/isc-pkcs11/Makefile
++	lib/export/isc-pkcs11/include/Makefile
++	lib/export/isc-pkcs11/include/isc/Makefile
++	lib/export/isc-pkcs11/nls/Makefile
++	lib/export/isc-pkcs11/unix/Makefile
++	lib/export/isc-pkcs11/unix/include/Makefile
++	lib/export/isc-pkcs11/unix/include/isc/Makefile
+ 	lib/export/isccfg/Makefile
+ 	lib/export/isccfg/include/Makefile
+ 	lib/export/isccfg/include/isccfg/Makefile
+@@ -4044,6 +4068,24 @@ AC_CONFIG_FILES([
+ 	lib/isc/unix/include/Makefile
+ 	lib/isc/unix/include/isc/Makefile
+ 	lib/isc/unix/include/pkcs11/Makefile
++	lib/isc-pkcs11/$arch/Makefile
++	lib/isc-pkcs11/$arch/include/Makefile
++	lib/isc-pkcs11/$arch/include/isc/Makefile
++	lib/isc-pkcs11/$thread_dir/Makefile
++	lib/isc-pkcs11/$thread_dir/include/Makefile
++	lib/isc-pkcs11/$thread_dir/include/isc/Makefile
++	lib/isc-pkcs11/Makefile
++	lib/isc-pkcs11/include/Makefile
++	lib/isc-pkcs11/include/isc/Makefile
++	lib/isc-pkcs11/include/isc/platform.h
++	lib/isc-pkcs11/include/pk11/Makefile
++	lib/isc-pkcs11/include/pkcs11/Makefile
++	lib/isc-pkcs11/tests/Makefile
++	lib/isc-pkcs11/nls/Makefile
++	lib/isc-pkcs11/unix/Makefile
++	lib/isc-pkcs11/unix/include/Makefile
++	lib/isc-pkcs11/unix/include/isc/Makefile
++	lib/isc-pkcs11/unix/include/pkcs11/Makefile
+ 	lib/isccc/Makefile
+ 	lib/isccc/include/Makefile
+ 	lib/isccc/include/isccc/Makefile
+diff --git a/lib/Makefile.in b/lib/Makefile.in
+index 8dc1d38..8e48d5e 100644
+--- a/lib/Makefile.in
++++ b/lib/Makefile.in
+@@ -23,7 +23,7 @@ top_srcdir =	@top_srcdir@
+ # Attempt to disable parallel processing.
+ .NOTPARALLEL:
+ .NO_PARALLEL:
+-SUBDIRS =	isc isccc dns isccfg bind9 lwres tests
++SUBDIRS =	isc isccc dns isccfg bind9 lwres tests isc-pkcs11 dns-pkcs11
+ TARGETS =
+ 
+ @BIND9_MAKE_RULES@
+diff --git a/lib/dns-pkcs11/Makefile.in b/lib/dns-pkcs11/Makefile.in
+index 41fac95..7d88424 100644
+--- a/lib/dns-pkcs11/Makefile.in
++++ b/lib/dns-pkcs11/Makefile.in
+@@ -27,16 +27,16 @@ top_srcdir =	@top_srcdir@
+ 
+ USE_ISC_SPNEGO = @USE_ISC_SPNEGO@
+ 
+-CINCLUDES =	-I. -I${top_srcdir}/lib/dns -Iinclude ${DNS_INCLUDES} ${ISC_INCLUDES} \
++CINCLUDES =	-I. -I${top_srcdir}/lib/dns-pkcs11 -Iinclude ${DNS_PKCS11_INCLUDES} ${ISC_PKCS11_INCLUDES} \
+ 		@DST_OPENSSL_INC@ @DST_GSSAPI_INC@
+ 
+-CDEFINES =	-DUSE_MD5 @CRYPTO@ @USE_GSSAPI@ ${USE_ISC_SPNEGO}
++CDEFINES =	-DUSE_MD5 @CRYPTO_PK11@ @USE_GSSAPI@ ${USE_ISC_SPNEGO}
+ 
+ CWARNINGS =
+ 
+-ISCLIBS =	../../lib/isc/libisc.@A@
++ISCLIBS =	../../lib/isc-pkcs11/libisc-pkcs11.@A@
+ 
+-ISCDEPLIBS =	../../lib/isc/libisc.@A@
++ISCDEPLIBS =	../../lib/isc-pkcs11/libisc-pkcs11.@A@
+ 
+ LIBS =		@LIBS@
+ 
+@@ -132,27 +132,27 @@ dynamic_db.@O@: dynamic_db.c
+ 	-DDYNDB_LIBDIR=\"@libdir@/bind/\" \
+ 	-c ${srcdir}/dynamic_db.c
+ 
+-libdns.@SA@: ${OBJS}
++libdns-pkcs11.@SA@: ${OBJS}
+ 	${AR} ${ARFLAGS} $@ ${OBJS}
+ 	${RANLIB} $@
+ 
+-libdns.la: ${OBJS}
++libdns-pkcs11.la: ${OBJS}
+ 	${LIBTOOL_MODE_LINK} \
+-		${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libdns.la -rpath ${libdir} \
++		${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libdns-pkcs11.la -rpath ${libdir} \
+ 		-version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+-		${OBJS} ${ISCLIBS} @DNS_CRYPTO_LIBS@ ${LIBS}
++		${OBJS} ${ISCLIBS} @DNS_CRYPTO_PK11_LIBS@ ${LIBS}
+ 
+-timestamp: libdns.@A@
++timestamp: libdns-pkcs11.@A@
+ 	touch timestamp
+ 
+ installdirs:
+ 	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir}
+ 
+ install:: timestamp installdirs
+-	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libdns.@A@ ${DESTDIR}${libdir}
++	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libdns-pkcs11.@A@ ${DESTDIR}${libdir}
+ 
+ clean distclean::
+-	rm -f libdns.@A@ timestamp
++	rm -f libdns-pkcs11.@A@ timestamp
+ 	rm -f gen code.h include/dns/enumtype.h include/dns/enumclass.h
+ 	rm -f include/dns/rdatastruct.h
+ 
+@@ -182,7 +182,7 @@ code.h:	gen
+ 	./gen -s ${srcdir} > code.h
+ 
+ gen: gen.c
+-	${BUILD_CC} ${BUILD_CFLAGS} -I${top_srcdir}/lib/isc/include \
++	${BUILD_CC} ${BUILD_CFLAGS} -I${top_srcdir}/lib/isc-pkcs11/include \
+ 	${BUILD_CPPFLAGS} ${BUILD_LDFLAGS} -o $@ ${srcdir}/gen.c ${BUILD_LIBS}
+ 
+ rbtdb64.@O@: rbtdb.c
+diff --git a/lib/export/Makefile.in b/lib/export/Makefile.in
+index 1fd7216..a8a1342 100644
+--- a/lib/export/Makefile.in
++++ b/lib/export/Makefile.in
+@@ -21,7 +21,7 @@ top_srcdir =	@top_srcdir@
+ # Attempt to disable parallel processing.
+ .NOTPARALLEL:
+ .NO_PARALLEL:
+-SUBDIRS =	isc dns isccfg irs samples
++SUBDIRS =	isc dns isccfg irs samples isc-pkcs11 dns-pkcs11
+ TARGETS =
+ 
+ @BIND9_MAKE_RULES@
+diff --git a/lib/export/dns-pkcs11/Makefile.in b/lib/export/dns-pkcs11/Makefile.in
+index e10bf59..669509f 100644
+--- a/lib/export/dns-pkcs11/Makefile.in
++++ b/lib/export/dns-pkcs11/Makefile.in
+@@ -15,7 +15,7 @@
+ # $Id$
+ 
+ top_srcdir =	@top_srcdir@
+-srcdir =	@top_srcdir@/lib/dns
++srcdir =	@top_srcdir@/lib/dns-pkcs11
+ export_srcdir =	@top_srcdir@/lib/export
+ 
+ # Attempt to disable parallel processing.
+@@ -28,16 +28,16 @@ export_srcdir =	@top_srcdir@/lib/export
+ 
+ @BIND9_MAKE_INCLUDES@
+ 
+-CINCLUDES =	-I. -I${top_srcdir}/lib/dns -Iinclude ${DNS_INCLUDES} -I${export_srcdir}/isc/include \
+-		${ISC_INCLUDES} @DST_OPENSSL_INC@ @DST_GSSAPI_INC@
++CINCLUDES =	-I. -I${top_srcdir}/lib/dns-pkcs11 -Iinclude ${DNS_PKCS11_INCLUDES} -I${export_srcdir}/isc-pkcs11/include \
++		${ISC_PKCS11_INCLUDES} @DST_OPENSSL_INC@ @DST_GSSAPI_INC@
+ 
+-CDEFINES =	-DUSE_MD5 @CRYPTO@ @USE_GSSAPI@
++CDEFINES =	-DUSE_MD5 @CRYPTO_PK11@ @USE_GSSAPI@
+ 
+ CWARNINGS =
+ 
+-ISCLIBS =	../isc/libisc-export.@A@
++ISCLIBS =	../isc-pkcs11/libisc-pkcs11-export.@A@
+ 
+-ISCDEPLIBS =	../isc/libisc-export.@A@
++ISCDEPLIBS =	../isc-pkcs11/libisc-pkcs11-export.@A@
+ 
+ LIBS =		@LIBS@
+ 
+@@ -116,29 +116,29 @@ version.@O@: ${srcdir}/version.c
+ 		-DLIBAGE=${LIBAGE} \
+ 		-c ${srcdir}/version.c
+ 
+-libdns-export.@SA@: ${OBJS}
++libdns-pkcs11-export.@SA@: ${OBJS}
+ 	${AR} ${ARFLAGS} $@ ${OBJS}
+ 	${RANLIB} $@
+ 
+-libdns-export.la: ${OBJS}
++libdns-pkcs11-export.la: ${OBJS}
+ 	${LIBTOOL_MODE_LINK} \
+-		${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libdns-export.la \
++		${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libdns-pkcs11-export.la \
+ 		-rpath ${export_libdir} \
+ 		-version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+-		${OBJS} ${ISCLIBS} @DNS_CRYPTO_LIBS@ ${LIBS}
++		${OBJS} ${ISCLIBS} @DNS_CRYPTO_PK11_LIBS@ ${LIBS}
+ 
+-timestamp: libdns-export.@A@
++timestamp: libdns-pkcs11-export.@A@
+ 	touch timestamp
+ 
+ installdirs:
+ 	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_libdir}
+ 
+ install:: timestamp installdirs
+-	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libdns-export.@A@ \
++	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libdns-pkcs11-export.@A@ \
+ 	${DESTDIR}${export_libdir}/
+ 
+ clean distclean::
+-	rm -f libdns-export.@A@ timestamp
++	rm -f libdns-pkcs11-export.@A@ timestamp
+ 	rm -f gen code.h include/dns/enumtype.h include/dns/enumclass.h
+ 	rm -f include/dns/rdatastruct.h
+ 
+diff --git a/lib/export/isc-pkcs11/Makefile.in b/lib/export/isc-pkcs11/Makefile.in
+index e12dffb..926e000 100644
+--- a/lib/export/isc-pkcs11/Makefile.in
++++ b/lib/export/isc-pkcs11/Makefile.in
+@@ -15,7 +15,7 @@
+ # $Id: Makefile.in,v 1.8 2010/06/09 23:50:58 tbox Exp $
+ 
+ top_srcdir =	@top_srcdir@
+-srcdir =	@top_srcdir@/lib/isc
++srcdir =	@top_srcdir@/lib/isc-pkcs11
+ export_srcdir =	@top_srcdir@/lib/export
+ 
+ @BIND9_VERSION@
+@@ -25,9 +25,9 @@ export_srcdir =	@top_srcdir@/lib/export
+ CINCLUDES =	-I${srcdir}/unix/include \
+ 		-I${srcdir}/@ISC_THREAD_DIR@/include \
+ 		-I${srcdir}/@ISC_ARCH_DIR@/include \
+-		-I${export_srcdir}/isc/include -I${srcdir}/include \
++		-I${export_srcdir}/isc-pkcs11/include -I${srcdir}/include \
+ 		@ISC_OPENSSL_INC@
+-CDEFINES =	@CRYPTO@ -DUSE_APPIMPREGISTER -DUSE_MEMIMPREGISTER \
++CDEFINES =	@CRYPTO_PK11@ -DUSE_APPIMPREGISTER -DUSE_MEMIMPREGISTER \
+ 		-DUSE_SOCKETIMPREGISTER -DUSE_TASKIMPREGISTER \
+ 		-DUSE_TIMERIMPREGISTER
+ CWARNINGS =
+@@ -119,26 +119,26 @@ version.@O@: ${srcdir}/version.c
+ 		-DLIBAGE=${LIBAGE} \
+ 		-c ${srcdir}/version.c
+ 
+-libisc-export.@SA@: ${OBJS}
++libisc-pkcs11-export.@SA@: ${OBJS}
+ 	${AR} ${ARFLAGS} $@ ${OBJS}
+ 	${RANLIB} $@
+ 
+-libisc-export.la: ${OBJS}
++libisc-pkcs11-export.la: ${OBJS}
+ 	${LIBTOOL_MODE_LINK} \
+-		${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc-export.la \
++		${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc-pkcs11-export.la \
+ 		-rpath ${export_libdir} \
+ 		-version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+ 		${OBJS} ${LIBS}
+ 
+-timestamp: libisc-export.@A@
++timestamp: libisc-pkcs11-export.@A@
+ 	touch timestamp
+ 
+ installdirs:
+ 	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_libdir}
+ 
+ install:: timestamp installdirs
+-	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libisc-export.@A@ \
++	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libisc-pkcs11-export.@A@ \
+ 	${DESTDIR}${export_libdir}
+ 
+ clean distclean::
+-	rm -f libisc-export.@A@ libisc-export.la timestamp
++	rm -f libisc-pkcs11-export.@A@ libisc-pkcs11-export.la timestamp
+diff --git a/lib/isc-pkcs11/Makefile.in b/lib/isc-pkcs11/Makefile.in
+index 801ab35..d326786 100644
+--- a/lib/isc-pkcs11/Makefile.in
++++ b/lib/isc-pkcs11/Makefile.in
+@@ -31,8 +31,8 @@ CINCLUDES =	-I${srcdir}/unix/include \
+ 		-I${srcdir}/@ISC_THREAD_DIR@/include \
+ 		-I${srcdir}/@ISC_ARCH_DIR@/include \
+ 		-I./include \
+-		-I${srcdir}/include @ISC_OPENSSL_INC@ ${DNS_INCLUDES}
+-CDEFINES =	@CRYPTO@ -DPK11_LIB_LOCATION=\"${PROVIDER}\"
++		-I${srcdir}/include ${DNS_PKCS11_INCLUDES}
++CDEFINES =	@CRYPTO_PK11@ -DPK11_LIB_LOCATION=\"${PROVIDER}\"
+ CWARNINGS =
+ 
+ # Alphabetically
+@@ -110,35 +110,35 @@ version.@O@: version.c
+ 		-DLIBAGE=${LIBAGE} \
+ 		-c ${srcdir}/version.c
+ 
+-libisc.@SA@: ${OBJS} ${SYMTBLOBJS}
++libisc-pkcs11.@SA@: ${OBJS} ${SYMTBLOBJS}
+ 	${AR} ${ARFLAGS} $@ ${OBJS} ${SYMTBLOBJS}
+ 	${RANLIB} $@
+ 
+-libisc-nosymtbl.@SA@: ${OBJS}
++libisc-pkcs11-nosymtbl.@SA@: ${OBJS}
+ 	${AR} ${ARFLAGS} $@ ${OBJS}
+ 	${RANLIB} $@
+ 
+-libisc.la: ${OBJS} ${SYMTBLOBJS}
++libisc-pkcs11.la: ${OBJS} ${SYMTBLOBJS}
+ 	${LIBTOOL_MODE_LINK} \
+-		${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc.la -rpath ${libdir} \
++		${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc-pkcs11.la -rpath ${libdir} \
+ 		-version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+ 		${OBJS} ${SYMTBLOBJS} ${LIBS}
+ 
+-libisc-nosymtbl.la: ${OBJS}
++libisc-pkcs11-nosymtbl.la: ${OBJS}
+ 	${LIBTOOL_MODE_LINK} \
+-		${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc-nosymtbl.la -rpath ${libdir} \
++		${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc-pkcs11-nosymtbl.la -rpath ${libdir} \
+ 		-version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \
+ 		${OBJS} ${LIBS}
+ 
+-timestamp: libisc.@A@ libisc-nosymtbl.@A@
++timestamp: libisc-pkcs11.@A@ libisc-pkcs11-nosymtbl.@A@
+ 	touch timestamp
+ 
+ installdirs:
+ 	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir}
+ 
+ install:: timestamp installdirs
+-	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libisc.@A@ ${DESTDIR}${libdir}
++	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libisc-pkcs11.@A@ ${DESTDIR}${libdir}
+ 
+ clean distclean::
+-	rm -f libisc.@A@ libisc-nosymtbl.@A@ libisc.la \
+-	libisc-nosymtbl.la timestamp
++	rm -f libisc-pkcs11.@A@ libisc-pkcs11-nosymtbl.@A@ libisc-pkcs11.la \
++	libisc-pkcs11-nosymtbl.la timestamp
+diff --git a/make/includes.in b/make/includes.in
+index f2f1b3f..639477c 100644
+--- a/make/includes.in
++++ b/make/includes.in
+@@ -46,3 +46,13 @@ BIND9_INCLUDES = @BIND9_BIND9_BUILDINCLUDE@ \
+ 
+ TEST_INCLUDES = \
+ 	-I${top_srcdir}/lib/tests/include
++
++ISC_PKCS11_INCLUDES = @BIND9_ISC_BUILDINCLUDE@ \
++	-I${top_srcdir}/lib/isc-pkcs11 \
++	-I${top_srcdir}/lib/isc-pkcs11/include \
++	-I${top_srcdir}/lib/isc-pkcs11/unix/include \
++	-I${top_srcdir}/lib/isc-pkcs11/@ISC_THREAD_DIR@/include \
++	-I${top_srcdir}/lib/isc-pkcs11/@ISC_ARCH_DIR@/include
++
++DNS_PKCS11_INCLUDES = @BIND9_DNS_BUILDINCLUDE@ \
++	-I${top_srcdir}/lib/dns-pkcs11/include
+-- 
+1.9.3
+
diff --git a/SOURCES/bind-9.9-native-pkcs11.patch b/SOURCES/bind-9.9-native-pkcs11.patch
new file mode 100644
index 0000000..c8024b3
--- /dev/null
+++ b/SOURCES/bind-9.9-native-pkcs11.patch
@@ -0,0 +1,25320 @@
+From e9ef042fc45d2004c99dd7642d5032fd5832b270 Mon Sep 17 00:00:00 2001
+From: Tomas Hozza <thozza@redhat.com>
+Date: Thu, 21 May 2015 10:52:03 +0200
+Subject: [PATCH] native PKCS#11
+
+Signed-off-by: Tomas Hozza <thozza@redhat.com>
+---
+ acconfig.h                                   |    7 +-
+ bin/check/Makefile.in                        |    3 +-
+ bin/dig/Makefile.in                          |   13 +-
+ bin/dig/dighost.c                            |   11 +-
+ bin/dnssec/Makefile.in                       |    3 +-
+ bin/dnssec/dnssec-dsfromkey.c                |    9 +-
+ bin/dnssec/dnssec-importkey.c                |   93 +-
+ bin/dnssec/dnssec-importkey.docbook          |   58 +-
+ bin/dnssec/dnssec-keyfromlabel.c             |   31 +-
+ bin/dnssec/dnssec-keyfromlabel.docbook       |   43 +-
+ bin/dnssec/dnssec-keygen.c                   |   21 +-
+ bin/dnssec/dnssec-keygen.docbook             |   13 +-
+ bin/dnssec/dnssec-revoke.c                   |   14 +-
+ bin/dnssec/dnssec-revoke.docbook             |   11 +-
+ bin/dnssec/dnssec-settime.c                  |   14 +-
+ bin/dnssec/dnssec-settime.docbook            |   11 +-
+ bin/dnssec/dnssec-signzone.c                 |   14 +-
+ bin/dnssec/dnssec-signzone.docbook           |   15 +-
+ bin/dnssec/dnssec-verify.c                   |   14 +-
+ bin/dnssec/dnssec-verify.docbook             |   17 +
+ bin/dnssec/dnssectool.c                      |    2 +-
+ bin/named/Makefile.in                        |    2 +-
+ bin/named/include/named/globals.h            |    4 +-
+ bin/named/main.c                             |    6 +
+ bin/named/named.docbook                      |   16 +-
+ bin/named/server.c                           |    9 +-
+ bin/nsupdate/Makefile.in                     |    6 +-
+ bin/pkcs11/Makefile.in                       |   67 +-
+ bin/pkcs11/pkcs11-destroy.8                  |   10 +-
+ bin/pkcs11/pkcs11-destroy.c                  |  153 +-
+ bin/pkcs11/pkcs11-destroy.docbook            |   19 +-
+ bin/pkcs11/pkcs11-destroy.html               |   22 +-
+ bin/pkcs11/pkcs11-keygen.8                   |   69 +-
+ bin/pkcs11/pkcs11-keygen.c                   |  687 +++++++--
+ bin/pkcs11/pkcs11-keygen.docbook             |  115 +-
+ bin/pkcs11/pkcs11-keygen.html                |   90 +-
+ bin/pkcs11/pkcs11-list.c                     |  118 +-
+ bin/pkcs11/pkcs11-tokens.8                   |   51 +
+ bin/pkcs11/pkcs11-tokens.c                   |  106 ++
+ bin/pkcs11/pkcs11-tokens.docbook             |   86 ++
+ bin/pkcs11/pkcs11-tokens.html                |   58 +
+ bin/rndc/Makefile.in                         |    3 +-
+ bin/tests/Makefile.in                        |   76 +-
+ bin/tests/dst/dst_test.c                     |    7 +-
+ bin/tests/dst/t_dst.c                        |   14 +-
+ bin/tests/pkcs11/Makefile.in                 |   49 +
+ bin/tests/pkcs11/benchmarks/Makefile.in      |   79 +
+ bin/tests/pkcs11/benchmarks/create.c         |  260 ++++
+ bin/tests/pkcs11/benchmarks/find.c           |  227 +++
+ bin/tests/pkcs11/benchmarks/genrsa.c         |  295 ++++
+ bin/tests/pkcs11/benchmarks/login.c          |  249 ++++
+ bin/tests/pkcs11/benchmarks/privrsa.c        |  360 +++++
+ bin/tests/pkcs11/benchmarks/pubrsa.c         |  281 ++++
+ bin/tests/pkcs11/benchmarks/random.c         |  192 +++
+ bin/tests/pkcs11/benchmarks/session.c        |  213 +++
+ bin/tests/pkcs11/benchmarks/sha1.c           |  214 +++
+ bin/tests/pkcs11/benchmarks/sign.c           |  368 +++++
+ bin/tests/pkcs11/benchmarks/verify.c         |  292 ++++
+ bin/tests/pkcs11/pkcs11-hmacmd5.c            |  332 +++++
+ bin/tests/pkcs11/pkcs11-md5sum.c             |  235 +++
+ bin/tests/system/autosign/prereq.sh          |    3 +-
+ bin/tests/system/cleanpkcs11.sh              |    6 +-
+ bin/tests/system/conf.sh.in                  |    8 +-
+ bin/tests/system/dnssec/prereq.sh            |    3 +-
+ bin/tests/system/ecdsa/prereq.sh.in          |   15 +-
+ bin/tests/system/gost/prereq.sh.in           |   15 +-
+ bin/tests/system/inline/clean.sh             |    2 +-
+ bin/tests/system/metadata/prereq.sh          |    3 +-
+ bin/tests/system/pending/prereq.sh           |   23 +-
+ bin/tests/system/pkcs11/clean.sh             |    5 +-
+ bin/tests/system/pkcs11/ns1/named.conf       |   10 +-
+ bin/tests/system/pkcs11/setup.sh             |   64 +-
+ bin/tests/system/pkcs11/tests.sh             |   72 +-
+ bin/tests/system/pkcs11ssl/clean.sh          |   20 +
+ bin/tests/system/pkcs11ssl/ns1/example.db.in |   29 +
+ bin/tests/system/pkcs11ssl/ns1/named.conf    |   52 +
+ bin/tests/system/pkcs11ssl/prereq.sh         |   34 +
+ bin/tests/system/pkcs11ssl/setup.sh          |   46 +
+ bin/tests/system/pkcs11ssl/tests.sh          |   71 +
+ bin/tests/system/pkcs11ssl/usepkcs11         |    1 +
+ bin/tests/system/rsabigexponent/Makefile.in  |    2 +-
+ bin/tests/system/rsabigexponent/bigkey.c     |   18 +-
+ bin/tests/system/rsabigexponent/prereq.sh    |    3 +-
+ bin/tests/system/smartsign/prereq.sh         |    3 +-
+ bin/tests/system/tkey/keycreate.c            |    1 +
+ bin/tests/system/tkey/prereq.sh              |    3 +-
+ config.h.in                                  |   19 +-
+ configure.in                                 |  383 ++++-
+ doc/arm/pkcs11.xml                           |  694 +++++----
+ lib/dns/Makefile.in                          |   16 +-
+ lib/dns/dnssec.c                             |   12 +-
+ lib/dns/ds.c                                 |   44 +-
+ lib/dns/dst_api.c                            |   73 +-
+ lib/dns/dst_gost.h                           |   57 +
+ lib/dns/dst_internal.h                       |   28 +-
+ lib/dns/dst_parse.c                          |   36 +-
+ lib/dns/dst_parse.h                          |    6 +-
+ lib/dns/dst_pkcs11.h                         |   43 +
+ lib/dns/dst_result.c                         |    3 +-
+ lib/dns/gssapi_link.c                        |    1 +
+ lib/dns/hmac_link.c                          |   47 +-
+ lib/dns/include/dst/dst.h                    |   10 +
+ lib/dns/include/dst/result.h                 |    3 +-
+ lib/dns/openssldh_link.c                     |    7 +
+ lib/dns/openssldsa_link.c                    |   36 +-
+ lib/dns/opensslecdsa_link.c                  |   73 +-
+ lib/dns/opensslgost_link.c                   |  180 ++-
+ lib/dns/opensslrsa_link.c                    |   35 +-
+ lib/dns/pkcs11.c                             |   50 +
+ lib/dns/pkcs11dh_link.c                      | 1140 +++++++++++++++
+ lib/dns/pkcs11dsa_link.c                     | 1130 +++++++++++++++
+ lib/dns/pkcs11ecdsa_link.c                   | 1189 ++++++++++++++++
+ lib/dns/pkcs11gost_link.c                    |  949 +++++++++++++
+ lib/dns/pkcs11rsa_link.c                     | 1583 +++++++++++++++++++++
+ lib/dns/rdata/generic/dlv_32769.c            |    9 +
+ lib/dns/rdata/generic/ds_43.c                |   10 +
+ lib/dns/tests/Makefile.in                    |   14 +-
+ lib/dns/tests/gost_test.c                    |  232 +++
+ lib/dns/tkey.c                               |   10 +-
+ lib/dns/tsig.c                               |   14 +-
+ lib/export/dns/Makefile.in                   |    4 +-
+ lib/export/isc/Makefile.in                   |    5 +-
+ lib/export/isc/unix/Makefile.in              |    4 +
+ lib/isc/Makefile.in                          |   14 +-
+ lib/isc/entropy.c                            |    8 +
+ lib/isc/hmacmd5.c                            |  166 +++
+ lib/isc/hmacsha.c                            |  375 +++++
+ lib/isc/include/Makefile.in                  |    2 +-
+ lib/isc/include/isc/hmacmd5.h                |    5 +
+ lib/isc/include/isc/hmacsha.h                |    9 +
+ lib/isc/include/isc/md5.h                    |    5 +
+ lib/isc/include/isc/resultclass.h            |    2 +-
+ lib/isc/include/isc/sha1.h                   |    5 +
+ lib/isc/include/isc/sha2.h                   |    6 +
+ lib/isc/include/pk11/Makefile.in             |   38 +
+ lib/isc/include/pk11/constants.h             |  107 ++
+ lib/isc/include/pk11/internal.h              |   46 +
+ lib/isc/include/pk11/pk11.h                  |  295 ++++
+ lib/isc/include/pk11/result.h                |   56 +
+ lib/isc/include/pkcs11/Makefile.in           |   40 +
+ lib/isc/include/pkcs11/pkcs11.h              |  299 ++++
+ lib/isc/include/pkcs11/pkcs11f.h             |  912 ++++++++++++
+ lib/isc/include/pkcs11/pkcs11t.h             | 1977 ++++++++++++++++++++++++++
+ lib/isc/md5.c                                |   50 +
+ lib/isc/pk11.c                               | 1327 +++++++++++++++++
+ lib/isc/pk11_result.c                        |   85 ++
+ lib/isc/sha1.c                               |   50 +-
+ lib/isc/sha2.c                               |  279 ++++
+ lib/isc/unix/Makefile.in                     |    4 +-
+ lib/isc/unix/include/Makefile.in             |    2 +-
+ lib/isc/unix/include/pkcs11/Makefile.in      |   33 +
+ lib/isc/unix/include/pkcs11/cryptoki.h       |   66 +
+ lib/isc/unix/pk11_api.c                      |  673 +++++++++
+ 153 files changed, 20271 insertions(+), 1183 deletions(-)
+ create mode 100644 bin/pkcs11/pkcs11-tokens.8
+ create mode 100644 bin/pkcs11/pkcs11-tokens.c
+ create mode 100644 bin/pkcs11/pkcs11-tokens.docbook
+ create mode 100644 bin/pkcs11/pkcs11-tokens.html
+ create mode 100644 bin/tests/pkcs11/Makefile.in
+ create mode 100644 bin/tests/pkcs11/benchmarks/Makefile.in
+ create mode 100644 bin/tests/pkcs11/benchmarks/create.c
+ create mode 100644 bin/tests/pkcs11/benchmarks/find.c
+ create mode 100644 bin/tests/pkcs11/benchmarks/genrsa.c
+ create mode 100644 bin/tests/pkcs11/benchmarks/login.c
+ create mode 100644 bin/tests/pkcs11/benchmarks/privrsa.c
+ create mode 100644 bin/tests/pkcs11/benchmarks/pubrsa.c
+ create mode 100644 bin/tests/pkcs11/benchmarks/random.c
+ create mode 100644 bin/tests/pkcs11/benchmarks/session.c
+ create mode 100644 bin/tests/pkcs11/benchmarks/sha1.c
+ create mode 100644 bin/tests/pkcs11/benchmarks/sign.c
+ create mode 100644 bin/tests/pkcs11/benchmarks/verify.c
+ create mode 100644 bin/tests/pkcs11/pkcs11-hmacmd5.c
+ create mode 100644 bin/tests/pkcs11/pkcs11-md5sum.c
+ create mode 100644 bin/tests/system/pkcs11ssl/clean.sh
+ create mode 100644 bin/tests/system/pkcs11ssl/ns1/example.db.in
+ create mode 100644 bin/tests/system/pkcs11ssl/ns1/named.conf
+ create mode 100644 bin/tests/system/pkcs11ssl/prereq.sh
+ create mode 100644 bin/tests/system/pkcs11ssl/setup.sh
+ create mode 100644 bin/tests/system/pkcs11ssl/tests.sh
+ create mode 100644 bin/tests/system/pkcs11ssl/usepkcs11
+ create mode 100644 lib/dns/dst_gost.h
+ create mode 100644 lib/dns/dst_pkcs11.h
+ create mode 100644 lib/dns/pkcs11.c
+ create mode 100644 lib/dns/pkcs11dh_link.c
+ create mode 100644 lib/dns/pkcs11dsa_link.c
+ create mode 100644 lib/dns/pkcs11ecdsa_link.c
+ create mode 100644 lib/dns/pkcs11gost_link.c
+ create mode 100644 lib/dns/pkcs11rsa_link.c
+ create mode 100644 lib/dns/tests/gost_test.c
+ create mode 100644 lib/isc/include/pk11/Makefile.in
+ create mode 100644 lib/isc/include/pk11/constants.h
+ create mode 100644 lib/isc/include/pk11/internal.h
+ create mode 100644 lib/isc/include/pk11/pk11.h
+ create mode 100644 lib/isc/include/pk11/result.h
+ create mode 100644 lib/isc/include/pkcs11/Makefile.in
+ create mode 100644 lib/isc/include/pkcs11/pkcs11.h
+ create mode 100644 lib/isc/include/pkcs11/pkcs11f.h
+ create mode 100644 lib/isc/include/pkcs11/pkcs11t.h
+ create mode 100644 lib/isc/pk11.c
+ create mode 100644 lib/isc/pk11_result.c
+ create mode 100644 lib/isc/unix/include/pkcs11/Makefile.in
+ create mode 100644 lib/isc/unix/include/pkcs11/cryptoki.h
+ create mode 100644 lib/isc/unix/pk11_api.c
+
+diff --git a/acconfig.h b/acconfig.h
+index 3d412d9..c8e832a 100644
+--- a/acconfig.h
++++ b/acconfig.h
+@@ -132,14 +132,11 @@ int sigwait(const unsigned int *set, int *sig);
+ /** define if you have strerror in the C library. */
+ #undef HAVE_STRERROR
+ 
+-/** Define if you are running under Compaq TruCluster. */
+-#undef HAVE_TRUCLUSTER
+-
+ /* Define if OpenSSL includes DSA support */
+ #undef HAVE_OPENSSL_DSA
+ 
+-/* Define if OpenSSL includes ECDSA support */
+-#undef HAVE_OPENSSL_ECDSA
++/* Define if you have getpassphrase in the C library. */
++#undef HAVE_GETPASSPHRASE
+ 
+ /* Define to the length type used by the socket API (socklen_t, size_t, int). */
+ #undef ISC_SOCKADDR_LEN_T
+diff --git a/bin/check/Makefile.in b/bin/check/Makefile.in
+index c191605..d585480 100644
+--- a/bin/check/Makefile.in
++++ b/bin/check/Makefile.in
+@@ -75,7 +75,8 @@ named-checkconf@EXEEXT@: named-checkconf.@O@ check-tool.@O@ ${ISCDEPLIBS} \
+ 	export LIBS0="${BIND9LIBS} ${ISCCFGLIBS} ${DNSLIBS}"; \
+ 	${FINALBUILDCMD}
+ 
+-named-checkzone@EXEEXT@: named-checkzone.@O@ check-tool.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
++named-checkzone@EXEEXT@: named-checkzone.@O@ check-tool.@O@ \
++		${ISCDEPLIBS} ${DNSDEPLIBS}
+ 	export BASEOBJS="named-checkzone.@O@ check-tool.@O@"; \
+ 	export LIBS0="${ISCCFGLIBS} ${DNSLIBS}"; \
+ 	${FINALBUILDCMD}
+diff --git a/bin/dig/Makefile.in b/bin/dig/Makefile.in
+index 3864e06..43dd061 100644
+--- a/bin/dig/Makefile.in
++++ b/bin/dig/Makefile.in
+@@ -28,7 +28,7 @@ READLINE_LIB = @READLINE_LIB@
+ CINCLUDES =	-I${srcdir}/include ${DNS_INCLUDES} ${BIND9_INCLUDES} \
+ 		${ISC_INCLUDES} ${LWRES_INCLUDES} ${ISCCFG_INCLUDES}
+ 
+-CDEFINES =	-DVERSION=\"${VERSION}\"
++CDEFINES =	-DVERSION=\"${VERSION}\" @CRYPTO@
+ CWARNINGS =
+ 
+ ISCCFGLIBS =	../../lib/isccfg/libisccfg.@A@
+@@ -44,13 +44,13 @@ BIND9DEPLIBS =	../../lib/bind9/libbind9.@A@
+ ISCDEPLIBS =	../../lib/isc/libisc.@A@
+ LWRESDEPLIBS =	../../lib/lwres/liblwres.@A@
+ 
+-DEPLIBS =	${DNSDEPLIBS} ${BIND9DEPLIBS} ${ISCDEPLIBS} ${ISCCFGDEPLIBS} \
+-		${LWRESDEPLIBS}
++DEPLIBS =	${DNSDEPLIBS} ${BIND9DEPLIBS} ${ISCDEPLIBS} \
++		${ISCCFGDEPLIBS} ${LWRESDEPLIBS}
+ 
+-LIBS =		${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \
++LIBS =		${LWRESLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \
+ 		${ISCLIBS} @IDNLIBS@ @LIBS@ -lidn
+ 
+-NOSYMLIBS =	${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \
++NOSYMLIBS =	${LWRESLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \
+ 		${ISCNOSYMLIBS} @IDNLIBS@ @LIBS@ -lidn
+ 
+ SUBDIRS =
+@@ -75,14 +75,17 @@ EXT_CFLAGS = -DWITH_LIBIDN
+ 
+ dig@EXEEXT@: dig.@O@ dighost.@O@ ${UOBJS} ${DEPLIBS}
+ 	export BASEOBJS="dig.@O@ dighost.@O@ ${UOBJS}"; \
++	export LIBS0="${DNSLIBS}"; \
+ 	${FINALBUILDCMD}
+ 
+ host@EXEEXT@: host.@O@ dighost.@O@ ${UOBJS} ${DEPLIBS}
+ 	export BASEOBJS="host.@O@ dighost.@O@ ${UOBJS}"; \
++	export LIBS0="${DNSLIBS}"; \
+ 	${FINALBUILDCMD}
+ 
+ nslookup@EXEEXT@: nslookup.@O@ dighost.@O@ ${UOBJS} ${DEPLIBS}
+ 	export BASEOBJS="nslookup.@O@ dighost.@O@ ${READLINE_LIB} ${UOBJS}"; \
++	export LIBS0="${DNSLIBS}"; \
+ 	${FINALBUILDCMD}
+ 
+ doc man:: ${MANOBJS}
+diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c
+index e2bb110..5c03d95 100644
+--- a/bin/dig/dighost.c
++++ b/bin/dig/dighost.c
+@@ -105,6 +105,10 @@
+ 
+ #include <dig/dig.h>
+ 
++#ifdef PKCS11CRYPTO
++#include <pk11/result.h>
++#endif
++
+ #if ! defined(NS_INADDRSZ)
+ #define NS_INADDRSZ	 4
+ #endif
+@@ -1347,6 +1351,11 @@ setup_libs(void) {
+ 
+ 	debug("setup_libs()");
+ 
++#ifdef PKCS11CRYPTO
++	pk11_result_register();
++#endif
++	dns_result_register();
++
+ 	result = isc_net_probeipv4();
+ 	if (result == ISC_R_SUCCESS)
+ 		have_ipv4 = ISC_TRUE;
+@@ -1403,8 +1412,6 @@ setup_libs(void) {
+ 
+ 	result = isc_mutex_init(&lookup_lock);
+ 	check_result(result, "isc_mutex_init");
+-
+-	dns_result_register();
+ }
+ 
+ /*%
+diff --git a/bin/dnssec/Makefile.in b/bin/dnssec/Makefile.in
+index ecb0fae..64e1846 100644
+--- a/bin/dnssec/Makefile.in
++++ b/bin/dnssec/Makefile.in
+@@ -25,7 +25,8 @@ top_srcdir =	@top_srcdir@
+ 
+ CINCLUDES =	${DNS_INCLUDES} ${ISC_INCLUDES}
+ 
+-CDEFINES =	-DVERSION=\"${VERSION}\" @USE_PKCS11@
++CDEFINES =	-DVERSION=\"${VERSION}\" @USE_PKCS11@ @PKCS11_ENGINE@ \
++		@CRYPTO@ -DPK11_LIB_LOCATION=\"@PKCS11_PROVIDER@\"
+ CWARNINGS =
+ 
+ DNSLIBS =	../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
+diff --git a/bin/dnssec/dnssec-dsfromkey.c b/bin/dnssec/dnssec-dsfromkey.c
+index bfedae8..df616ac 100644
+--- a/bin/dnssec/dnssec-dsfromkey.c
++++ b/bin/dnssec/dnssec-dsfromkey.c
+@@ -49,6 +49,10 @@
+ 
+ #include <dst/dst.h>
+ 
++#ifdef PKCS11CRYPTO
++#include <pk11/result.h>
++#endif
++
+ #include "dnssectool.h"
+ 
+ #ifndef PATH_MAX
+@@ -370,6 +374,9 @@ main(int argc, char **argv) {
+ 	if (result != ISC_R_SUCCESS)
+ 		fatal("out of memory");
+ 
++#ifdef PKCS11CRYPTO
++	pk11_result_register();
++#endif
+ 	dns_result_register();
+ 
+ 	isc_commandline_errprint = ISC_FALSE;
+@@ -448,7 +455,7 @@ main(int argc, char **argv) {
+ 		else if (strcasecmp(algname, "SHA256") == 0 ||
+ 			 strcasecmp(algname, "SHA-256") == 0)
+ 			dtype = DNS_DSDIGEST_SHA256;
+-#ifdef HAVE_OPENSSL_GOST
++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
+ 		else if (strcasecmp(algname, "GOST") == 0)
+ 			dtype = DNS_DSDIGEST_GOST;
+ #endif
+diff --git a/bin/dnssec/dnssec-importkey.c b/bin/dnssec/dnssec-importkey.c
+index 00f9200..73166c4 100644
+--- a/bin/dnssec/dnssec-importkey.c
++++ b/bin/dnssec/dnssec-importkey.c
+@@ -47,6 +47,10 @@
+ 
+ #include <dst/dst.h>
+ 
++#ifdef PKCS11CRYPTO
++#include <pk11/result.h>
++#endif
++
+ #include "dnssectool.h"
+ 
+ #ifndef PATH_MAX
+@@ -61,7 +65,9 @@ static dns_fixedname_t	fixed;
+ static dns_name_t	*name = NULL;
+ static isc_mem_t	*mctx = NULL;
+ static isc_boolean_t	setpub = ISC_FALSE, setdel = ISC_FALSE;
++static isc_boolean_t	setttl = ISC_FALSE;
+ static isc_stdtime_t	pub = 0, del = 0;
++static dns_ttl_t	ttl = 0;
+ 
+ static isc_result_t
+ initname(char *setname) {
+@@ -190,9 +196,10 @@ static void
+ emit(const char *dir, dns_rdata_t *rdata) {
+ 	isc_result_t result;
+ 	char keystr[DST_KEY_FORMATSIZE];
+-	char newname[1024];
++	char pubname[1024];
++	char priname[1024];
+ 	isc_buffer_t buf;
+-	dst_key_t *key = NULL;
++	dst_key_t *key = NULL, *tmp = NULL;
+ 
+ 	isc_buffer_init(&buf, rdata->data, rdata->length);
+ 	isc_buffer_add(&buf, rdata->length);
+@@ -201,18 +208,36 @@ emit(const char *dir, dns_rdata_t *rdata) {
+ 		fatal("dst_key_fromdns: %s", isc_result_totext(result));
+ 	}
+ 
+-	dst_key_setexternal(key, ISC_TRUE);
+-	if (setpub)
+-		dst_key_settime(key, DST_TIME_PUBLISH, pub);
+-	if (setdel)
+-		dst_key_settime(key, DST_TIME_DELETE, del);
+-
+-	isc_buffer_init(&buf, newname, sizeof(newname));
++	isc_buffer_init(&buf, pubname, sizeof(pubname));
+ 	result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf);
+ 	if (result != ISC_R_SUCCESS) {
+ 		fatal("Failed to build public key filename: %s",
+ 		      isc_result_totext(result));
+ 	}
++	isc_buffer_init(&buf, priname, sizeof(priname));
++	result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf);
++	if (result != ISC_R_SUCCESS) {
++		fatal("Failed to build private key filename: %s",
++		      isc_result_totext(result));
++	}
++
++	result = dst_key_fromfile(dst_key_name(key), dst_key_id(key),
++				  dst_key_alg(key),
++				  DST_TYPE_PUBLIC | DST_TYPE_PRIVATE,
++				  dir, mctx, &tmp);
++	if (result == ISC_R_SUCCESS) {
++		if (dst_key_isprivate(tmp) && !dst_key_isexternal(tmp))
++			fatal("Private key already exists in %s", priname);
++		dst_key_free(&tmp);
++	}
++
++	dst_key_setexternal(key, ISC_TRUE);
++	if (setpub)
++		dst_key_settime(key, DST_TIME_PUBLISH, pub);
++	if (setdel)
++		dst_key_settime(key, DST_TIME_DELETE, del);
++	if (setttl)
++		dst_key_setttl(key, ttl);
+ 
+ 	result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
+ 				dir);
+@@ -221,8 +246,7 @@ emit(const char *dir, dns_rdata_t *rdata) {
+ 		fatal("Failed to write key %s: %s", keystr,
+ 		      isc_result_totext(result));
+ 	}
+-
+-	printf("%s\n", newname);
++	printf("%s\n", pubname);
+ 
+ 	isc_buffer_clear(&buf);
+ 	result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf);
+@@ -230,7 +254,7 @@ emit(const char *dir, dns_rdata_t *rdata) {
+ 		fatal("Failed to build private key filename: %s",
+ 		      isc_result_totext(result));
+ 	}
+-	printf("%s\n", newname);
++	printf("%s\n", priname);
+ 	dst_key_free(&key);
+ }
+ 
+@@ -240,13 +264,21 @@ usage(void) ISC_PLATFORM_NORETURN_POST;
+ static void
+ usage(void) {
+ 	fprintf(stderr, "Usage:\n");
+-	fprintf(stderr,	"    %s options [-K dir] file\n\n", program);
++	fprintf(stderr,	"    %s options [-K dir] keyfile\n\n", program);
++	fprintf(stderr, "    %s options -f file [keyname]\n\n", program);
+ 	fprintf(stderr, "Version: %s\n", VERSION);
+ 	fprintf(stderr, "Options:\n");
+-	fprintf(stderr, "    -v <verbose level>\n");
++	fprintf(stderr, "    -f file: read key from zone file\n");
+ 	fprintf(stderr, "    -K <directory>: directory in which to store "
+-			"the keyset files\n");
+-	fprintf(stderr, "    -f file: read keyset from zone file\n");
++				"the key files\n");
++	fprintf(stderr, "    -L ttl:             set default key TTL\n");
++	fprintf(stderr, "    -v <verbose level>\n");
++	fprintf(stderr, "    -h: print usage and exit\n");
++	fprintf(stderr, "Timing options:\n");
++	fprintf(stderr, "    -P date/[+-]offset/none: set/unset key "
++						     "publication date\n");
++	fprintf(stderr, "    -D date/[+-]offset/none: set/unset key "
++						     "deletion date\n");
+ 
+ 	exit (-1);
+ }
+@@ -274,15 +306,19 @@ main(int argc, char **argv) {
+ 	if (result != ISC_R_SUCCESS)
+ 		fatal("out of memory");
+ 
++#ifdef PKCS11CRYPTO
++	pk11_result_register();
++#endif
+ 	dns_result_register();
+ 
+ 	isc_commandline_errprint = ISC_FALSE;
+ 
+-	while ((ch = isc_commandline_parse(argc, argv, "D:f:hK:P:v:")) != -1) {
++#define CMDLINE_FLAGS "D:f:hK:L:P:v:"
++	while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
+ 		switch (ch) {
+-                case 'D':
+-                        if (setdel)
+-                                fatal("-D specified more than once");
++		case 'D':
++			if (setdel)
++				fatal("-D specified more than once");
+ 
+ 			setdel = ISC_TRUE;
+ 			del = strtotime(isc_commandline_argument, now, now);
+@@ -292,9 +328,16 @@ main(int argc, char **argv) {
+ 			if (strlen(dir) == 0U)
+ 				fatal("directory must be non-empty string");
+ 			break;
+-                case 'P':
+-                        if (setpub)
+-                                fatal("-P specified more than once");
++		case 'L':
++			if (strcmp(isc_commandline_argument, "none") == 0)
++				ttl = 0;
++			else
++				ttl = strtottl(isc_commandline_argument);
++			setttl = ISC_TRUE;
++			break;
++		case 'P':
++			if (setpub)
++				fatal("-P specified more than once");
+ 
+ 			setpub = ISC_TRUE;
+ 			pub = strtotime(isc_commandline_argument, now, now);
+@@ -346,8 +389,8 @@ main(int argc, char **argv) {
+ 	dns_rdataset_init(&rdataset);
+ 
+ 	if (filename != NULL) {
+-		if (argc < isc_commandline_index + 1 && filename != NULL) {
+-			/* using zone name as the zone file name */
++		if (argc < isc_commandline_index + 1) {
++			/* using filename as zone name */
+ 			namestr = filename;
+ 		} else
+ 			namestr = argv[isc_commandline_index];
+diff --git a/bin/dnssec/dnssec-importkey.docbook b/bin/dnssec/dnssec-importkey.docbook
+index b8d160c..853db30 100644
+--- a/bin/dnssec/dnssec-importkey.docbook
++++ b/bin/dnssec/dnssec-importkey.docbook
+@@ -44,22 +44,45 @@
+   <refsynopsisdiv>
+     <cmdsynopsis>
+       <command>dnssec-importkey</command>
+-      <arg><option>-f <replaceable class="parameter">filename</replaceable></option></arg>
+       <arg><option>-K <replaceable class="parameter">directory</replaceable></option></arg>
++      <arg><option>-L <replaceable class="parameter">ttl</replaceable></option></arg>
+       <arg><option>-P <replaceable class="parameter">date/offset</replaceable></option></arg>
+       <arg><option>-D <replaceable class="parameter">date/offset</replaceable></option></arg>
+       <arg><option>-h</option></arg>
+       <arg><option>-v <replaceable class="parameter">level</replaceable></option></arg>
+-      <arg><option>keyname</option></arg>
++      <arg choice="req"><option>keyfile</option></arg>
++    </cmdsynopsis>
++    <cmdsynopsis>
++      <command>dnssec-importkey</command>
++      <arg choice="req"><option>-f <replaceable class="parameter">filename</replaceable></option></arg>
++      <arg><option>-K <replaceable class="parameter">directory</replaceable></option></arg>
++      <arg><option>-L <replaceable class="parameter">ttl</replaceable></option></arg>
++      <arg><option>-P <replaceable class="parameter">date/offset</replaceable></option></arg>
++      <arg><option>-D <replaceable class="parameter">date/offset</replaceable></option></arg>
++      <arg><option>-h</option></arg>
++      <arg><option>-v <replaceable class="parameter">level</replaceable></option></arg>
++      <arg><option>dnsname</option></arg>
+     </cmdsynopsis>
+   </refsynopsisdiv>
+ 
+   <refsect1>
+     <title>DESCRIPTION</title>
+     <para><command>dnssec-importkey</command>
+-      read a DNSKEY record and generated a .key/.private key pair.
+-      Publication (<option>-P</option>) and deletions (<option>-D</option>)
+-      times can be set for the key.
++      reads a public DNSKEY record and generates a pair of
++      .key/.private files.  The DNSKEY record may be read from an
++      existing .key file, in which case a corresponding .private file
++      will be generated, or it may be read from any other file or
++      from the standard input, in which case both .key and .private
++      files will be generated.
++    </para>
++    <para>
++      The newly-created .private file does <emphasis>not</command>
++      contain private key data, and cannot be used for signing.
++      However, having a .private file makes it possible to set
++      publication (<option>-P</option>) and deletion
++      (<option>-D</option>) times for the key, which means the
++      public key can be added to and removed from the DNSKEY RRset
++      on schedule even if the true private key is stored offline.
+     </para>
+   </refsect1>
+ 
+@@ -70,9 +93,16 @@
+       <varlistentry>
+ 	<term>-f <replaceable class="parameter">filename</replaceable></term>
+         <listitem>
+-	  <para>
+-	    Filename to read the key from.
+-	  </para>
++          <para>
++            Zone file mode: instead of a public keyfile name, the argument
++	    is the DNS domain name of a zone master file, which can be read
++            from <option>file</option>.  If the domain name is the same as
++            <option>file</option>, then it may be omitted.
++          </para>
++          <para>
++            If <option>file</option> is set to <literal>"-"</literal>, then
++            the zone data is read from the standard input.
++          </para>
+         </listitem>
+       </varlistentry>
+   
+@@ -93,7 +123,7 @@
+             into a DNSKEY RR.  If the key is imported into a zone,
+             this is the TTL that will be used for it, unless there was
+             already a DNSKEY RRset in place, in which case the existing TTL
+-            would take precedence.  importkey the default TTL to
++            would take precedence.  Setting the default TTL to
+             <literal>0</literal> or <literal>none</literal> removes it.
+           </para>
+         </listitem>
+@@ -160,6 +190,16 @@
+   </refsect1>
+ 
+   <refsect1>
++    <title>FILES</title>
++    <para>
++      A keyfile can be designed by the key identification
++      <filename>Knnnn.+aaa+iiiii</filename> or the full file name
++      <filename>Knnnn.+aaa+iiiii.key</filename> as generated by
++      <refentrytitle>dnssec-keygen</refentrytitle><manvolnum>8</manvolnum>.
++    </para>
++  </refsect1>
++
++  <refsect1>
+     <title>SEE ALSO</title>
+     <para><citerefentry>
+         <refentrytitle>dnssec-keygen</refentrytitle><manvolnum>8</manvolnum>
+diff --git a/bin/dnssec/dnssec-keyfromlabel.c b/bin/dnssec/dnssec-keyfromlabel.c
+index 3ad00d7..cc212e1 100644
+--- a/bin/dnssec/dnssec-keyfromlabel.c
++++ b/bin/dnssec/dnssec-keyfromlabel.c
+@@ -43,6 +43,10 @@
+ 
+ #include <dst/dst.h>
+ 
++#ifdef PKCS11CRYPTO
++#include <pk11/result.h>
++#endif
++
+ #include "dnssectool.h"
+ 
+ #define MAX_RSA 4096 /* should be long enough... */
+@@ -76,10 +80,15 @@ usage(void) {
+ 			       "NSEC3RSASHA1 if using -3)\n");
+ 	fprintf(stderr, "    -3: use NSEC3-capable algorithm\n");
+ 	fprintf(stderr, "    -c class (default: IN)\n");
+-#ifdef USE_PKCS11
+-	fprintf(stderr, "    -E enginename (default: pkcs11)\n");
++	fprintf(stderr, "    -E <engine>:\n");
++#if defined(PKCS11CRYPTO)
++	fprintf(stderr, "        path to PKCS#11 provider library "
++				"(default is %s)\n", PK11_LIB_LOCATION);
++#elif defined(USE_PKCS11)
++	fprintf(stderr, "        name of an OpenSSL engine to use "
++				"(default is \"pkcs11\")\n");
+ #else
+-	fprintf(stderr, "    -E enginename\n");
++	fprintf(stderr, "        name of an OpenSSL engine to use\n");
+ #endif
+ 	fprintf(stderr, "    -f keyflag: KSK | REVOKE\n");
+ 	fprintf(stderr, "    -K directory: directory in which to place "
+@@ -116,7 +125,7 @@ main(int argc, char **argv) {
+ 	char		*nametype = NULL, *type = NULL;
+ 	const char	*directory = NULL;
+ #ifdef USE_PKCS11
+-	const char	*engine = "pkcs11";
++	const char	*engine = PKCS11_ENGINE;
+ #else
+ 	const char	*engine = NULL;
+ #endif
+@@ -161,6 +170,9 @@ main(int argc, char **argv) {
+ 
+ 	RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
+ 
++#ifdef PKCS11CRYPTO
++	pk11_result_register();
++#endif
+ 	dns_result_register();
+ 
+ 	isc_commandline_errprint = ISC_FALSE;
+@@ -334,16 +346,15 @@ main(int argc, char **argv) {
+ 	if (argc > isc_commandline_index + 1)
+ 		fatal("extraneous arguments");
+ 
+-	if (strchr(label, ':') == NULL &&
+-	    engine != NULL && strlen(engine) != 0U) {
++	if (strchr(label, ':') == NULL) {
+ 		char *l;
+ 		int len;
+ 
+-		len = strlen(label) + strlen(engine) + 2;
++		len = strlen(label) + 8;
+ 		l = isc_mem_allocate(mctx, len);
+ 		if (l == NULL)
+ 			fatal("cannot allocate memory");
+-		snprintf(l, len, "%s:%s", engine, label);
++		snprintf(l, len, "pkcs11:%s", label);
+ 		isc_mem_free(mctx, label);
+ 		label = l;
+ 	}
+@@ -460,7 +471,7 @@ main(int argc, char **argv) {
+ 
+ 	/* associate the key */
+ 	ret = dst_key_fromlabel(name, alg, flags, protocol,
+-				rdclass, engine, label, NULL, mctx, &key);
++				rdclass, "pkcs11", label, NULL, mctx, &key);
+ 	isc_entropy_stopcallbacksources(ectx);
+ 
+ 	if (ret != ISC_R_SUCCESS) {
+@@ -468,7 +479,7 @@ main(int argc, char **argv) {
+ 		char algstr[DNS_SECALG_FORMATSIZE];
+ 		dns_name_format(name, namestr, sizeof(namestr));
+ 		dns_secalg_format(alg, algstr, sizeof(algstr));
+-		fatal("failed to get key %s/%s: %s\n",
++		fatal("failed to get key %s/%s: %s",
+ 		      namestr, algstr, isc_result_totext(ret));
+ 		/* NOTREACHED */
+ 		exit(-1);
+diff --git a/bin/dnssec/dnssec-keyfromlabel.docbook b/bin/dnssec/dnssec-keyfromlabel.docbook
+index 0dd3c0e..c48a100 100644
+--- a/bin/dnssec/dnssec-keyfromlabel.docbook
++++ b/bin/dnssec/dnssec-keyfromlabel.docbook
+@@ -133,8 +133,15 @@
+         <term>-E <replaceable class="parameter">engine</replaceable></term>
+         <listitem>
+           <para>
+-            Specifies the name of the crypto hardware (OpenSSL engine).
+-            When compiled with PKCS#11 support it defaults to "pkcs11".
++            Specifies the cryptographic hardware to use.
++          </para>
++          <para>
++            When BIND is built with OpenSSL PKCS#11 support, this defaults
++            to the string "pkcs11", which identifies an OpenSSL engine
++            that can drive a cryptographic accelerator or hardware service
++            module.  When BIND is built with native PKCS#11 cryptography
++            (--enable-native-pkcs11), it defaults to the path of the PKCS#11
++            provider library specified via "--with-pkcs11".
+           </para>
+         </listitem>
+       </varlistentry>
+@@ -143,9 +150,32 @@
+         <term>-l <replaceable class="parameter">label</replaceable></term>
+         <listitem>
+           <para>
+-            Specifies the label of the key pair in the crypto hardware.
+-            The label may be preceded by an optional OpenSSL engine name,
+-            separated by a colon, as in "pkcs11:keylabel".
++            Specifies the label for a key pair in the crypto hardware.
++          </para>
++          <para>
++            When <acronym>BIND</acronym> 9 is built with OpenSSL-based
++            PKCS#11 support, the label is an arbitrary string that
++            identifies a particular key.  It may be preceded by an
++            optional OpenSSL engine name, followed by a colon, as in
++            "pkcs11:<replaceable>keylabel<replaceable>".
++          </para>
++          <para>
++            When <acronym>BIND</acronym> 9 is built with native PKCS#11
++            support, the label is a PKCS#11 URI string in the format
++            "pkcs11:<option>keyword</option>=<replaceable>value</replaceable><optional>;<option>keyword</option>=<replaceable>value</replaceable>;...</optional>"
++            Keywords include "token", which identifies the HSM; "object", which
++            identifies the key; and "pin-source", which identifies a file from
++            which the HSM's PIN code can be obtained.  The label will be
++            stored in the on-disk "private" file.
++          </para>
++          <para>
++            If the label contains a
++            <option>pin-source</option> field, tools using the generated
++            key files will be able to use the HSM for signing and other
++            operations without any need for an operator to manually enter
++            a PIN.  Note: Making the HSM's PIN accessible in this manner
++            may reduce the security advantage of using an HSM; be sure
++            this is what you want to do before making use of this feature.
+           </para>
+         </listitem>
+       </varlistentry>
+@@ -429,7 +459,8 @@
+         <refentrytitle>dnssec-signzone</refentrytitle><manvolnum>8</manvolnum>
+       </citerefentry>,
+       <citetitle>BIND 9 Administrator Reference Manual</citetitle>,
+-      <citetitle>RFC 4034</citetitle>.
++      <citetitle>RFC 4034</citetitle>,
++      <citetitle>The PKCS#11 URI Scheme (draft-pechanec-pkcs11uri-13)</citetitle>.
+     </para>
+   </refsect1>
+ 
+diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c
+index 7061829..97b96ee 100644
+--- a/bin/dnssec/dnssec-keygen.c
++++ b/bin/dnssec/dnssec-keygen.c
+@@ -58,6 +58,10 @@
+ 
+ #include <dst/dst.h>
+ 
++#ifdef PKCS11CRYPTO
++#include <pk11/result.h>
++#endif
++
+ #include "dnssectool.h"
+ 
+ #define MAX_RSA 4096 /* should be long enough... */
+@@ -119,10 +123,15 @@ usage(void) {
+ 	fprintf(stderr, "        (DNSKEY generation defaults to ZONE)\n");
+ 	fprintf(stderr, "    -c <class>: (default: IN)\n");
+ 	fprintf(stderr, "    -d <digest bits> (0 => max, default)\n");
+-#ifdef USE_PKCS11
+-	fprintf(stderr, "    -E <engine name> (default \"pkcs11\")\n");
++	fprintf(stderr, "    -E <engine>:\n");
++#if defined(PKCS11CRYPTO)
++	fprintf(stderr, "        path to PKCS#11 provider library "
++				"(default is %s)\n", PK11_LIB_LOCATION);
++#elif defined(USE_PKCS11)
++	fprintf(stderr, "        name of an OpenSSL engine to use "
++				"(default is \"pkcs11\")\n");
+ #else
+-	fprintf(stderr, "    -E <engine name>\n");
++	fprintf(stderr, "        name of an OpenSSL engine to use\n");
+ #endif
+ 	fprintf(stderr, "    -f <keyflag>: KSK | REVOKE\n");
+ 	fprintf(stderr, "    -g <generator>: use specified generator "
+@@ -134,7 +143,6 @@ usage(void) {
+ 			"records with (default: 0)\n");
+ 	fprintf(stderr, "    -T <rrtype>: DNSKEY | KEY (default: DNSKEY; "
+ 			"use KEY for SIG(0))\n");
+-	fprintf(stderr, "        ECCGOST:\tignored\n");
+ 	fprintf(stderr, "    -t <type>: "
+ 			"AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF "
+ 			"(default: AUTHCONF)\n");
+@@ -223,7 +231,7 @@ main(int argc, char **argv) {
+ 	isc_log_t	*log = NULL;
+ 	isc_entropy_t	*ectx = NULL;
+ #ifdef USE_PKCS11
+-	const char	*engine = "pkcs11";
++	const char	*engine = PKCS11_ENGINE;
+ #else
+ 	const char	*engine = NULL;
+ #endif
+@@ -250,6 +258,9 @@ main(int argc, char **argv) {
+ 	if (argc == 1)
+ 		usage();
+ 
++#ifdef PKCS11CRYPTO
++	pk11_result_register();
++#endif
+ 	dns_result_register();
+ 
+ 	isc_commandline_errprint = ISC_FALSE;
+diff --git a/bin/dnssec/dnssec-keygen.docbook b/bin/dnssec/dnssec-keygen.docbook
+index bc50c02..4c693eb 100644
+--- a/bin/dnssec/dnssec-keygen.docbook
++++ b/bin/dnssec/dnssec-keygen.docbook
+@@ -224,10 +224,15 @@
+         <term>-E <replaceable class="parameter">engine</replaceable></term>
+         <listitem>
+           <para>
+-            Uses a crypto hardware (OpenSSL engine) for random number
+-            and, when supported, key generation. When compiled with PKCS#11
+-            support it defaults to pkcs11; the empty name resets it to
+-            no engine.
++            Specifies the cryptographic hardware to use, when applicable.
++          </para>
++          <para>
++            When BIND is built with OpenSSL PKCS#11 support, this defaults
++            to the string "pkcs11", which identifies an OpenSSL engine
++            that can drive a cryptographic accelerator or hardware service
++            module.  When BIND is built with native PKCS#11 cryptography
++            (--enable-native-pkcs11), it defaults to the path of the PKCS#11
++            provider library specified via "--with-pkcs11".
+           </para>
+         </listitem>
+       </varlistentry>
+diff --git a/bin/dnssec/dnssec-revoke.c b/bin/dnssec/dnssec-revoke.c
+index 7b11581..7b5aaee 100644
+--- a/bin/dnssec/dnssec-revoke.c
++++ b/bin/dnssec/dnssec-revoke.c
+@@ -38,6 +38,10 @@
+ 
+ #include <dst/dst.h>
+ 
++#ifdef PKCS11CRYPTO
++#include <pk11/result.h>
++#endif
++
+ #include "dnssectool.h"
+ 
+ const char *program = "dnssec-revoke";
+@@ -53,7 +57,10 @@ usage(void) {
+ 	fprintf(stderr, "Usage:\n");
+ 	fprintf(stderr,	"    %s [options] keyfile\n\n", program);
+ 	fprintf(stderr, "Version: %s\n", VERSION);
+-#ifdef USE_PKCS11
++#if defined(PKCS11CRYPTO)
++	fprintf(stderr, "    -E engine:    specify PKCS#11 provider "
++					"(default: %s)\n", PK11_LIB_LOCATION);
++#elif defined(USE_PKCS11)
+ 	fprintf(stderr, "    -E engine:    specify OpenSSL engine "
+ 					   "(default \"pkcs11\")\n");
+ #else
+@@ -76,7 +83,7 @@ int
+ main(int argc, char **argv) {
+ 	isc_result_t result;
+ #ifdef USE_PKCS11
+-	const char *engine = "pkcs11";
++	const char *engine = PKCS11_ENGINE;
+ #else
+ 	const char *engine = NULL;
+ #endif
+@@ -100,6 +107,9 @@ main(int argc, char **argv) {
+ 	if (result != ISC_R_SUCCESS)
+ 		fatal("Out of memory");
+ 
++#ifdef PKCS11CRYPTO
++	pk11_result_register();
++#endif
+ 	dns_result_register();
+ 
+ 	isc_commandline_errprint = ISC_FALSE;
+diff --git a/bin/dnssec/dnssec-revoke.docbook b/bin/dnssec/dnssec-revoke.docbook
+index 4062f5e..0c1dd4e 100644
+--- a/bin/dnssec/dnssec-revoke.docbook
++++ b/bin/dnssec/dnssec-revoke.docbook
+@@ -109,8 +109,15 @@
+         <term>-E <replaceable class="parameter">engine</replaceable></term>
+         <listitem>
+           <para>
+-            Use the given OpenSSL engine. When compiled with PKCS#11 support
+-            it defaults to pkcs11; the empty name resets it to no engine.
++            Specifies the cryptographic hardware to use, when applicable.
++          </para>
++          <para>
++            When BIND is built with OpenSSL PKCS#11 support, this defaults
++            to the string "pkcs11", which identifies an OpenSSL engine
++            that can drive a cryptographic accelerator or hardware service
++            module.  When BIND is built with native PKCS#11 cryptography
++            (--enable-native-pkcs11), it defaults to the path of the PKCS#11
++            provider library specified via "--with-pkcs11".
+           </para>
+         </listitem>
+       </varlistentry>
+diff --git a/bin/dnssec/dnssec-settime.c b/bin/dnssec/dnssec-settime.c
+index 108d803..c71cac7 100644
+--- a/bin/dnssec/dnssec-settime.c
++++ b/bin/dnssec/dnssec-settime.c
+@@ -41,6 +41,10 @@
+ 
+ #include <dst/dst.h>
+ 
++#ifdef PKCS11CRYPTO
++#include <pk11/result.h>
++#endif
++
+ #include "dnssectool.h"
+ 
+ const char *program = "dnssec-settime";
+@@ -57,7 +61,10 @@ usage(void) {
+ 	fprintf(stderr,	"    %s [options] keyfile\n\n", program);
+ 	fprintf(stderr, "Version: %s\n", VERSION);
+ 	fprintf(stderr, "General options:\n");
+-#ifdef USE_PKCS11
++#if defined(PKCS11CRYPTO)
++	fprintf(stderr, "    -E engine:          specify PKCS#11 provider "
++					"(default: %s)\n", PK11_LIB_LOCATION);
++#elif defined(USE_PKCS11)
+ 	fprintf(stderr, "    -E engine:          specify OpenSSL engine "
+ 						 "(default \"pkcs11\")\n");
+ #else
+@@ -119,7 +126,7 @@ int
+ main(int argc, char **argv) {
+ 	isc_result_t	result;
+ #ifdef USE_PKCS11
+-	const char	*engine = "pkcs11";
++	const char	*engine = PKCS11_ENGINE;
+ #else
+ 	const char	*engine = NULL;
+ #endif
+@@ -165,6 +172,9 @@ main(int argc, char **argv) {
+ 
+ 	setup_logging(verbose, mctx, &log);
+ 
++#ifdef PKCS11CRYPTO
++	pk11_result_register();
++#endif
+ 	dns_result_register();
+ 
+ 	isc_commandline_errprint = ISC_FALSE;
+diff --git a/bin/dnssec/dnssec-settime.docbook b/bin/dnssec/dnssec-settime.docbook
+index bc6870b..3540bf2 100644
+--- a/bin/dnssec/dnssec-settime.docbook
++++ b/bin/dnssec/dnssec-settime.docbook
+@@ -153,8 +153,15 @@
+         <term>-E <replaceable class="parameter">engine</replaceable></term>
+         <listitem>
+           <para>
+-            Use the given OpenSSL engine. When compiled with PKCS#11 support
+-            it defaults to pkcs11; the empty name resets it to no engine.
++            Specifies the cryptographic hardware to use, when applicable.
++          </para>
++          <para>
++            When BIND is built with OpenSSL PKCS#11 support, this defaults
++            to the string "pkcs11", which identifies an OpenSSL engine
++            that can drive a cryptographic accelerator or hardware service
++            module.  When BIND is built with native PKCS#11 cryptography
++            (--enable-native-pkcs11), it defaults to the path of the PKCS#11
++            provider library specified via "--with-pkcs11".
+           </para>
+         </listitem>
+       </varlistentry>
+diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c
+index 83456a7..128c753 100644
+--- a/bin/dnssec/dnssec-signzone.c
++++ b/bin/dnssec/dnssec-signzone.c
+@@ -86,6 +86,10 @@
+ 
+ #include <dst/dst.h>
+ 
++#ifdef PKCS11CRYPTO
++#include <pk11/result.h>
++#endif
++
+ #include "dnssectool.h"
+ 
+ #ifndef PATH_MAX
+@@ -2938,7 +2942,10 @@ usage(void) {
+ 	fprintf(stderr, "verify generated signatures\n");
+ 	fprintf(stderr, "\t-c class (IN)\n");
+ 	fprintf(stderr, "\t-E engine:\n");
+-#ifdef USE_PKCS11
++#if defined(PKCS11CRYPTO)
++	fprintf(stderr, "\t\tpath to PKCS#11 provider library "
++		"(default is %s)\n", PK11_LIB_LOCATION);
++#elif defined(USE_PKCS11)
+ 	fprintf(stderr, "\t\tname of an OpenSSL engine to use "
+ 				"(default is \"pkcs11\")\n");
+ #else
+@@ -3033,7 +3040,7 @@ main(int argc, char *argv[]) {
+ 	isc_log_t *log = NULL;
+ 	isc_boolean_t pseudorandom = ISC_FALSE;
+ #ifdef USE_PKCS11
+-	const char *engine = "pkcs11";
++	const char *engine = PKCS11_ENGINE;
+ #else
+ 	const char *engine = NULL;
+ #endif
+@@ -3085,6 +3092,9 @@ main(int argc, char *argv[]) {
+ 	if (result != ISC_R_SUCCESS)
+ 		fatal("out of memory");
+ 
++#ifdef PKCS11CRYPTO
++	pk11_result_register();
++#endif
+ 	dns_result_register();
+ 
+ 	isc_commandline_errprint = ISC_FALSE;
+diff --git a/bin/dnssec/dnssec-signzone.docbook b/bin/dnssec/dnssec-signzone.docbook
+index e427fc1..c46f43c 100644
+--- a/bin/dnssec/dnssec-signzone.docbook
++++ b/bin/dnssec/dnssec-signzone.docbook
+@@ -176,10 +176,17 @@
+         <term>-E <replaceable class="parameter">engine</replaceable></term>
+         <listitem>
+           <para>
+-            Uses a crypto hardware (OpenSSL engine) for the crypto operations
+-            it supports, for instance signing with private keys from
+-            a secure key store. When compiled with PKCS#11 support
+-            it defaults to pkcs11; the empty name resets it to no engine.
++            When applicable, specifies the hardware to use for
++            cryptographic operations, such as a secure key store used
++            for signing.
++          </para>
++          <para>
++            When BIND is built with OpenSSL PKCS#11 support, this defaults
++            to the string "pkcs11", which identifies an OpenSSL engine
++            that can drive a cryptographic accelerator or hardware service
++            module.  When BIND is built with native PKCS#11 cryptography
++            (--enable-native-pkcs11), it defaults to the path of the PKCS#11
++            provider library specified via "--with-pkcs11".
+           </para>
+         </listitem>
+       </varlistentry>
+diff --git a/bin/dnssec/dnssec-verify.c b/bin/dnssec/dnssec-verify.c
+index 682896c..817e380 100644
+--- a/bin/dnssec/dnssec-verify.c
++++ b/bin/dnssec/dnssec-verify.c
+@@ -69,6 +69,10 @@
+ 
+ #include <dst/dst.h>
+ 
++#ifdef PKCS11CRYPTO
++#include <pk11/result.h>
++#endif
++
+ #include "dnssectool.h"
+ 
+ const char *program = "dnssec-verify";
+@@ -137,7 +141,10 @@ usage(void) {
+ 	fprintf(stderr, "\t\tfile format of input zonefile (text)\n");
+ 	fprintf(stderr, "\t-c class (IN)\n");
+ 	fprintf(stderr, "\t-E engine:\n");
+-#ifdef USE_PKCS11
++#if defined(PKCS11CRYPTO)
++	fprintf(stderr, "\t\tpath to PKCS#11 provider library "
++		"(default is %s)\n", PK11_LIB_LOCATION);
++#elif defined(USE_PKCS11)
+ 	fprintf(stderr, "\t\tname of an OpenSSL engine to use "
+ 				"(default is \"pkcs11\")\n");
+ #else
+@@ -156,7 +163,7 @@ main(int argc, char *argv[]) {
+ 	isc_result_t result;
+ 	isc_log_t *log = NULL;
+ #ifdef USE_PKCS11
+-	const char *engine = "pkcs11";
++	const char *engine = PKCS11_ENGINE;
+ #else
+ 	const char *engine = NULL;
+ #endif
+@@ -195,6 +202,9 @@ main(int argc, char *argv[]) {
+ 	if (result != ISC_R_SUCCESS)
+ 		fatal("out of memory");
+ 
++#ifdef PKCS11CRYPTO
++	pk11_result_register();
++#endif
+ 	dns_result_register();
+ 
+ 	isc_commandline_errprint = ISC_FALSE;
+diff --git a/bin/dnssec/dnssec-verify.docbook b/bin/dnssec/dnssec-verify.docbook
+index 0835df1..875f3ed 100644
+--- a/bin/dnssec/dnssec-verify.docbook
++++ b/bin/dnssec/dnssec-verify.docbook
+@@ -78,6 +78,23 @@
+       </varlistentry>
+ 
+       <varlistentry>
++        <term>-E <replaceable class="parameter">engine</replaceable></term>
++        <listitem>
++          <para>
++            Specifies the cryptographic hardware to use, when applicable.
++          </para>
++          <para>
++            When BIND is built with OpenSSL PKCS#11 support, this defaults
++            to the string "pkcs11", which identifies an OpenSSL engine
++            that can drive a cryptographic accelerator or hardware service
++            module.  When BIND is built with native PKCS#11 cryptography
++            (--enable-native-pkcs11), it defaults to the path of the PKCS#11
++            provider library specified via "--with-pkcs11".
++          </para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
+         <term>-I <replaceable class="parameter">input-format</replaceable></term>
+         <listitem>
+           <para>
+diff --git a/bin/dnssec/dnssectool.c b/bin/dnssec/dnssectool.c
+index 5f5f7d8..c68ae69 100644
+--- a/bin/dnssec/dnssectool.c
++++ b/bin/dnssec/dnssectool.c
+@@ -319,7 +319,7 @@ strtotime(const char *str, isc_int64_t now, isc_int64_t base) {
+ 	isc_result_t result;
+ 	const char *orig = str;
+ 	char *endp;
+-	int n;
++	size_t n;
+ 
+ 	if ((str[0] == '0' || str[0] == '-') && str[1] == '\0')
+ 		return ((isc_stdtime_t) 0);
+diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in
+index 68c42a8..cd65777 100644
+--- a/bin/named/Makefile.in
++++ b/bin/named/Makefile.in
+@@ -51,7 +51,7 @@ CINCLUDES =	-I${srcdir}/include -I${srcdir}/unix/include -I. \
+ 		${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} \
+ 		${DLZDRIVER_INCLUDES} ${DBDRIVER_INCLUDES} @DST_OPENSSL_INC@
+ 
+-CDEFINES =      @CONTRIB_DLZ@ @USE_PKCS11@ @USE_OPENSSL@
++CDEFINES =      @CONTRIB_DLZ@ @USE_PKCS11@ @PKCS11_ENGINE@ @CRYPTO@
+ 
+ CWARNINGS =
+ 
+diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h
+index cbc14d8..aad462d 100644
+--- a/bin/named/include/named/globals.h
++++ b/bin/named/include/named/globals.h
+@@ -146,8 +146,8 @@ EXTERN const char *		lwresd_g_defaultpidfile INIT(NS_LOCALSTATEDIR
+ 
+ EXTERN const char *		ns_g_username		INIT(NULL);
+ 
+-#ifdef USE_PKCS11
+-EXTERN const char *		ns_g_engine		INIT("pkcs11");
++#if defined(USE_PKCS11)
++EXTERN const char *		ns_g_engine		INIT(PKCS11_ENGINE);
+ #else
+ EXTERN const char *		ns_g_engine		INIT(NULL);
+ #endif
+diff --git a/bin/named/main.c b/bin/named/main.c
+index 15905ef..a00687f 100644
+--- a/bin/named/main.c
++++ b/bin/named/main.c
+@@ -51,6 +51,9 @@
+ #include <dns/view.h>
+ 
+ #include <dst/result.h>
++#ifdef PKCS11CRYPTO
++#include <pk11/result.h>
++#endif
+ 
+ #include <dlz/dlz_dlopen_driver.h>
+ 
+@@ -1081,6 +1084,9 @@ main(int argc, char *argv[]) {
+ 	dns_result_register();
+ 	dst_result_register();
+ 	isccc_result_register();
++#ifdef PKCS11CRYPTO
++	pk11_result_register();
++#endif
+ 
+ 	parse_command_line(argc, argv);
+ 
+diff --git a/bin/named/named.docbook b/bin/named/named.docbook
+index 1f08e19..8f46aac 100644
+--- a/bin/named/named.docbook
++++ b/bin/named/named.docbook
+@@ -153,11 +153,17 @@
+         <term>-E <replaceable class="parameter">engine-name</replaceable></term>
+         <listitem>
+           <para>
+-            Use a crypto hardware (OpenSSL engine) for the crypto operations
+-            it supports, for instance re-signing with private keys from
+-            a secure key store. When compiled with PKCS#11 support
+-            <replaceable class="parameter">engine-name</replaceable>
+-            defaults to pkcs11, the empty name resets it to no engine.
++            When applicable, specifies the hardware to use for
++            cryptographic operations, such as a secure key store used
++            for signing.
++          </para>
++          <para>
++            When BIND is built with OpenSSL PKCS#11 support, this defaults
++            to the string "pkcs11", which identifies an OpenSSL engine
++            that can drive a cryptographic accelerator or hardware service
++            module.  When BIND is built with native PKCS#11 cryptography
++            (--enable-native-pkcs11), it defaults to the path of the PKCS#11
++            provider library specified via "--with-pkcs11".
+           </para>
+         </listitem>
+       </varlistentry>
+diff --git a/bin/named/server.c b/bin/named/server.c
+index 56df6bf..227c646 100644
+--- a/bin/named/server.c
++++ b/bin/named/server.c
+@@ -6215,6 +6215,11 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
+ 	server->in_roothints = NULL;
+ 	server->blackholeacl = NULL;
+ 
++	/* Must be first. */
++	CHECKFATAL(dst_lib_init2(ns_g_mctx, ns_g_entropy,
++				 ns_g_engine, ISC_ENTROPY_GOODONLY),
++		   "initializing DST");
++
+ 	CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
+ 				     &server->in_roothints),
+ 		   "setting up root hints");
+@@ -6231,10 +6236,6 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
+ 		   ISC_R_NOMEMORY : ISC_R_SUCCESS,
+ 		   "allocating reload event");
+ 
+-	CHECKFATAL(dst_lib_init2(ns_g_mctx, ns_g_entropy,
+-				 ns_g_engine, ISC_ENTROPY_GOODONLY),
+-		   "initializing DST");
+-
+ 	server->tkeyctx = NULL;
+ 	CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy,
+ 				      &server->tkeyctx),
+diff --git a/bin/nsupdate/Makefile.in b/bin/nsupdate/Makefile.in
+index 09e6c14..e258ffc 100644
+--- a/bin/nsupdate/Makefile.in
++++ b/bin/nsupdate/Makefile.in
+@@ -46,9 +46,11 @@ ISCCFGDEPLIBS =	../../lib/isccfg/libisccfg.@A@
+ 
+ DEPLIBS =	${DNSDEPLIBS} ${BIND9DEPLIBS} ${ISCDEPLIBS} ${ISCCFGDEPLIBS}
+ 
+-LIBS =		${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} ${ISCLIBS} @LIBS@
++LIBS =		${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \
++		${ISCLIBS} @LIBS@
+ 
+-NOSYMLIBS =	${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} ${ISCNOSYMLIBS} @LIBS@
++NOSYMLIBS =	${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \
++		${ISCNOSYMLIBS} @LIBS@
+ 
+ SUBDIRS =
+ 
+diff --git a/bin/pkcs11/Makefile.in b/bin/pkcs11/Makefile.in
+index 407d977..15d3fb5 100644
+--- a/bin/pkcs11/Makefile.in
++++ b/bin/pkcs11/Makefile.in
+@@ -20,38 +20,51 @@ top_srcdir =	@top_srcdir@
+ 
+ @BIND9_MAKE_INCLUDES@
+ 
+-PROVIDER =	@PKCS11_PROVIDER@
++CINCLUDES =	${ISC_INCLUDES}
+ 
+-CINCLUDES =	-I${srcdir}/include -I${srcdir}/unix
++CDEFINES =
+ 
+-CDEFINES =	-DPK11_LIB_LOCATION=\"${PROVIDER}\"
++ISCLIBS =	../../lib/isc/libisc.@A@
++
++ISCDEPLIBS =	../../lib/isc/libisc.@A@
++
++DEPLIBS =	${ISCDEPLIBS}
+ 
+ # if FORCE_STATIC_PROVIDER: LIBS = ${PROVIDER}
+-LIBS =		-ldl
++LIBS =		${ISCLIBS} @LIBS@
+ 
+-SUBDIRS =
++SUBDIRS =	benchmarks
+ 
+-TARGETS =	pkcs11-keygen@EXEEXT@ pkcs11-list@EXEEXT@ \
+-		pkcs11-destroy@EXEEXT@
+-SRCS =		pkcs11-keygen.c pkcs11-list.c pkcs11-destroy.c
++TARGETS =	pkcs11-list@EXEEXT@ pkcs11-destroy@EXEEXT@ \
++		pkcs11-keygen@EXEEXT@ pkcs11-tokens@EXEEXT@
++SRCS =		pkcs11-list.c pkcs11-destroy.c \
++		pkcs11-keygen.c pkcs11-tokens.c
++OBJS =		pkcs11-list.@O@ pkcs11-destroy.@O@ \
++		pkcs11-keygen.@O@ pkcs11-tokens.@O@
+ 
+-MANPAGES =	pkcs11-keygen.8 pkcs11-list.8 pkcs11-destroy.8
+-HTMLPAGES =	pkcs11-keygen.html pkcs11-list.html pkcs11-destroy.html
++MANPAGES =	pkcs11-list.8 pkcs11-destroy.8 \
++		pkcs11-keygen.8 pkcs11-tokens.8
++HTMLPAGES =	pkcs11-list.html pkcs11-destroy.html \
++		pkcs11-keygen.html pkcs11-tokens.html
+ MANOBJS =	${MANPAGES} ${HTMLPAGES}
+ 
+ @BIND9_MAKE_RULES@
+ 
+-pkcs11-keygen@EXEEXT@: @srcdir@/pkcs11-keygen.c
+-	${CC} ${ALL_CFLAGS} ${LDFLAGS} \
+-	-o $@ @srcdir@/pkcs11-keygen.c ${LIBS}
+-
+-pkcs11-list@EXEEXT@: @srcdir@/pkcs11-list.c
+-	${CC} ${ALL_CFLAGS} ${LDFLAGS} \
+-	-o $@ @srcdir@/pkcs11-list.c ${LIBS}
+-
+-pkcs11-destroy@EXEEXT@: @srcdir@/pkcs11-destroy.c
+-	${CC} ${ALL_CFLAGS} ${LDFLAGS} \
+-	-o $@ @srcdir@/pkcs11-destroy.c ${LIBS}
++pkcs11-list@EXEEXT@: @srcdir@/pkcs11-list.@O@ ${DEPLIBS}
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \
++	-o $@ @srcdir@/pkcs11-list.@O@ ${LIBS}
++
++pkcs11-destroy@EXEEXT@: @srcdir@/pkcs11-destroy.@O@ ${DEPLIBS}
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \
++	-o $@ @srcdir@/pkcs11-destroy.@O@ ${LIBS}
++ 
++pkcs11-keygen@EXEEXT@: @srcdir@/pkcs11-keygen.@O@ ${DEPLIBS}
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \
++	-o $@ @srcdir@/pkcs11-keygen.@O@ ${LIBS}
++ 
++pkcs11-tokens@EXEEXT@: @srcdir@/pkcs11-tokens.@O@ ${DEPLIBS}
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \
++	-o $@ @srcdir@/pkcs11-tokens.@O@ ${LIBS}
+ 
+ doc man:: ${MANOBJS}
+ 
+@@ -63,12 +76,14 @@ installdirs:
+ 	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man8
+ 
+ install:: ${TARGETS} installdirs
+-	${INSTALL_PROGRAM} pkcs11-keygen@EXEEXT@ ${DESTDIR}${sbindir}
+-	${INSTALL_PROGRAM} pkcs11-list@EXEEXT@ ${DESTDIR}${sbindir}
+-	${INSTALL_PROGRAM} pkcs11-destroy@EXEEXT@ ${DESTDIR}${sbindir}
+-	${INSTALL_DATA} ${srcdir}/pkcs11-keygen.8 ${DESTDIR}${mandir}/man8
++	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} pkcs11-list@EXEEXT@ ${DESTDIR}${sbindir}
++	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} pkcs11-destroy@EXEEXT@ ${DESTDIR}${sbindir}
++	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} pkcs11-keygen@EXEEXT@ ${DESTDIR}${sbindir}
++	${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} pkcs11-tokens@EXEEXT@ ${DESTDIR}${sbindir}
+ 	${INSTALL_DATA} ${srcdir}/pkcs11-list.8 ${DESTDIR}${mandir}/man8
+ 	${INSTALL_DATA} ${srcdir}/pkcs11-destroy.8 ${DESTDIR}${mandir}/man8
++	${INSTALL_DATA} ${srcdir}/pkcs11-keygen.8 ${DESTDIR}${mandir}/man8
++	${INSTALL_DATA} ${srcdir}/pkcs11-tokens.8 ${DESTDIR}${mandir}/man8
+ 
+ clean distclean::
+-	rm -f ${TARGETS}
++	rm -f ${OBJS} ${TARGETS}
+diff --git a/bin/pkcs11/pkcs11-destroy.8 b/bin/pkcs11/pkcs11-destroy.8
+index aff35b3..25323ca 100644
+--- a/bin/pkcs11/pkcs11-destroy.8
++++ b/bin/pkcs11/pkcs11-destroy.8
+@@ -32,7 +32,7 @@
+ pkcs11\-destroy \- destroy PKCS#11 objects
+ .SH "SYNOPSIS"
+ .HP 15
+-\fBpkcs11\-destroy\fR [\fB\-m\ \fR\fB\fImodule\fR\fR] [\fB\-s\ \fR\fB\fIslot\fR\fR] {\-i\ \fIID\fR | \-l\ \fIlabel\fR} [\fB\-p\ \fR\fB\fIPIN\fR\fR]
++\fBpkcs11\-destroy\fR [\fB\-m\ \fR\fB\fImodule\fR\fR] [\fB\-s\ \fR\fB\fIslot\fR\fR] {\-i\ \fIID\fR | \-l\ \fIlabel\fR} [\fB\-p\ \fR\fB\fIPIN\fR\fR] [\fB\-w\ \fR\fB\fIseconds\fR\fR]
+ .SH "DESCRIPTION"
+ .PP
+ \fBpkcs11\-destroy\fR
+@@ -41,7 +41,7 @@ destroys keys stored in a PKCS#11 device, identified by their
+ or
+ \fBlabel\fR.
+ .PP
+-Matching keys are displayed before being destroyed. There is a five second delay to allow the user to interrupt the process before the destruction takes place.
++Matching keys are displayed before being destroyed. By default, there is a five second delay to allow the user to interrupt the process before the destruction takes place.
+ .SH "ARGUMENTS"
+ .PP
+ \-m \fImodule\fR
+@@ -70,6 +70,12 @@ Specify the PIN for the device. If no PIN is provided on the command line,
+ \fBpkcs11\-destroy\fR
+ will prompt for it.
+ .RE
++.PP
++\-w \fIseconds\fR
++.RS 4
++Specify how long to pause before carrying out key destruction. The default is five seconds. If set to
++0, destruction will be immediate.
++.RE
+ .SH "SEE ALSO"
+ .PP
+ \fBpkcs11\-list\fR(3),
+diff --git a/bin/pkcs11/pkcs11-destroy.c b/bin/pkcs11/pkcs11-destroy.c
+index 0f46a89..2905395 100644
+--- a/bin/pkcs11/pkcs11-destroy.c
++++ b/bin/pkcs11/pkcs11-destroy.c
+@@ -40,7 +40,10 @@
+ 
+ /* $Id: pkcs11-destroy.c,v 1.8 2010/01/13 21:19:52 fdupont Exp $ */
+ 
+-/* pkcs11-destroy [-m module] [-s $slot] [-i $id | -l $label] [-p $pin] */
++/*
++ * pkcs11-destroy [-m module] [-s $slot] [-i $id | -l $label]
++ *                 [-p $pin] [ -w $wait ]
++ */
+ 
+ /*! \file */
+ 
+@@ -52,74 +55,70 @@
+ #include <errno.h>
+ #include <string.h>
+ #include <sys/types.h>
+-#include "cryptoki.h"
+ 
+-#ifdef WIN32
+-#define sleep(x)	Sleep(x)
+-#include "win32.c"
+-#else
+-#ifndef FORCE_STATIC_PROVIDER
+-#include "unix.c"
+-#endif
+-#endif
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/result.h>
+ 
+ #if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
+ #define getpassphrase(x)	getpass(x)
+ #endif
+ 
+ int
+-main(int argc, char *argv[])
+-{
++main(int argc, char *argv[]) {
++	isc_result_t result;
+ 	CK_RV rv;
+ 	CK_SLOT_ID slot = 0;
+ 	CK_SESSION_HANDLE hSession;
+-	CK_UTF8CHAR *pin = NULL;
+ 	CK_BYTE attr_id[2];
+ 	CK_OBJECT_HANDLE akey[50];
++	pk11_context_t pctx;
++	char *lib_name = NULL;
+ 	char *label = NULL;
++	char *pin = NULL;
+ 	int error = 0;
+-	unsigned int id = 0, i = 0;
++	unsigned int id = 0, i = 0, wait = 5;
+ 	int c, errflg = 0;
+ 	CK_ULONG ulObjectCount;
+ 	CK_ATTRIBUTE search_template[] = {
+ 		{CKA_ID, &attr_id, sizeof(attr_id)}
+ 	};
+-	char *pk11_provider;
+ 	unsigned int j, len;
+-	extern char *optarg;
+-	extern int optopt;
+-
+-	pk11_provider = getenv("PKCS11_PROVIDER");
+-	if (pk11_provider != NULL)
+-		pk11_libname = pk11_provider;
+ 
+-	while ((c = getopt(argc, argv, ":m:s:i:l:p:")) != -1) {
++	while ((c = isc_commandline_parse(argc, argv, ":m:s:i:l:p:w:")) != -1) {
+ 		switch (c) {
+ 		case 'm':
+-			pk11_libname = optarg;
++			lib_name = isc_commandline_argument;
+ 			break;
+ 		case 's':
+-			slot = atoi(optarg);
++			slot = atoi(isc_commandline_argument);
+ 			break;
+ 		case 'i':
+-			id = atoi(optarg);
++			id = atoi(isc_commandline_argument);
+ 			id &= 0xffff;
+ 			break;
+ 		case 'l':
+-			label = optarg;
++			label = isc_commandline_argument;
+ 			break;
+ 		case 'p':
+-			pin = (CK_UTF8CHAR *)optarg;
++			pin = isc_commandline_argument;
++			break;
++		case 'w':
++			wait = atoi(isc_commandline_argument);
+ 			break;
+ 		case ':':
+ 			fprintf(stderr,
+ 				"Option -%c requires an operand\n",
+-				optopt);
++				isc_commandline_option);
+ 			errflg++;
+ 			break;
+ 		case '?':
+ 		default:
+-			fprintf(stderr, "Unrecognised option: -%c\n", optopt);
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
+ 			errflg++;
+ 		}
+ 	}
+@@ -127,56 +126,49 @@ main(int argc, char *argv[])
+ 	if (errflg || (id && (label != NULL))) {
+ 		fprintf(stderr, "Usage:\n");
+ 		fprintf(stderr, "\tpkcs11-destroy [-m module] [-s slot] "
+-				"[-i id | -l label] [-p pin]\n");
++				"[-i id | -l label] [-p pin] [-w waittime]\n");
+ 		exit(1);
+ 	}
+ 
+ 	if (id) {
+-		printf("id %i\n", id);
+ 		attr_id[0] = (id >> 8) & 0xff;
+ 		attr_id[1] = id & 0xff;
+ 	} else if (label) {
+-		printf("label %s\n", label);
+ 		search_template[0].type = CKA_LABEL;
+ 		search_template[0].pValue = label;
+ 		search_template[0].ulValueLen = strlen(label);
+ 	}
+ 
+-	/* Initialize the CRYPTOKI library */
+-	rv = C_Initialize(NULL_PTR);
+-	if (rv != CKR_OK) {
+-		if (rv == 0xfe)
+-			fprintf(stderr,
+-				"Can't load or link module \"%s\"\n",
+-				pk11_libname);
+-		else
+-			fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv);
+-		exit(1);
+-	}
++	pk11_result_register();
+ 
+-	/* Open a session on the slot found */
+-	rv = C_OpenSession(slot, CKF_RW_SESSION+CKF_SERIAL_SESSION,
+-			   NULL_PTR, NULL_PTR, &hSession);
+-	if (rv != CKR_OK) {
+-		fprintf(stderr, "C_OpenSession: Error = 0x%.8lX\n", rv);
+-		error = 1;
+-		goto exit_program;
+-	}
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
+ 
+ 	if (pin == NULL)
+-		pin = (CK_UTF8CHAR *)getpassphrase("Enter Pin: ");
++		pin = getpassphrase("Enter Pin: ");
+ 
+ 	/* Login to the Token (Keystore) */
+-	rv = C_Login(hSession, CKU_USER, pin, strlen((char *)pin));
+-	memset(pin, 0, strlen((char *)pin));
+-	if (rv != CKR_OK) {
+-		fprintf(stderr, "C_Login: Error = 0x%.8lX\n", rv);
+-		error = 1;
+-		goto exit_session;
++	result = pk11_get_session(&pctx, OP_ANY, ISC_FALSE, ISC_TRUE,
++				  ISC_TRUE, (const char *) pin, slot);
++	if (result == PK11_R_NORANDOMSERVICE ||
++	    result == PK11_R_NODIGESTSERVICE ||
++	    result == PK11_R_NOAESSERVICE) {
++		fprintf(stderr, "Warning: %s\n", isc_result_totext(result));
++		fprintf(stderr, "This HSM will not work with BIND 9 "
++				"using native PKCS#11.\n");
++	} else if (result != ISC_R_SUCCESS) {
++		fprintf(stderr, "Unrecoverable error initializing "
++				"PKCS#11: %s\n", isc_result_totext(result));
++		exit(1);
+ 	}
+ 
+-	rv = C_FindObjectsInit(hSession, search_template,
+-		   ((id != 0) || (label != NULL)) ? 1 : 0); 
++	memset(pin, 0, strlen(pin));
++
++	hSession = pctx.session;
++
++	rv = pkcs_C_FindObjectsInit(hSession, search_template,
++				    ((id != 0) || (label != NULL)) ? 1 : 0);
+ 
+ 	if (rv != CKR_OK) {
+ 		fprintf(stderr, "C_FindObjectsInit: Error = 0x%.8lX\n", rv);
+@@ -184,13 +176,19 @@ main(int argc, char *argv[])
+ 		goto exit_session;
+ 	}
+ 	
+-	rv = C_FindObjects(hSession, akey, 50, &ulObjectCount);
++	rv = pkcs_C_FindObjects(hSession, akey, 50, &ulObjectCount);
+ 	if (rv != CKR_OK) {
+ 		fprintf(stderr, "C_FindObjects: Error = 0x%.8lX\n", rv);
+ 		error = 1;
+ 		goto exit_search;
+ 	}
+ 
++	if (ulObjectCount == 0) {
++		printf("No matching key objects found.\n");
++		goto exit_search;
++	} else
++		printf("Key object%s found:\n", ulObjectCount > 1 ? "s" : "");
++
+ 	for (i = 0; i < ulObjectCount; i++) {
+ 		CK_OBJECT_CLASS oclass = 0;
+ 		CK_BYTE labelbuf[64 + 1];
+@@ -204,7 +202,8 @@ main(int argc, char *argv[])
+ 		memset(labelbuf, 0, sizeof(labelbuf));
+ 		memset(idbuf, 0, sizeof(idbuf));
+ 
+-		rv = C_GetAttributeValue(hSession, akey[i], attr_template, 3);
++		rv = pkcs_C_GetAttributeValue(hSession, akey[i],
++					      attr_template, 3);
+ 		if (rv != CKR_OK) {
+ 			fprintf(stderr,
+ 				"C_GetAttributeValue[%u]: rv = 0x%.8lX\n",
+@@ -213,7 +212,7 @@ main(int argc, char *argv[])
+ 			goto exit_search;
+ 		}
+ 		len = attr_template[2].ulValueLen;
+-		printf("object[%u]: class %lu label '%s' id[%lu] ",
++		printf("  object[%u]: class %lu, label '%s', id[%lu] ",
+ 		       i, oclass, labelbuf, attr_template[2].ulValueLen);
+ 		if (len > 4)
+ 			len = 4;
+@@ -227,32 +226,40 @@ main(int argc, char *argv[])
+ 			printf("\n");
+ 	}
+ 
+-	/* give a chance to kill this */
+-	printf("sleeping 5 seconds...\n");
+-	sleep(5);
++	if (wait != 0) {
++		printf("WARNING: This action is irreversible! "
++		       "Destroying key objects in %d seconds\n  ", wait);
++		for (i = 0; i < wait; i++) {
++			printf(".");
++			fflush(stdout);
++			sleep(1);
++		}
++		printf("\n");
++	}
+ 
+ 	for (i = 0; i < ulObjectCount; i++) {
+-		rv = C_DestroyObject(hSession, akey[i]);
++		rv = pkcs_C_DestroyObject(hSession, akey[i]);
+ 		if (rv != CKR_OK) {
+ 			fprintf(stderr,
+-				"C_DestroyObject[%u]: rv = 0x%.8lX\n",
++				"C_DestroyObject[%u] failed: rv = 0x%.8lX\n",
+ 				i, rv);
+ 			error = 1;
+ 		}
+ 	}
+ 
++	if (error == 0)
++		printf("Destruction complete.\n");
++
+  exit_search:
+-	rv = C_FindObjectsFinal(hSession);
++	rv = pkcs_C_FindObjectsFinal(hSession);
+ 	if (rv != CKR_OK) {
+ 		fprintf(stderr, "C_FindObjectsFinal: Error = 0x%.8lX\n", rv);
+ 		error = 1;
+ 	}
+ 
+  exit_session:
+-	(void)C_CloseSession(hSession);
+-
+- exit_program:
+-	(void)C_Finalize(NULL_PTR);
++	pk11_return_session(&pctx);
++	(void) pk11_finalize();
+ 
+ 	exit(error);
+ }
+diff --git a/bin/pkcs11/pkcs11-destroy.docbook b/bin/pkcs11/pkcs11-destroy.docbook
+index b4c2048..45c0208 100644
+--- a/bin/pkcs11/pkcs11-destroy.docbook
++++ b/bin/pkcs11/pkcs11-destroy.docbook
+@@ -37,6 +37,7 @@
+   <docinfo>
+     <copyright>
+       <year>2009</year>
++      <year>2014</year>
+       <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+     </copyright>
+   </docinfo>
+@@ -51,6 +52,7 @@
+         <arg choice="plain">-l <replaceable class="parameter">label</replaceable></arg>
+       </group>
+       <arg><option>-p <replaceable class="parameter">PIN</replaceable></option></arg>
++      <arg><option>-w <replaceable class="parameter">seconds</replaceable></option></arg>
+     </cmdsynopsis>
+   </refsynopsisdiv>
+ 
+@@ -62,9 +64,9 @@
+       <option>label</option>.
+     </para>
+     <para>
+-      Matching keys are displayed before being destroyed.  There is a
+-      five second delay to allow the user to interrupt the process
+-      before the destruction takes place.
++      Matching keys are displayed before being destroyed.  By default,
++      there is a five second delay to allow the user to interrupt the
++      process before the destruction takes place.
+     </para>
+   </refsect1>
+ 
+@@ -119,6 +121,17 @@
+           </para>
+         </listitem>
+       </varlistentry>
++
++      <varlistentry>
++        <term>-w <replaceable class="parameter">seconds</replaceable></term>
++        <listitem>
++          <para>
++            Specify how long to pause before carrying out key destruction.
++            The default is five seconds.  If set to <literal>0</literal>,
++            destruction will be immediate.
++          </para>
++        </listitem>
++      </varlistentry>
+     </variablelist>
+   </refsect1>
+ 
+diff --git a/bin/pkcs11/pkcs11-destroy.html b/bin/pkcs11/pkcs11-destroy.html
+index afc6e36..899b3e9 100644
+--- a/bin/pkcs11/pkcs11-destroy.html
++++ b/bin/pkcs11/pkcs11-destroy.html
+@@ -29,23 +29,23 @@
+ </div>
+ <div class="refsynopsisdiv">
+ <h2>Synopsis</h2>
+-<div class="cmdsynopsis"><p><code class="command">pkcs11-destroy</code>  [<code class="option">-m <em class="replaceable"><code>module</code></em></code>] [<code class="option">-s <em class="replaceable"><code>slot</code></em></code>] { -i <em class="replaceable"><code>ID</code></em>  |   -l <em class="replaceable"><code>label</code></em> } [<code class="option">-p <em class="replaceable"><code>PIN</code></em></code>]</p></div>
++<div class="cmdsynopsis"><p><code class="command">pkcs11-destroy</code>  [<code class="option">-m <em class="replaceable"><code>module</code></em></code>] [<code class="option">-s <em class="replaceable"><code>slot</code></em></code>] { -i <em class="replaceable"><code>ID</code></em>  |   -l <em class="replaceable"><code>label</code></em> } [<code class="option">-p <em class="replaceable"><code>PIN</code></em></code>] [<code class="option">-w <em class="replaceable"><code>seconds</code></em></code>]</p></div>
+ </div>
+ <div class="refsect1" lang="en">
+-<a name="id2543384"></a><h2>DESCRIPTION</h2>
++<a name="id2543393"></a><h2>DESCRIPTION</h2>
+ <p>
+       <span><strong class="command">pkcs11-destroy</strong></span> destroys keys stored in a
+       PKCS#11 device, identified by their <code class="option">ID</code> or
+       <code class="option">label</code>.
+     </p>
+ <p>
+-      Matching keys are displayed before being destroyed.  There is a
+-      five second delay to allow the user to interrupt the process
+-      before the destruction takes place.
++      Matching keys are displayed before being destroyed.  By default,
++      there is a five second delay to allow the user to interrupt the
++      process before the destruction takes place.
+     </p>
+ </div>
+ <div class="refsect1" lang="en">
+-<a name="id2543406"></a><h2>ARGUMENTS</h2>
++<a name="id2543415"></a><h2>ARGUMENTS</h2>
+ <div class="variablelist"><dl>
+ <dt><span class="term">-m <em class="replaceable"><code>module</code></em></span></dt>
+ <dd><p>
+@@ -71,17 +71,23 @@
+             Specify the PIN for the device.  If no PIN is provided on the
+             command line, <span><strong class="command">pkcs11-destroy</strong></span> will prompt for it.
+           </p></dd>
++<dt><span class="term">-w <em class="replaceable"><code>seconds</code></em></span></dt>
++<dd><p>
++            Specify how long to pause before carrying out key destruction.
++            The default is five seconds.  If set to <code class="literal">0</code>,
++            destruction will be immediate.
++          </p></dd>
+ </dl></div>
+ </div>
+ <div class="refsect1" lang="en">
+-<a name="id2543507"></a><h2>SEE ALSO</h2>
++<a name="id2543537"></a><h2>SEE ALSO</h2>
+ <p>
+       <span class="citerefentry"><span class="refentrytitle">pkcs11-list</span>(3)</span>,
+       <span class="citerefentry"><span class="refentrytitle">pkcs11-keygen</span>(3)</span>
+     </p>
+ </div>
+ <div class="refsect1" lang="en">
+-<a name="id2543533"></a><h2>AUTHOR</h2>
++<a name="id2543563"></a><h2>AUTHOR</h2>
+ <p><span class="corpauthor">Internet Systems Consortium</span>
+     </p>
+ </div>
+diff --git a/bin/pkcs11/pkcs11-keygen.8 b/bin/pkcs11/pkcs11-keygen.8
+index 568e862..53de464 100644
+--- a/bin/pkcs11/pkcs11-keygen.8
++++ b/bin/pkcs11/pkcs11-keygen.8
+@@ -23,80 +23,91 @@
+ .\"    Manual: BIND9
+ .\"    Source: BIND9
+ .\"
+-.TH "PKCS11\-KEYGEN" "8" "Sep 18, 2009" "BIND9" "BIND9"
++.TH "PKCS11\-ECGEN" "8" "Feb 30, 2012" "BIND9" "BIND9"
+ .\" disable hyphenation
+ .nh
+ .\" disable justification (adjust text to left margin only)
+ .ad l
+ .SH "NAME"
+-pkcs11\-keygen \- generate RSA keys on a PKCS#11 device
++pkcs11\-keygen \- generate keys on a PKCS#11 device
+ .SH "SYNOPSIS"
+ .HP 14
+-\fBpkcs11\-keygen\fR [\fB\-P\fR] [\fB\-m\ \fR\fB\fImodule\fR\fR] [\fB\-s\ \fR\fB\fIslot\fR\fR] [\fB\-e\fR] {\-b\ \fIkeysize\fR} {\-l\ \fIlabel\fR} [\fB\-i\ \fR\fB\fIid\fR\fR] [\fB\-p\ \fR\fB\fIPIN\fR\fR]
++\fBpkcs11\-keygen\fR {\-a\ \fIalgorithm\fR} [\fB\-b\ \fR\fB\fIkeysize\fR\fR] [\fB\-e\fR] [\fB\-i\ \fR\fB\fIid\fR\fR] [\fB\-m\ \fR\fB\fImodule\fR\fR] [\fB\-P\fR] [\fB\-p\ \fR\fB\fIPIN\fR\fR] [\fB\-q\fR] [\fB\-S\fR] [\fB\-s\ \fR\fB\fIslot\fR\fR] {label}
+ .SH "DESCRIPTION"
+ .PP
+ \fBpkcs11\-keygen\fR
+-causes a PKCS#11 device to generate a new RSA key pair with the specified
++causes a PKCS#11 device to generate a new key pair with the given
+ \fBlabel\fR
+-and with
++(which must be unique) and with
+ \fBkeysize\fR
+-bits of modulus.
++bits of prime.
+ .SH "ARGUMENTS"
+ .PP
+-\-P
+-.RS 4
+-Set the new private key to be non\-sensitive and extractable. The allows the private key data to be read from the PKCS#11 device. The default is for private keys to be sensitive and non\-extractable.
+-.RE
+-.PP
+-\-m \fImodule\fR
++\-a \fIalgorithm\fR
+ .RS 4
+-Specify the PKCS#11 provider module. This must be the full path to a shared library object implementing the PKCS#11 API for the device.
++Specify the key algorithm class: Supported classes are RSA, DSA, DH, and ECC. In addition to these strings, the
++\fBalgorithm\fR
++can be specified as a DNSSEC signing algorithm that will be used with this key; for example, NSEC3RSASHA1 maps to RSA, and ECDSAP256SHA256 maps to ECC. The default class is "RSA".
+ .RE
+ .PP
+-\-s \fIslot\fR
++\-b \fIkeysize\fR
+ .RS 4
+-Open the session with the given PKCS#11 slot. The default is slot 0.
++Create the key pair with
++\fBkeysize\fR
++bits of prime. For ECC keys, the only valid values are 256 and 384, and the default is 256.
+ .RE
+ .PP
+ \-e
+ .RS 4
+-Use a large exponent.
++For RSA keys only, use a large exponent.
+ .RE
+ .PP
+-\-b \fIkeysize\fR
++\-i \fIid\fR
+ .RS 4
+-Create the key pair with
+-\fBkeysize\fR
+-bits of modulus.
++Create key objects with id. The id is either an unsigned short 2 byte or an unsigned long 4 byte number.
+ .RE
+ .PP
+-\-l \fIlabel\fR
++\-m \fImodule\fR
+ .RS 4
+-Create key objects with the given label. This name must be unique.
++Specify the PKCS#11 provider module. This must be the full path to a shared library object implementing the PKCS#11 API for the device.
+ .RE
+ .PP
+-\-i \fIid\fR
++\-P
+ .RS 4
+-Create key objects with id. The id is either an unsigned short 2 byte or an unsigned long 4 byte number.
++Set the new private key to be non\-sensitive and extractable. The allows the private key data to be read from the PKCS#11 device. The default is for private keys to be sensitive and non\-extractable.
+ .RE
+ .PP
+ \-p \fIPIN\fR
+ .RS 4
+ Specify the PIN for the device. If no PIN is provided on the command line,
+-\fBpkcs11\-keygen\fR
++\fBpkcs11\-ecgen\fR
+ will prompt for it.
+ .RE
++.PP
++\-e
++.RS 4
++Quiet mode: suppress unnecessary output.
++.RE
++.PP
++\-S
++.RS 4
++For Diffie\-Hellman (DH) keys only, use a special prime of 768, 1024 or 1536 bit size and base (aka generator) 2. If not specified, bit size will default to 1024.
++.RE
++.PP
++\-s \fIslot\fR
++.RS 4
++Open the session with the given PKCS#11 slot. The default is slot 0.
++.RE
+ .SH "SEE ALSO"
+ .PP
++\fBpkcs11\-rsagen\fR(3),
++\fBpkcs11\-dsagen\fR(3),
+ \fBpkcs11\-list\fR(3),
+ \fBpkcs11\-destroy\fR(3),
+ \fBdnssec\-keyfromlabel\fR(3),
+-.SH "CAVEAT"
+-.PP
+-Some PKCS#11 providers crash with big public exponent.
+ .SH "AUTHOR"
+ .PP
+ Internet Systems Consortium
+ .SH "COPYRIGHT"
+-Copyright \(co 2009 Internet Systems Consortium, Inc. ("ISC")
++Copyright \(co 2012 Internet Systems Consortium, Inc. ("ISC")
+ .br
+diff --git a/bin/pkcs11/pkcs11-keygen.c b/bin/pkcs11/pkcs11-keygen.c
+index 1ffb343..cc91776 100644
+--- a/bin/pkcs11/pkcs11-keygen.c
++++ b/bin/pkcs11/pkcs11-keygen.c
+@@ -40,18 +40,19 @@
+ 
+ /* $Id: pkcs11-keygen.c,v 1.9 2009/10/26 23:36:53 each Exp $ */
+ 
+-/* pkcs11-keygen - pkcs11 rsa key generator
+-*
+-* create RSASHA1 key in the keystore of an SCA6000
+-* The calculation of key tag is left to the script
+-* that converts the key into a DNSKEY RR and inserts 
+-* it into a zone file.
+-*
+-* usage:
+-* pkcs11-keygen [-P] [-m module] [-s slot] [-e] -b keysize
+-*               -l label [-i id] [-p pin] 
+-*
+-*/
++/* pkcs11-keygen - PKCS#11 key generator
++ *
++ * Create a key in the keystore of an HSM
++ *
++ * The calculation of key tag is left to the script
++ * that converts the key into a DNSKEY RR and inserts 
++ * it into a zone file.
++ *
++ * usage:
++ * pkcs11-keygen [-P] [-m module] [-s slot] [-e] [-b keysize]
++ *               [-i id] [-p pin] -l label
++ *
++ */
+ 
+ /*! \file */
+ 
+@@ -63,15 +64,16 @@
+ #include <errno.h>
+ #include <string.h>
+ #include <sys/types.h>
+-#include "cryptoki.h"
+ 
+-#ifdef WIN32
+-#include "win32.c"
+-#else
+-#ifndef FORCE_STATIC_PROVIDER
+-#include "unix.c"
+-#endif
+-#endif
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/result.h>
++#define WANT_DH_PRIMES
++#define WANT_ECC_CURVES
++#include <pk11/constants.h>
+ 
+ #if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
+ #define getpassphrase(x)	getpass(x)
+@@ -81,188 +83,478 @@
+ static CK_BBOOL truevalue = TRUE;
+ static CK_BBOOL falsevalue = FALSE;
+ 
++/* Key class: RSA, ECC, DSA, DH, or unknown */
++typedef enum {
++	key_unknown,
++	key_rsa,
++	key_dsa,
++	key_dh,
++	key_ecc
++} key_class_t;
++
++/*
++ * Private key template: usable for most key classes without
++ * modificaton; override CKA_SIGN with CKA_DERIVE for DH
++ */
++#define PRIVATE_LABEL 0
++#define PRIVATE_SIGN 1
++#define PRIVATE_DERIVE 1
++#define PRIVATE_TOKEN 2
++#define PRIVATE_PRIVATE 3
++#define PRIVATE_SENSITIVE 4
++#define PRIVATE_EXTRACTABLE 5
++#define PRIVATE_ID 6
++#define PRIVATE_ATTRS 7
++static CK_ATTRIBUTE private_template[] = {
++	{CKA_LABEL, NULL_PTR, 0},
++	{CKA_SIGN, &truevalue, sizeof(truevalue)},
++	{CKA_TOKEN, &truevalue, sizeof(truevalue)},
++	{CKA_PRIVATE, &truevalue, sizeof(truevalue)},
++	{CKA_SENSITIVE, &truevalue, sizeof(truevalue)},
++	{CKA_EXTRACTABLE, &falsevalue, sizeof(falsevalue)},
++	{CKA_ID, NULL_PTR, 0}
++};
++
++/*
++ * Public key template for RSA keys
++ */
++#define RSA_LABEL 0
++#define RSA_VERIFY 1
++#define RSA_TOKEN 2
++#define RSA_PRIVATE 3
++#define RSA_MODULUS_BITS 4
++#define RSA_PUBLIC_EXPONENT 5
++#define RSA_ID 6
++#define RSA_ATTRS 7
++static CK_ATTRIBUTE rsa_template[] = {
++	{CKA_LABEL, NULL_PTR, 0},
++	{CKA_VERIFY, &truevalue, sizeof(truevalue)},
++	{CKA_TOKEN, &truevalue, sizeof(truevalue)},
++	{CKA_PRIVATE, &falsevalue, sizeof(falsevalue)},
++	{CKA_MODULUS_BITS, NULL_PTR, 0},
++	{CKA_PUBLIC_EXPONENT, NULL_PTR, 0},
++	{CKA_ID, NULL_PTR, 0}
++};
++
++/*
++ * Public key template for ECC keys
++ */
++#define ECC_LABEL 0
++#define ECC_VERIFY 1
++#define ECC_TOKEN 2
++#define ECC_PRIVATE 3
++#define ECC_PARAMS 4
++#define ECC_ID 5
++#define ECC_ATTRS 6
++static CK_ATTRIBUTE ecc_template[] = {
++	{CKA_LABEL, NULL_PTR, 0},
++	{CKA_VERIFY, &truevalue, sizeof(truevalue)},
++	{CKA_TOKEN, &truevalue, sizeof(truevalue)},
++	{CKA_PRIVATE, &falsevalue, sizeof(falsevalue)},
++	{CKA_EC_PARAMS, NULL_PTR, 0},
++	{CKA_ID, NULL_PTR, 0}
++};
++
++/*
++ * Public key template for DSA keys
++ */
++#define DSA_LABEL 0
++#define DSA_VERIFY 1
++#define DSA_TOKEN 2
++#define DSA_PRIVATE 3
++#define DSA_PRIME 4
++#define DSA_SUBPRIME 5
++#define DSA_BASE 6
++#define DSA_ID 7
++#define DSA_ATTRS 8
++static CK_ATTRIBUTE dsa_template[] = {
++	{CKA_LABEL, NULL_PTR, 0},
++	{CKA_VERIFY, &truevalue, sizeof(truevalue)},
++	{CKA_TOKEN, &truevalue, sizeof(truevalue)},
++	{CKA_PRIVATE, &falsevalue, sizeof(falsevalue)},
++	{CKA_PRIME, NULL_PTR, 0},
++	{CKA_SUBPRIME, NULL_PTR, 0},
++	{CKA_BASE, NULL_PTR, 0},
++	{CKA_ID, NULL_PTR, 0}
++};
++#define DSA_PARAM_PRIME 0
++#define DSA_PARAM_SUBPRIME 1
++#define DSA_PARAM_BASE 2
++#define DSA_PARAM_ATTRS 3
++static CK_ATTRIBUTE dsa_param_template[] = {
++	{CKA_PRIME, NULL_PTR, 0},
++	{CKA_SUBPRIME, NULL_PTR, 0},
++	{CKA_BASE, NULL_PTR, 0},
++};
++#define DSA_DOMAIN_PRIMEBITS 0
++#define DSA_DOMAIN_PRIVATE 1
++#define DSA_DOMAIN_ATTRS 2
++static CK_ATTRIBUTE dsa_domain_template[] = {
++	{CKA_PRIME_BITS, NULL_PTR, 0},
++	{CKA_PRIVATE, &falsevalue, sizeof(falsevalue)},
++};
++
++/*
++ * Public key template for DH keys
++ */
++#define DH_LABEL 0
++#define DH_VERIFY 1
++#define DH_TOKEN 2
++#define DH_PRIVATE 3
++#define DH_PRIME 4
++#define DH_BASE 5
++#define DH_ID 6
++#define DH_ATTRS 7
++static CK_ATTRIBUTE dh_template[] = {
++	{CKA_LABEL, NULL_PTR, 0},
++	{CKA_VERIFY, &truevalue, sizeof(truevalue)},
++	{CKA_TOKEN, &truevalue, sizeof(truevalue)},
++	{CKA_PRIVATE, &falsevalue, sizeof(falsevalue)},
++	{CKA_PRIME, NULL_PTR, 0},
++	{CKA_BASE, NULL_PTR, 0},
++	{CKA_ID, NULL_PTR, 0}
++};
++#define DH_PARAM_PRIME 0
++#define DH_PARAM_BASE 1
++#define DH_PARAM_ATTRS 2
++static CK_ATTRIBUTE dh_param_template[] = {
++	{CKA_PRIME, NULL_PTR, 0},
++	{CKA_BASE, NULL_PTR, 0},
++};
++#define DH_DOMAIN_PRIMEBITS 0
++#define DH_DOMAIN_ATTRS 1
++static CK_ATTRIBUTE dh_domain_template[] = {
++	{CKA_PRIME_BITS, NULL_PTR, 0},
++};
++
++/*
++ * Convert from text to key class.  Accepts the names of DNSSEC
++ * signing algorithms, so e.g., ECDSAP256SHA256 maps to ECC and
++ * NSEC3RSASHA1 maps to RSA.
++ */
++static key_class_t
++keyclass_fromtext(const char *name) {
++	if (name == NULL)
++		return (key_unknown);
++
++	if (strncasecmp(name, "rsa", 3) == 0 ||
++	    strncasecmp(name, "nsec3rsa", 8) == 0)
++		return (key_rsa);
++	else if (strncasecmp(name, "dsa", 3) == 0 ||
++		 strncasecmp(name, "nsec3dsa", 8) == 0)
++		return (key_dsa);
++	else if (strcasecmp(name, "dh") == 0)
++		return (key_dh);
++	else if (strncasecmp(name, "ecc", 3) == 0 ||
++		 strncasecmp(name, "ecdsa", 5) == 0)
++		return (key_ecc);
++	else
++		return (key_unknown);
++}
++
++static void
++usage() {
++	fprintf(stderr,
++		"Usage:\n"
++		"\tpkcs11-keygen -a algorithm -b keysize -l label\n"
++		"\t              [-P] [-m module] "
++			"[-s slot] [-e] [-S] [-i id] [-p PIN]\n");
++	exit(2);
++}
++
+ int
+-main(int argc, char *argv[])
+-{
++main(int argc, char *argv[]) {
++	isc_result_t result;
+ 	CK_RV rv;
+ 	CK_SLOT_ID slot = 0;
+-	CK_MECHANISM genmech;
++	CK_MECHANISM mech, dpmech;
+ 	CK_SESSION_HANDLE hSession;
+-	CK_UTF8CHAR *pin = NULL;
+-	CK_ULONG modulusbits = 0;
++	char *lib_name = NULL;
++	char *pin = NULL;
++	CK_ULONG bits = 0;
+ 	CK_CHAR *label = NULL;
+-	CK_OBJECT_HANDLE privatekey, publickey;
+-	CK_BYTE public_exponent[5];
+-	CK_ULONG expsize = 3;
++	CK_OBJECT_HANDLE privatekey, publickey, domainparams;
++	CK_BYTE exponent[5];
++	CK_ULONG expsize = 0;
++	pk11_context_t pctx;
+ 	int error = 0;
+ 	int c, errflg = 0;
+-	int hide = 1;
+-	int idlen = 0;
++	int hide = 1, special = 0, quiet = 0;
++	int idlen = 0, id_offset = 0;
++	unsigned int i;
+ 	unsigned long id = 0;
+ 	CK_BYTE idbuf[4];
+ 	CK_ULONG ulObjectCount;
+-	/* Set search template */
+ 	CK_ATTRIBUTE search_template[] = {
+ 		{CKA_LABEL, NULL_PTR, 0}
+ 	};
+-	CK_ATTRIBUTE publickey_template[] = {
+-		{CKA_LABEL, NULL_PTR, 0},
+-		{CKA_VERIFY, &truevalue, sizeof(truevalue)},
+-		{CKA_TOKEN, &truevalue, sizeof(truevalue)},
+-		{CKA_MODULUS_BITS, &modulusbits, sizeof(modulusbits)},
+-		{CKA_PUBLIC_EXPONENT, &public_exponent, expsize},
+-		{CKA_ID, &idbuf, idlen}
+-	};
+-	CK_ULONG publickey_attrcnt = 6;
+-	CK_ATTRIBUTE privatekey_template[] = {
+-		{CKA_LABEL, NULL_PTR, 0},
+-		{CKA_SIGN, &truevalue, sizeof(truevalue)},
+-		{CKA_TOKEN, &truevalue, sizeof(truevalue)},
+-		{CKA_PRIVATE, &truevalue, sizeof(truevalue)},
+-		{CKA_SENSITIVE, &truevalue, sizeof(truevalue)},
+-		{CKA_EXTRACTABLE, &falsevalue, sizeof(falsevalue)},
+-		{CKA_ID, &idbuf, idlen}
+-	};
+-	CK_ULONG privatekey_attrcnt = 7;
+-	char *pk11_provider;
+-	extern char *optarg;
+-	extern int optopt;
+ 
+-	pk11_provider = getenv("PKCS11_PROVIDER");
+-	if (pk11_provider != NULL)
+-		pk11_libname = pk11_provider;
++	CK_ATTRIBUTE *public_template = NULL;
++	CK_ATTRIBUTE *domain_template = NULL;
++	CK_ATTRIBUTE *param_template = NULL;
++	CK_ULONG public_attrcnt = 0, private_attrcnt = PRIVATE_ATTRS;
++	CK_ULONG domain_attrcnt = 0, param_attrcnt = 0;
++	key_class_t keyclass = key_rsa;
++	pk11_optype_t op_type = OP_ANY;
+ 
+-	while ((c = getopt(argc, argv, ":Pm:s:b:ei:l:p:")) != -1) {
++#define OPTIONS ":a:b:ei:l:m:Pp:qSs:"
++	while ((c = isc_commandline_parse(argc, argv, OPTIONS)) != -1) {
+ 		switch (c) {
++		case 'a':
++			keyclass = keyclass_fromtext(isc_commandline_argument);
++			break;
+ 		case 'P':
+ 			hide = 0;
+ 			break;
+ 		case 'm':
+-			pk11_libname = optarg;
++			lib_name = isc_commandline_argument;
+ 			break;
+ 		case 's':
+-			slot = atoi(optarg);
++			slot = atoi(isc_commandline_argument);
+ 			break;
+ 		case 'e':
+ 			expsize = 5;
+ 			break;
+ 		case 'b':
+-			modulusbits = atoi(optarg);
++			bits = atoi(isc_commandline_argument);
+ 			break;
+ 		case 'l':
+-			label = (CK_CHAR *)optarg;
++			/* -l option is retained for backward compatibility * */
++			label = (CK_CHAR *)isc_commandline_argument;
+ 			break;
+ 		case 'i':
+-			id = strtoul(optarg, NULL, 0);
++			id = strtoul(isc_commandline_argument, NULL, 0);
+ 			idlen = 4;
+ 			break;
+ 		case 'p':
+-			pin = (CK_UTF8CHAR *)optarg;
++			pin = isc_commandline_argument;
++			break;
++		case 'q':
++			quiet = 1;
++			break;
++		case 'S':
++			special = 1;
+ 			break;
+ 		case ':':
+ 			fprintf(stderr,
+ 				"Option -%c requires an operand\n",
+-				optopt);
++				isc_commandline_option);
+ 			errflg++;
+ 			break;
+ 		case '?':
+ 		default:
+-			fprintf(stderr, "Unrecognised option: -%c\n", optopt);
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
+ 			errflg++;
+ 		}
+ 	}
+ 
+-	if (errflg || !modulusbits || (label == NULL)) {
+-		fprintf(stderr, "Usage:\n");
+-		fprintf(stderr, "\tpkcs11-keygen -b keysize -l label\n");
+-		fprintf(stderr, "\t              [-P] [-m module] "
+-				"[-s slot] [-e] [-i id] [-p PIN]\n");
++	if (label == NULL && isc_commandline_index < argc)
++		label = (CK_CHAR *)argv[isc_commandline_index];
++
++	if (errflg || (label == NULL))
++		usage();
++
++	if (expsize != 0 && keyclass != key_rsa) {
++		fprintf(stderr, "The -e option is only compatible "
++				"with RSA key generation\n");
+ 		exit(2);
+ 	}
++
++	if (special != 0 && keyclass != key_dh) {
++		fprintf(stderr, "The -S option is only compatible "
++				"with Diffie-Hellman key generation\n");
++		exit(2);
++	}
++
++	switch (keyclass) {
++	case key_rsa:
++		op_type = OP_RSA;
++		if (expsize == 0)
++			expsize = 3;
++		if (bits == 0)
++			usage();
++
++		mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
++		mech.pParameter = NULL;
++		mech.ulParameterLen = 0;
++
++		public_template = rsa_template;
++		public_attrcnt = RSA_ATTRS;
++		id_offset = RSA_ID;
++
++		/* Set public exponent to F4 or F5 */
++		exponent[0] = 0x01;
++		exponent[1] = 0x00;
++		if (expsize == 3)
++			exponent[2] = 0x01;
++		else {
++			exponent[2] = 0x00;
++			exponent[3] = 0x00;
++			exponent[4] = 0x01;
++		}
++
++		public_template[RSA_MODULUS_BITS].pValue = &bits;
++		public_template[RSA_MODULUS_BITS].ulValueLen = sizeof(bits);
++		public_template[RSA_PUBLIC_EXPONENT].pValue = &exponent;
++		public_template[RSA_PUBLIC_EXPONENT].ulValueLen = expsize;
++		break;
++	case key_ecc:
++		op_type = OP_EC;
++		if (bits == 0)
++			bits = 256;
++		else if (bits != 256 && bits != 384) {
++			fprintf(stderr, "ECC keys only support bit sizes of "
++					"256 and 384\n");
++			exit(2);
++		}
++
++		mech.mechanism = CKM_EC_KEY_PAIR_GEN;
++		mech.pParameter = NULL;
++		mech.ulParameterLen = 0;
++
++		public_template = ecc_template;
++		public_attrcnt = ECC_ATTRS;
++		id_offset = ECC_ID;
++
++		if (bits == 256) {
++			public_template[4].pValue = pk11_ecc_prime256v1;
++			public_template[4].ulValueLen =
++				sizeof(pk11_ecc_prime256v1);
++		} else {
++			public_template[4].pValue = pk11_ecc_secp384r1;
++			public_template[4].ulValueLen =
++				sizeof(pk11_ecc_secp384r1);
++		}
++
++		break;
++	case key_dsa:
++		op_type = OP_DSA;
++		if (bits == 0)
++			usage();
++
++		dpmech.mechanism = CKM_DSA_PARAMETER_GEN;
++		dpmech.pParameter = NULL;
++		dpmech.ulParameterLen = 0;
++		mech.mechanism = CKM_DSA_KEY_PAIR_GEN;
++		mech.pParameter = NULL;
++		mech.ulParameterLen = 0;
++
++		public_template = dsa_template;
++		public_attrcnt = DSA_ATTRS;
++		id_offset = DSA_ID;
++
++		domain_template = dsa_domain_template;
++		domain_attrcnt = DSA_DOMAIN_ATTRS;
++		param_template = dsa_param_template;
++		param_attrcnt = DSA_PARAM_ATTRS;
++
++		domain_template[DSA_DOMAIN_PRIMEBITS].pValue = &bits;
++		domain_template[DSA_DOMAIN_PRIMEBITS].ulValueLen = sizeof(bits);
++		break;
++	case key_dh:
++		op_type = OP_DH;
++		if (special && bits == 0)
++			bits = 1024;
++		else if (special &&
++			 bits != 768 && bits != 1024 && bits != 1536)
++		{
++			fprintf(stderr, "When using the special prime (-S) "
++				"option, only key sizes of\n"
++				"768, 1024 or 1536 are supported.\n");
++			exit(2);
++		} else if (bits == 0)
++			usage();
++
++		dpmech.mechanism = CKM_DH_PKCS_PARAMETER_GEN;
++		dpmech.pParameter = NULL;
++		dpmech.ulParameterLen = 0;
++		mech.mechanism = CKM_DH_PKCS_KEY_PAIR_GEN;
++		mech.pParameter = NULL;
++		mech.ulParameterLen = 0;
++
++		/* Override CKA_SIGN attribute */
++		private_template[PRIVATE_DERIVE].type = CKA_DERIVE;
++
++		public_template = dh_template;
++		public_attrcnt = DH_ATTRS;
++		id_offset = DH_ID;
++
++		domain_template = dh_domain_template;
++		domain_attrcnt = DH_DOMAIN_ATTRS;
++		param_template = dh_param_template;
++		param_attrcnt = DH_PARAM_ATTRS;
++
++		domain_template[DH_DOMAIN_PRIMEBITS].pValue = &bits;
++		domain_template[DH_DOMAIN_PRIMEBITS].ulValueLen = sizeof(bits);
++		break;
++	case key_unknown:
++		usage();
++	}
+ 	
+ 	search_template[0].pValue = label;
+ 	search_template[0].ulValueLen = strlen((char *)label);
+-	publickey_template[0].pValue = label;
+-	publickey_template[0].ulValueLen = strlen((char *)label);
+-	privatekey_template[0].pValue = label;
+-	privatekey_template[0].ulValueLen = strlen((char *)label);
+-
+-	/* Set public exponent to F4 or F5 */
+-	public_exponent[0] = 0x01;
+-	public_exponent[1] = 0x00;
+-	if (expsize == 3)
+-		public_exponent[2] = 0x01;
+-	else {
+-		publickey_template[4].ulValueLen = expsize;
+-		public_exponent[2] = 0x00;
+-		public_exponent[3] = 0x00;
+-		public_exponent[4] = 0x01;
+-	}
+-
+-	/* Set up mechanism for generating key pair */
+-	genmech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
+-	genmech.pParameter = NULL_PTR;
+-	genmech.ulParameterLen = 0;
++	public_template[0].pValue = label;
++	public_template[0].ulValueLen = strlen((char *)label);
++	private_template[0].pValue = label;
++	private_template[0].ulValueLen = strlen((char *)label);
+ 
+ 	if (idlen == 0) {
+-		publickey_attrcnt--;
+-		privatekey_attrcnt--;
+-	} else if (id <= 0xffff) {
+-		idlen = 2;
+-		publickey_template[5].ulValueLen = idlen;
+-		privatekey_template[6].ulValueLen = idlen;
+-		idbuf[0] = (CK_BYTE)(id >> 8);
+-		idbuf[1] = (CK_BYTE)id;
++		public_attrcnt--;
++		private_attrcnt--;
+ 	} else {
+-		idbuf[0] = (CK_BYTE)(id >> 24);
+-		idbuf[1] = (CK_BYTE)(id >> 16);
+-		idbuf[2] = (CK_BYTE)(id >> 8);
+-		idbuf[3] = (CK_BYTE)id;
+-	}
+-
+-	/* Initialize the CRYPTOKI library */
+-	rv = C_Initialize(NULL_PTR);
++		if (id <= 0xffff) {
++			idlen = 2;
++			idbuf[0] = (CK_BYTE)(id >> 8);
++			idbuf[1] = (CK_BYTE)id;
++		} else {
++			idbuf[0] = (CK_BYTE)(id >> 24);
++			idbuf[1] = (CK_BYTE)(id >> 16);
++			idbuf[2] = (CK_BYTE)(id >> 8);
++			idbuf[3] = (CK_BYTE)id;
++		}
+ 
+-	if (rv != CKR_OK) {
+-		if (rv == 0xfe)
+-			fprintf(stderr,
+-				"Can't load or link module \"%s\"\n",
+-				pk11_libname);
+-		else
+-			fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv);
+-		exit(1);
++		public_template[id_offset].pValue = idbuf;
++		public_template[id_offset].ulValueLen = idlen;
++		private_template[PRIVATE_ID].pValue = idbuf;
++		private_template[PRIVATE_ID].ulValueLen = idlen;
+ 	}
+ 
+-	/* Open a session on the slot found */
+-	rv = C_OpenSession(slot, CKF_RW_SESSION+CKF_SERIAL_SESSION,
+-			   NULL_PTR, NULL_PTR, &hSession);
++	pk11_result_register();
+ 
+-	if (rv != CKR_OK) {
+-		fprintf(stderr, "C_OpenSession: Error = 0x%.8lX\n", rv);
+-		error = 1;
+-		goto exit_program;
+-	}
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
+ 
+-	/* Login to the Token (Keystore) */
+ 	if (pin == NULL)
+-		pin = (CK_UTF8CHAR *)getpassphrase("Enter Pin: ");
++		pin = getpassphrase("Enter Pin: ");
+ 
+-	rv = C_Login(hSession, CKU_USER, pin, strlen((char *)pin));
+-	memset(pin, 0, strlen((char *)pin));
+-	if (rv != CKR_OK) {
+-		fprintf(stderr, "C_Login: Error = 0x%.8lX\n", rv);
+-		error = 1;
+-		goto exit_session;
++	result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_TRUE,
++				  ISC_TRUE, (const char *) pin, slot);
++	if (result == PK11_R_NORANDOMSERVICE ||
++	    result == PK11_R_NODIGESTSERVICE ||
++	    result == PK11_R_NOAESSERVICE) {
++		fprintf(stderr, "Warning: %s\n", isc_result_totext(result));
++		fprintf(stderr, "This HSM will not work with BIND 9 "
++				"using native PKCS#11.\n");
++	} else if (result != ISC_R_SUCCESS) {
++		fprintf(stderr, "Unrecoverable error initializing "
++				"PKCS#11: %s\n", isc_result_totext(result));
++		exit(1);
+ 	}
+ 
++	/* Login to the Token (Keystore) */
++	memset(pin, 0, strlen(pin));
++	hSession = pctx.session;
++
+ 	/* check if a key with the same id already exists */
+-	rv = C_FindObjectsInit(hSession, search_template, 1); 
++	rv = pkcs_C_FindObjectsInit(hSession, search_template, 1);
+ 	if (rv != CKR_OK) {
+ 		fprintf(stderr, "C_FindObjectsInit: Error = 0x%.8lX\n", rv);
+ 		error = 1;
+ 		goto exit_session;
+ 	}
+-	rv = C_FindObjects(hSession, &privatekey, 1, &ulObjectCount);
++	rv = pkcs_C_FindObjects(hSession, &privatekey, 1, &ulObjectCount);
+ 	if (rv != CKR_OK) {
+ 		fprintf(stderr, "C_FindObjects: Error = 0x%.8lX\n", rv);
+ 		error = 1;
+@@ -276,33 +568,140 @@ main(int argc, char *argv[])
+ 
+ 	/* Set attributes if the key is not to be hidden */
+ 	if (!hide) {
+-		privatekey_template[4].pValue = &falsevalue;
+-		privatekey_template[5].pValue = &truevalue;
++		private_template[4].pValue = &falsevalue;
++		private_template[5].pValue = &truevalue;
++	}
++
++	if (keyclass == key_rsa || keyclass == key_ecc)
++		goto generate_keys;
++
++	/*
++	 * Special setup for Diffie-Hellman keys
++	 */
++	if (special != 0) {
++		public_template[DH_BASE].pValue = pk11_dh_bn2;
++		public_template[DH_BASE].ulValueLen = sizeof(pk11_dh_bn2);
++		if (bits == 768) {
++			public_template[DH_PRIME].pValue = pk11_dh_bn768;
++			public_template[DH_PRIME].ulValueLen =
++				sizeof(pk11_dh_bn768);
++		} else if (bits == 1024) {
++			public_template[DH_PRIME].pValue = pk11_dh_bn1024;
++			public_template[DH_PRIME].ulValueLen =
++				sizeof(pk11_dh_bn1024);
++		} else {
++			public_template[DH_PRIME].pValue = pk11_dh_bn1536;
++			public_template[DH_PRIME].ulValueLen =
++				sizeof(pk11_dh_bn1536);
++		}
++		param_attrcnt = 0;
++		goto generate_keys;
++	}
++
++	/* Generate Domain parameters */
++	rv = pkcs_C_GenerateKey(hSession, &dpmech, domain_template,
++			   domain_attrcnt, &domainparams);
++
++	if (rv != CKR_OK) {
++		fprintf(stderr,
++			"C_GenerateKey: Error = 0x%.8lX\n", rv);
++		error = 1;
++		goto exit_search;
++	}
++
++	/* Get Domain parameters */
++	rv = pkcs_C_GetAttributeValue(hSession, domainparams,
++				 param_template, param_attrcnt);
++
++	if (rv != CKR_OK) {
++		fprintf(stderr,
++			"C_GetAttributeValue0: Error = 0x%.8lX\n", rv);
++		error = 1;
++		goto exit_domain;
++	}
++
++	/* Allocate space for parameter attributes */
++	for (i = 0; i < param_attrcnt; i++)
++		param_template[i].pValue = malloc(param_template[i].ulValueLen);
++
++	rv = pkcs_C_GetAttributeValue(hSession, domainparams,
++				 dsa_param_template, DSA_PARAM_ATTRS);
++
++	if (rv != CKR_OK) {
++		fprintf(stderr,
++			"C_GetAttributeValue1: Error = 0x%.8lX\n", rv);
++		error = 1;
++		goto exit_params;
++	}
++
++	switch (keyclass) {
++	case key_dsa:
++		public_template[DSA_PRIME].pValue =
++			param_template[DSA_PARAM_PRIME].pValue;
++		public_template[DSA_PRIME].ulValueLen =
++			param_template[DSA_PARAM_PRIME].ulValueLen;
++		public_template[DSA_SUBPRIME].pValue =
++			param_template[DSA_PARAM_SUBPRIME].pValue;
++		public_template[DSA_SUBPRIME].ulValueLen =
++			param_template[DSA_PARAM_SUBPRIME].ulValueLen;
++		public_template[DSA_BASE].pValue =
++			param_template[DSA_PARAM_BASE].pValue;
++		public_template[DSA_BASE].ulValueLen =
++			param_template[DSA_PARAM_BASE].ulValueLen;
++		break;
++	case key_dh:
++		public_template[DH_PRIME].pValue =
++			param_template[DH_PARAM_PRIME].pValue;
++		public_template[DH_PRIME].ulValueLen =
++			param_template[DH_PARAM_PRIME].ulValueLen;
++		public_template[DH_BASE].pValue =
++			param_template[DH_PARAM_BASE].pValue;
++		public_template[DH_BASE].ulValueLen =
++			param_template[DH_PARAM_BASE].ulValueLen;
++	default:
++		break;
+ 	}
+ 
++ generate_keys:
+ 	/* Generate Key pair for signing/verifying */
+-	rv = C_GenerateKeyPair(hSession, &genmech,
+-			       publickey_template, publickey_attrcnt,
+-			       privatekey_template, privatekey_attrcnt,
++	rv = pkcs_C_GenerateKeyPair(hSession, &mech,
++			       public_template, public_attrcnt,
++			       private_template, private_attrcnt,
+ 			       &publickey, &privatekey);
+ 	
+ 	if (rv != CKR_OK) {
+ 		fprintf(stderr, "C_GenerateKeyPair: Error = 0x%.8lX\n", rv);
+ 		error = 1;
++	 } else if (!quiet)
++		printf("Key pair generation complete.\n");
++
++ exit_params:
++	/* Free parameter attributes */
++	if (keyclass == key_dsa || keyclass == key_dh)
++		for (i = 0; i < param_attrcnt; i++)
++			free(param_template[i].pValue);
++
++ exit_domain:
++	/* Destroy domain parameters */
++	if (keyclass == key_dsa || (keyclass == key_dh && !special)) {
++		rv = pkcs_C_DestroyObject(hSession, domainparams);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_DestroyObject: Error = 0x%.8lX\n", rv);
++			error = 1;
++		}
+ 	}
+-	
++
+  exit_search:
+-	rv = C_FindObjectsFinal(hSession);
++	rv = pkcs_C_FindObjectsFinal(hSession);
+ 	if (rv != CKR_OK) {
+ 		fprintf(stderr, "C_FindObjectsFinal: Error = 0x%.8lX\n", rv);
+ 		error = 1;
+ 	}
+ 
+  exit_session:
+-	(void)C_CloseSession(hSession);
+-
+- exit_program:
+-	(void)C_Finalize(NULL_PTR);
++	pk11_return_session(&pctx);
++	(void) pk11_finalize();
+ 
+ 	exit(error);
+ }
+diff --git a/bin/pkcs11/pkcs11-keygen.docbook b/bin/pkcs11/pkcs11-keygen.docbook
+index 7c4ba08..d62ba2f 100644
+--- a/bin/pkcs11/pkcs11-keygen.docbook
++++ b/bin/pkcs11/pkcs11-keygen.docbook
+@@ -18,25 +18,26 @@
+ -->
+ 
+ <!-- $Id: pkcs11-keygen.docbook,v 1.3 2009/10/05 12:23:11 fdupont Exp $ -->
+-<refentry id="man.pkcs11-keygen">
++<refentry id="man.pkcs11-ecgen">
+   <refentryinfo>
+-    <date>Sep 18, 2009</date>
++    <date>Feb 30, 2012</date>
+   </refentryinfo>
+ 
+   <refmeta>
+-    <refentrytitle><application>pkcs11-keygen</application></refentrytitle>
++    <refentrytitle><application>pkcs11-ecgen</application></refentrytitle>
+     <manvolnum>8</manvolnum>
+     <refmiscinfo>BIND9</refmiscinfo>
+   </refmeta>
+ 
+   <refnamediv>
+     <refname><application>pkcs11-keygen</application></refname>
+-    <refpurpose>generate RSA keys on a PKCS#11 device</refpurpose>
++    <refpurpose>generate keys on a PKCS#11 device</refpurpose>
+   </refnamediv>
+ 
+   <docinfo>
+     <copyright>
+       <year>2009</year>
++      <year>2014</year>
+       <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+     </copyright>
+   </docinfo>
+@@ -44,14 +45,17 @@
+   <refsynopsisdiv>
+     <cmdsynopsis>
+       <command>pkcs11-keygen</command>
+-      <arg><option>-P</option></arg>
+-      <arg><option>-m <replaceable class="parameter">module</replaceable></option></arg>
+-      <arg><option>-s <replaceable class="parameter">slot</replaceable></option></arg>
++      <arg choice="req">-a <replaceable class="parameter">algorithm</replaceable></arg>
++      <arg><option>-b <replaceable class="parameter">keysize</replaceable></option></arg>
+       <arg><option>-e</option></arg>
+-      <arg choice="req">-b <replaceable class="parameter">keysize</replaceable></arg>
+-      <arg choice="req">-l <replaceable class="parameter">label</replaceable></arg>
+       <arg><option>-i <replaceable class="parameter">id</replaceable></option></arg>
++      <arg><option>-m <replaceable class="parameter">module</replaceable></option></arg>
++      <arg><option>-P</option></arg>
+       <arg><option>-p <replaceable class="parameter">PIN</replaceable></option></arg>
++      <arg><option>-q</option></arg>
++      <arg><option>-S</option></arg>
++      <arg><option>-s <replaceable class="parameter">slot</replaceable></option></arg>
++      <arg choice="req">label</arg>
+     </cmdsynopsis>
+   </refsynopsisdiv>
+ 
+@@ -59,8 +63,8 @@
+     <title>DESCRIPTION</title>
+     <para>
+       <command>pkcs11-keygen</command> causes a PKCS#11 device to generate
+-      a new RSA key pair with the specified <option>label</option> and
+-      with <option>keysize</option> bits of modulus.
++      a new key pair with the given <option>label</option> (which must be
++      unique) and with <option>keysize</option> bits of prime.
+     </para>
+   </refsect1>
+ 
+@@ -68,83 +72,109 @@
+     <title>ARGUMENTS</title>
+     <variablelist>
+       <varlistentry>
+-        <term>-P</term>
++        <term>-a <replaceable class="parameter">algorithm</replaceable></term>
+         <listitem>
+           <para>
+-            Set the new private key to be non-sensitive and extractable.
+-            The allows the private key data to be read from the PKCS#11
+-            device.  The default is for private keys to be sensitive and
+-            non-extractable.
++            Specify the key algorithm class: Supported classes are RSA,
++            DSA, DH, and ECC. In addition to these strings, the
++            <option>algorithm</option> can be specified as a DNSSEC
++            signing algorithm that will be used with this key; for
++            example, NSEC3RSASHA1 maps to RSA, and ECDSAP256SHA256 maps
++            to ECC.  The default class is "RSA".
+           </para>
+         </listitem>
+       </varlistentry>
+ 
+       <varlistentry>
+-        <term>-m <replaceable class="parameter">module</replaceable></term>
++        <term>-b <replaceable class="parameter">keysize</replaceable></term>
+         <listitem>
+           <para>
+-            Specify the PKCS#11 provider module.  This must be the full
+-            path to a shared library object implementing the PKCS#11 API
+-            for the device.
++            Create the key pair with <option>keysize</option> bits of
++            prime. For ECC keys, the only valid values are 256 and 384,
++            and the default is 256.
+           </para>
+         </listitem>
+       </varlistentry>
+ 
+       <varlistentry>
+-        <term>-s <replaceable class="parameter">slot</replaceable></term>
++        <term>-e</term>
+         <listitem>
+           <para>
+-            Open the session with the given PKCS#11 slot.  The default is
+-            slot 0.
++            For RSA keys only, use a large exponent.
+           </para>
+         </listitem>
+       </varlistentry>
+ 
+       <varlistentry>
+-        <term>-e</term>
++        <term>-i <replaceable class="parameter">id</replaceable></term>
+         <listitem>
+           <para>
+-            Use a large exponent.
++            Create key objects with id. The id is either
++            an unsigned short 2 byte or an unsigned long 4 byte number.
+           </para>
+         </listitem>
+       </varlistentry>
+ 
+       <varlistentry>
+-        <term>-b <replaceable class="parameter">keysize</replaceable></term>
++        <term>-m <replaceable class="parameter">module</replaceable></term>
+         <listitem>
+           <para>
+-            Create the key pair with <option>keysize</option> bits of
+-            modulus.
++            Specify the PKCS#11 provider module.  This must be the full
++            path to a shared library object implementing the PKCS#11 API
++            for the device.
++          </para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
++        <term>-P</term>
++        <listitem>
++          <para>
++            Set the new private key to be non-sensitive and extractable.
++            The allows the private key data to be read from the PKCS#11
++            device.  The default is for private keys to be sensitive and
++            non-extractable.
+           </para>
+         </listitem>
+       </varlistentry>
+ 
+       <varlistentry>
+-        <term>-l <replaceable class="parameter">label</replaceable></term>
++        <term>-p <replaceable class="parameter">PIN</replaceable></term>
+         <listitem>
+           <para>
+-            Create key objects with the given label.
+-            This name must be unique.
++            Specify the PIN for the device.  If no PIN is provided on
++            the command line, <command>pkcs11-ecgen</command> will
++            prompt for it.
+           </para>
+         </listitem>
+       </varlistentry>
+ 
+       <varlistentry>
+-        <term>-i <replaceable class="parameter">id</replaceable></term>
++		<term>-q</term>
+         <listitem>
+           <para>
+-            Create key objects with id. The id is either
+-            an unsigned short 2 byte or an unsigned long 4 byte number.
++		    Quiet mode: suppress unnecessary output.
++          </para>
++        </listitem>
++      </varlistentry>
++
++	  <varlistentry>
++        <term>-S</term>
++        <listitem>
++          <para>
++            For Diffie-Hellman (DH) keys only, use a special prime of
++            768, 1024 or 1536 bit size and base (aka generator) 2.
++	    If not specified, bit size will default to 1024.
+           </para>
+         </listitem>
+       </varlistentry>
+ 
+       <varlistentry>
+-        <term>-p <replaceable class="parameter">PIN</replaceable></term>
++        <term>-s <replaceable class="parameter">slot</replaceable></term>
+         <listitem>
+           <para>
+-            Specify the PIN for the device.  If no PIN is provided on the
+-            command line, <command>pkcs11-keygen</command> will prompt for it.
++            Open the session with the given PKCS#11 slot.  The default is
++            slot 0.
+           </para>
+         </listitem>
+       </varlistentry>
+@@ -155,6 +185,12 @@
+     <title>SEE ALSO</title>
+     <para>
+       <citerefentry>
++        <refentrytitle>pkcs11-rsagen</refentrytitle><manvolnum>3</manvolnum>
++      </citerefentry>,
++      <citerefentry>
++        <refentrytitle>pkcs11-dsagen</refentrytitle><manvolnum>3</manvolnum>
++      </citerefentry>,
++      <citerefentry>
+         <refentrytitle>pkcs11-list</refentrytitle><manvolnum>3</manvolnum>
+       </citerefentry>,
+       <citerefentry>
+@@ -167,11 +203,6 @@
+   </refsect1>
+ 
+   <refsect1>
+-    <title>CAVEAT</title>
+-    <para>Some PKCS#11 providers crash with big public exponent.</para>
+-  </refsect1>
+-
+-  <refsect1>
+     <title>AUTHOR</title>
+     <para><corpauthor>Internet Systems Consortium</corpauthor>
+     </para>
+diff --git a/bin/pkcs11/pkcs11-keygen.html b/bin/pkcs11/pkcs11-keygen.html
+index 41378fc..c7fdecf 100644
+--- a/bin/pkcs11/pkcs11-keygen.html
++++ b/bin/pkcs11/pkcs11-keygen.html
+@@ -18,36 +18,53 @@
+ <html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+-<title>pkcs11-keygen</title>
++<title>pkcs11-ecgen</title>
+ <meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
+ </head>
+ <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
+-<a name="man.pkcs11-keygen"></a><div class="titlepage"></div>
++<a name="man.pkcs11-ecgen"></a><div class="titlepage"></div>
+ <div class="refnamediv">
+ <h2>Name</h2>
+-<p><span class="application">pkcs11-keygen</span> &#8212; generate RSA keys on a PKCS#11 device</p>
++<p><span class="application">pkcs11-keygen</span> &#8212; generate keys on a PKCS#11 device</p>
+ </div>
+ <div class="refsynopsisdiv">
+ <h2>Synopsis</h2>
+-<div class="cmdsynopsis"><p><code class="command">pkcs11-keygen</code>  [<code class="option">-P</code>] [<code class="option">-m <em class="replaceable"><code>module</code></em></code>] [<code class="option">-s <em class="replaceable"><code>slot</code></em></code>] [<code class="option">-e</code>] {-b <em class="replaceable"><code>keysize</code></em>} {-l <em class="replaceable"><code>label</code></em>} [<code class="option">-i <em class="replaceable"><code>id</code></em></code>] [<code class="option">-p <em class="replaceable"><code>PIN</code></em></code>]</p></div>
++<div class="cmdsynopsis"><p><code class="command">pkcs11-keygen</code>  {-a <em class="replaceable"><code>algorithm</code></em>} [<code class="option">-b <em class="replaceable"><code>keysize</code></em></code>] [<code class="option">-e</code>] [<code class="option">-i <em class="replaceable"><code>id</code></em></code>] [<code class="option">-m <em class="replaceable"><code>module</code></em></code>] [<code class="option">-P</code>] [<code class="option">-p <em class="replaceable"><code>PIN</code></em></code>] [<code class="option">-q</code>] [<code class="option">-S</code>] [<code class="option">-s <em class="replaceable"><code>slot</code></em></code>] {label}</p></div>
+ </div>
+ <div class="refsect1" lang="en">
+-<a name="id2543397"></a><h2>DESCRIPTION</h2>
++<a name="id2543410"></a><h2>DESCRIPTION</h2>
+ <p>
+       <span><strong class="command">pkcs11-keygen</strong></span> causes a PKCS#11 device to generate
+-      a new RSA key pair with the specified <code class="option">label</code> and
+-      with <code class="option">keysize</code> bits of modulus.
++      a new key pair with the given <code class="option">label</code> (which must be
++      unique) and with <code class="option">keysize</code> bits of prime.
+     </p>
+ </div>
+ <div class="refsect1" lang="en">
+-<a name="id2543416"></a><h2>ARGUMENTS</h2>
++<a name="id2543430"></a><h2>ARGUMENTS</h2>
+ <div class="variablelist"><dl>
+-<dt><span class="term">-P</span></dt>
++<dt><span class="term">-a <em class="replaceable"><code>algorithm</code></em></span></dt>
+ <dd><p>
+-            Set the new private key to be non-sensitive and extractable.
+-            The allows the private key data to be read from the PKCS#11
+-            device.  The default is for private keys to be sensitive and
+-            non-extractable.
++            Specify the key algorithm class: Supported classes are RSA,
++            DSA, DH, and ECC. In addition to these strings, the
++            <code class="option">algorithm</code> can be specified as a DNSSEC
++            signing algorithm that will be used with this key; for
++            example, NSEC3RSASHA1 maps to RSA, and ECDSAP256SHA256 maps
++            to ECC.  The default class is "RSA".
++          </p></dd>
++<dt><span class="term">-b <em class="replaceable"><code>keysize</code></em></span></dt>
++<dd><p>
++            Create the key pair with <code class="option">keysize</code> bits of
++            prime. For ECC keys, the only valid values are 256 and 384,
++            and the default is 256.
++          </p></dd>
++<dt><span class="term">-e</span></dt>
++<dd><p>
++            For RSA keys only, use a large exponent.
++          </p></dd>
++<dt><span class="term">-i <em class="replaceable"><code>id</code></em></span></dt>
++<dd><p>
++            Create key objects with id. The id is either
++            an unsigned short 2 byte or an unsigned long 4 byte number.
+           </p></dd>
+ <dt><span class="term">-m <em class="replaceable"><code>module</code></em></span></dt>
+ <dd><p>
+@@ -55,51 +72,48 @@
+             path to a shared library object implementing the PKCS#11 API
+             for the device.
+           </p></dd>
+-<dt><span class="term">-s <em class="replaceable"><code>slot</code></em></span></dt>
+-<dd><p>
+-            Open the session with the given PKCS#11 slot.  The default is
+-            slot 0.
+-          </p></dd>
+-<dt><span class="term">-e</span></dt>
++<dt><span class="term">-P</span></dt>
+ <dd><p>
+-            Use a large exponent.
++            Set the new private key to be non-sensitive and extractable.
++            The allows the private key data to be read from the PKCS#11
++            device.  The default is for private keys to be sensitive and
++            non-extractable.
+           </p></dd>
+-<dt><span class="term">-b <em class="replaceable"><code>keysize</code></em></span></dt>
++<dt><span class="term">-p <em class="replaceable"><code>PIN</code></em></span></dt>
+ <dd><p>
+-            Create the key pair with <code class="option">keysize</code> bits of
+-            modulus.
++            Specify the PIN for the device.  If no PIN is provided on
++            the command line, <span><strong class="command">pkcs11-ecgen</strong></span> will
++            prompt for it.
+           </p></dd>
+-<dt><span class="term">-l <em class="replaceable"><code>label</code></em></span></dt>
++<dt><span class="term">-q</span></dt>
+ <dd><p>
+-            Create key objects with the given label.
+-            This name must be unique.
++            Quiet mode: suppress unnecessary output.
+           </p></dd>
+-<dt><span class="term">-i <em class="replaceable"><code>id</code></em></span></dt>
++<dt><span class="term">-S</span></dt>
+ <dd><p>
+-            Create key objects with id. The id is either
+-            an unsigned short 2 byte or an unsigned long 4 byte number.
++            For Diffie-Hellman (DH) keys only, use a special prime of
++            768, 1024 or 1536 bit size and base (aka generator) 2.
++	    	If not specified, bit size will default to 1024.
+           </p></dd>
+-<dt><span class="term">-p <em class="replaceable"><code>PIN</code></em></span></dt>
++<dt><span class="term">-s <em class="replaceable"><code>slot</code></em></span></dt>
+ <dd><p>
+-            Specify the PIN for the device.  If no PIN is provided on the
+-            command line, <span><strong class="command">pkcs11-keygen</strong></span> will prompt for it.
++            Open the session with the given PKCS#11 slot.  The default is
++            slot 0.
+           </p></dd>
+ </dl></div>
+ </div>
+ <div class="refsect1" lang="en">
+-<a name="id2543563"></a><h2>SEE ALSO</h2>
++<a name="id2543605"></a><h2>SEE ALSO</h2>
+ <p>
++      <span class="citerefentry"><span class="refentrytitle">pkcs11-rsagen</span>(3)</span>,
++      <span class="citerefentry"><span class="refentrytitle">pkcs11-dsagen</span>(3)</span>,
+       <span class="citerefentry"><span class="refentrytitle">pkcs11-list</span>(3)</span>,
+       <span class="citerefentry"><span class="refentrytitle">pkcs11-destroy</span>(3)</span>,
+       <span class="citerefentry"><span class="refentrytitle">dnssec-keyfromlabel</span>(3)</span>,
+     </p>
+ </div>
+ <div class="refsect1" lang="en">
+-<a name="id2543598"></a><h2>CAVEAT</h2>
+-<p>Some PKCS#11 providers crash with big public exponent.</p>
+-</div>
+-<div class="refsect1" lang="en">
+-<a name="id2543609"></a><h2>AUTHOR</h2>
++<a name="id2543657"></a><h2>AUTHOR</h2>
+ <p><span class="corpauthor">Internet Systems Consortium</span>
+     </p>
+ </div>
+diff --git a/bin/pkcs11/pkcs11-list.c b/bin/pkcs11/pkcs11-list.c
+index 336bf41..bc6ad28 100644
+--- a/bin/pkcs11/pkcs11-list.c
++++ b/bin/pkcs11/pkcs11-list.c
+@@ -52,74 +52,68 @@
+ #include <errno.h>
+ #include <string.h>
+ #include <sys/types.h>
+-#include "cryptoki.h"
+ 
+-#ifdef WIN32
+-#include "win32.c"
+-#else
+-#ifndef FORCE_STATIC_PROVIDER
+-#include "unix.c"
+-#endif
+-#endif
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/result.h>
+ 
+ #if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
+ #define getpassphrase(x)		getpass(x)
+ #endif
+ 
+ int
+-main(int argc, char *argv[])
+-{
++main(int argc, char *argv[]) {
++	isc_result_t result;
+ 	CK_RV rv;
+ 	CK_SLOT_ID slot = 0;
+ 	CK_SESSION_HANDLE hSession;
+-	CK_UTF8CHAR *pin = NULL;
+ 	CK_BYTE attr_id[2];
+ 	CK_OBJECT_HANDLE akey[50];
++	pk11_context_t pctx;
++	char *lib_name = NULL;
+ 	char *label = NULL;
+-	int error = 0, public = 0, all = 0;
++	char *pin = NULL;
++	isc_boolean_t error = ISC_FALSE, logon = ISC_TRUE, all = ISC_FALSE;
+ 	unsigned int i = 0, id = 0;
+ 	int c, errflg = 0;
+ 	CK_ULONG ulObjectCount;
+ 	CK_ATTRIBUTE search_template[] = {
+ 		{CKA_ID, &attr_id, sizeof(attr_id)}
+ 	};
+-	char *pk11_provider;
+-	extern char *optarg;
+-	extern int optopt;
+ 
+-	pk11_provider = getenv("PKCS11_PROVIDER");
+-	if (pk11_provider != NULL)
+-		pk11_libname = pk11_provider;
+-
+-	while ((c = getopt(argc, argv, ":m:s:i:l:p:P")) != -1) {
++	while ((c = isc_commandline_parse(argc, argv, ":m:s:i:l:p:P")) != -1) {
+ 		switch (c) {
+ 		case 'P':
+-			public = 1;
++			logon = ISC_FALSE;
+ 			break;
+ 		case 'm':
+-			pk11_libname = optarg;
++			lib_name = isc_commandline_argument;
+ 			break;
+ 		case 's':
+-			slot = atoi(optarg);
++			slot = atoi(isc_commandline_argument);
+ 			break;
+ 		case 'i':
+-			id = atoi(optarg);
++			id = atoi(isc_commandline_argument);
+ 			id &= 0xffff;
+ 			break;
+ 		case 'l':
+-			label = optarg;
++			label = isc_commandline_argument;
+ 			break;
+ 		case 'p':
+-			pin = (CK_UTF8CHAR *)optarg;
++			pin = isc_commandline_argument;
+ 			break;
+ 		case ':':
+ 			fprintf(stderr, "Option -%c requires an operand\n",
+-				optopt);
++				isc_commandline_option);
+ 			errflg++;
+ 			break;
+ 		case '?':
+ 		default:
+-			fprintf(stderr, "Unrecognised option: -%c\n", optopt);
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
+ 			errflg++;
+ 		}
+ 	}
+@@ -132,7 +126,7 @@ main(int argc, char *argv[])
+ 	}
+ 
+ 	if (!id && (label == NULL))
+-		all = 1;
++		all = ISC_TRUE;
+ 
+ 	if (slot)
+ 		printf("slot %lu\n", slot);
+@@ -148,41 +142,37 @@ main(int argc, char *argv[])
+ 		search_template[0].ulValueLen = strlen(label);
+ 	}
+ 
++	pk11_result_register();
++
+ 	/* Initialize the CRYPTOKI library */
+-	rv = C_Initialize(NULL_PTR);
+-	if (rv != CKR_OK) {
+-		if (rv == 0xfe)
+-			fprintf(stderr,
+-				"Can't load or link module \"%s\"\n",
+-				pk11_libname);
+-		else
+-			fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv);
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
++
++	if (logon && pin == NULL)
++		pin = getpassphrase("Enter Pin: ");
++
++	result = pk11_get_session(&pctx, OP_ANY, ISC_FALSE, ISC_FALSE,
++				  logon, pin, slot);
++	if (result == PK11_R_NORANDOMSERVICE ||
++	    result == PK11_R_NODIGESTSERVICE ||
++	    result == PK11_R_NOAESSERVICE) {
++		fprintf(stderr, "Warning: %s\n", isc_result_totext(result));
++		fprintf(stderr, "This HSM will not work with BIND 9 "
++				"using native PKCS#11.\n");
++	} else if (result != ISC_R_SUCCESS) {
++		fprintf(stderr, "Unrecoverable error initializing "
++			"PKCS#11: %s\n", isc_result_totext(result));
++		fprintf(stderr, "Unrecoverable error initializing "
++				"PKCS#11: %s\n", isc_result_totext(result));
+ 		exit(1);
+ 	}
+ 
+-	/* Open a session on the slot found */
+-	rv = C_OpenSession(slot, CKF_SERIAL_SESSION,
+-			   NULL_PTR, NULL_PTR, &hSession);
+-	if (rv != CKR_OK) {
+-		fprintf(stderr, "C_OpenSession: Error = 0x%.8lX\n", rv);
+-		error = 1;
+-		goto exit_program;
+-	}
++	if (pin != NULL)
++		memset(pin, 0, strlen(pin));
+ 
+-	/* Login to the Token (Keystore) */
+-	if (!public) {
+-		if (pin == NULL)
+-			pin = (CK_UTF8CHAR *)getpassphrase("Enter Pin: ");
+-		rv = C_Login(hSession, CKU_USER, pin, strlen((char *)pin));
+-		memset(pin, 0, strlen((char *)pin));
+-		if (rv != CKR_OK) {
+-			fprintf(stderr, "C_Login: Error = 0x%.8lX\n", rv);
+-			error = 1;
+-			goto exit_session;
+-		}
+-	}
++	hSession = pctx.session;
+ 
+-	rv = C_FindObjectsInit(hSession, search_template, all ? 0 : 1); 
++	rv = pkcs_C_FindObjectsInit(hSession, search_template, all ? 0 : 1); 
+ 	if (rv != CKR_OK) {
+ 		fprintf(stderr, "C_FindObjectsInit: Error = 0x%.8lX\n", rv);
+ 		error = 1;
+@@ -191,7 +181,7 @@ main(int argc, char *argv[])
+ 	
+ 	ulObjectCount = 1;
+ 	while (ulObjectCount) {
+-		rv = C_FindObjects(hSession, akey, 50, &ulObjectCount);
++		rv = pkcs_C_FindObjects(hSession, akey, 50, &ulObjectCount);
+ 		if (rv != CKR_OK) {
+ 			fprintf(stderr,
+ 				"C_FindObjects: Error = 0x%.8lX\n",
+@@ -215,7 +205,7 @@ main(int argc, char *argv[])
+ 			memset(labelbuf, 0, sizeof(labelbuf));
+ 			memset(idbuf, 0, sizeof(idbuf));
+ 
+-			rv = C_GetAttributeValue(hSession, akey[i],
++			rv = pkcs_C_GetAttributeValue(hSession, akey[i],
+ 						 template, 3);
+ 			if (rv != CKR_OK) {
+ 				fprintf(stderr,
+@@ -260,17 +250,15 @@ main(int argc, char *argv[])
+ 	}
+ 
+  exit_search:
+-	rv = C_FindObjectsFinal(hSession);
++	rv = pkcs_C_FindObjectsFinal(hSession);
+ 	if (rv != CKR_OK) {
+ 		fprintf(stderr, "C_FindObjectsFinal: Error = 0x%.8lX\n", rv);
+ 		error = 1;
+ 	}
+ 
+  exit_session:
+-	(void)C_CloseSession(hSession);
+-
+- exit_program:
+-	(void)C_Finalize(NULL_PTR);
++	pk11_return_session(&pctx);
++	(void) pk11_finalize();
+ 
+ 	exit(error);
+ }
+diff --git a/bin/pkcs11/pkcs11-tokens.8 b/bin/pkcs11/pkcs11-tokens.8
+new file mode 100644
+index 0000000..7c2be83
+--- /dev/null
++++ b/bin/pkcs11/pkcs11-tokens.8
+@@ -0,0 +1,51 @@
++.\" Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
++.\" 
++.\" Permission to use, copy, modify, and/or distribute this software for any
++.\" purpose with or without fee is hereby granted, provided that the above
++.\" copyright notice and this permission notice appear in all copies.
++.\" 
++.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++.\" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++.\" AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++.\" LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++.\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++.\" PERFORMANCE OF THIS SOFTWARE.
++.\"
++.\" $Id$
++.\"
++.hy 0
++.ad l
++.\"     Title: pkcs11\-tokens
++.\"    Author: 
++.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/>
++.\"      Date: August 25, 2013
++.\"    Manual: BIND9
++.\"    Source: BIND9
++.\"
++.TH "PKCS11\-TOKENS" "8" "August 25, 2013" "BIND9" "BIND9"
++.\" disable hyphenation
++.nh
++.\" disable justification (adjust text to left margin only)
++.ad l
++.SH "NAME"
++pkcs11\-tokens \- list PKCS#11 available tokens
++.SH "SYNOPSIS"
++.HP 14
++\fBpkcs11\-tokens\fR [\fB\-m\ \fR\fB\fImodule\fR\fR]
++.SH "DESCRIPTION"
++.PP
++\fBpkcs11\-tokens\fR
++lists the PKCS#11 available tokens with defaults from the slot/token scan performed at application initialization.
++.SH "ARGUMENTS"
++.PP
++\-m \fImodule\fR
++.RS 4
++Specify the PKCS#11 provider module. This must be the full path to a shared library object implementing the PKCS#11 API for the device.
++.RE
++.SH "AUTHOR"
++.PP
++Internet Systems Consortium
++.SH "COPYRIGHT"
++Copyright \(co 2013 Internet Systems Consortium, Inc. ("ISC")
++.br
+diff --git a/bin/pkcs11/pkcs11-tokens.c b/bin/pkcs11/pkcs11-tokens.c
+new file mode 100644
+index 0000000..ff4e030
+--- /dev/null
++++ b/bin/pkcs11/pkcs11-tokens.c
+@@ -0,0 +1,106 @@
++/*
++ * Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* $Id$ */
++
++/* pkcs11-tokens [-m module] */
++
++/*! \file */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <string.h>
++#include <sys/types.h>
++
++#include <isc/commandline.h>
++#include <isc/mem.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/result.h>
++
++int
++main(int argc, char *argv[]) {
++	isc_result_t result;
++	char *lib_name = NULL;
++	int c, errflg = 0;
++	isc_mem_t *mctx = NULL;
++	pk11_context_t pctx;
++
++	while ((c = isc_commandline_parse(argc, argv, ":m:")) != -1) {
++		switch (c) {
++		case 'm':
++			lib_name = isc_commandline_argument;
++			break;
++		case ':':
++			fprintf(stderr, "Option -%c requires an operand\n",
++				isc_commandline_option);
++			errflg++;
++			break;
++		case '?':
++		default:
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
++			errflg++;
++		}
++	}
++
++	if (errflg) {
++		fprintf(stderr, "Usage:\n");
++		fprintf(stderr, "\tpkcs11-tokens [-m module]\n");
++		exit(1);
++	}
++
++	if (isc_mem_create(0, 0, &mctx) != ISC_R_SUCCESS) {
++		fprintf(stderr, "isc_mem_create() failed\n");
++		exit(1);
++	}
++
++	pk11_result_register();
++
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
++
++	result = pk11_get_session(&pctx, OP_ANY, ISC_FALSE, ISC_FALSE,
++				  ISC_FALSE, NULL, 0);
++	if (result == PK11_R_NORANDOMSERVICE ||
++	    result == PK11_R_NODIGESTSERVICE ||
++	    result == PK11_R_NOAESSERVICE) {
++		fprintf(stderr, "Warning: %s\n", isc_result_totext(result));
++		fprintf(stderr, "This HSM will not work with BIND 9 "
++				"using native PKCS#11.\n\n");
++	} else if (result != ISC_R_SUCCESS) {
++		fprintf(stderr, "Unrecoverable error initializing "
++				"PKCS#11: %s\n", isc_result_totext(result));
++		exit(1);
++	}
++
++	pk11_dump_tokens();
++
++	if (pctx.handle != NULL)
++		pk11_return_session(&pctx);
++	(void) pk11_finalize();
++
++	isc_mem_destroy(&mctx);
++
++	exit(0);
++}
+diff --git a/bin/pkcs11/pkcs11-tokens.docbook b/bin/pkcs11/pkcs11-tokens.docbook
+new file mode 100644
+index 0000000..44dc7cd
+--- /dev/null
++++ b/bin/pkcs11/pkcs11-tokens.docbook
+@@ -0,0 +1,86 @@
++<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
++               "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
++	       [<!ENTITY mdash "&#8212;">]>
++<!--
++ - Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
++ -
++ - Permission to use, copy, modify, and/or distribute this software for any
++ - purpose with or without fee is hereby granted, provided that the above
++ - copyright notice and this permission notice appear in all copies.
++ -
++ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ - AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ - PERFORMANCE OF THIS SOFTWARE.
++-->
++
++<!-- $Id$ -->
++<refentry id="man.pkcs11-tokens">
++  <refentryinfo>
++    <date>August 25, 2013</date>
++  </refentryinfo>
++
++  <refmeta>
++    <refentrytitle><application>pkcs11-tokens</application></refentrytitle>
++    <manvolnum>8</manvolnum>
++    <refmiscinfo>BIND9</refmiscinfo>
++  </refmeta>
++
++  <refnamediv>
++    <refname><application>pkcs11-tokens</application></refname>
++    <refpurpose>list PKCS#11 available tokens</refpurpose>
++  </refnamediv>
++
++  <docinfo>
++    <copyright>
++      <year>2013</year>
++      <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
++    </copyright>
++  </docinfo>
++
++  <refsynopsisdiv>
++    <cmdsynopsis>
++      <command>pkcs11-tokens</command>
++      <arg><option>-m <replaceable class="parameter">module</replaceable></option></arg>
++    </cmdsynopsis>
++  </refsynopsisdiv>
++
++  <refsect1>
++    <title>DESCRIPTION</title>
++    <para>
++      <command>pkcs11-tokens</command>
++      lists the PKCS#11 available tokens with defaults from the slot/token
++      scan performed at application initialization.
++    </para>
++  </refsect1>
++
++  <refsect1>
++    <title>ARGUMENTS</title>
++    <variablelist>
++      <varlistentry>
++        <term>-m <replaceable class="parameter">module</replaceable></term>
++        <listitem>
++          <para>
++            Specify the PKCS#11 provider module.  This must be the full
++            path to a shared library object implementing the PKCS#11 API
++            for the device.
++          </para>
++        </listitem>
++      </varlistentry>
++    </variablelist>
++  </refsect1>
++
++  <refsect1>
++    <title>AUTHOR</title>
++    <para><corpauthor>Internet Systems Consortium</corpauthor>
++    </para>
++  </refsect1>
++
++</refentry><!--
++ - Local variables:
++ - mode: sgml
++ - End:
++-->
+diff --git a/bin/pkcs11/pkcs11-tokens.html b/bin/pkcs11/pkcs11-tokens.html
+new file mode 100644
+index 0000000..45d7243
+--- /dev/null
++++ b/bin/pkcs11/pkcs11-tokens.html
+@@ -0,0 +1,58 @@
++<!--
++ - Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
++ - 
++ - Permission to use, copy, modify, and/or distribute this software for any
++ - purpose with or without fee is hereby granted, provided that the above
++ - copyright notice and this permission notice appear in all copies.
++ - 
++ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ - PERFORMANCE OF THIS SOFTWARE.
++-->
++<!-- $Id$ -->
++<html>
++<head>
++<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
++<title>pkcs11-tokens</title>
++<meta name="generator" content="DocBook XSL Stylesheets V1.71.1">
++</head>
++<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en">
++<a name="man.pkcs11-tokens"></a><div class="titlepage"></div>
++<div class="refnamediv">
++<h2>Name</h2>
++<p><span class="application">pkcs11-tokens</span> &#8212; list PKCS#11 available tokens</p>
++</div>
++<div class="refsynopsisdiv">
++<h2>Synopsis</h2>
++<div class="cmdsynopsis"><p><code class="command">pkcs11-tokens</code>  [<code class="option">-m <em class="replaceable"><code>module</code></em></code>]</p></div>
++</div>
++<div class="refsect1" lang="en">
++<a name="id2543342"></a><h2>DESCRIPTION</h2>
++<p>
++      <span><strong class="command">pkcs11-tokens</strong></span>
++      lists the PKCS#11 available tokens with defaults from the slot/token
++      scan performed at application initialization.
++    </p>
++</div>
++<div class="refsect1" lang="en">
++<a name="id2543355"></a><h2>ARGUMENTS</h2>
++<div class="variablelist"><dl>
++<dt><span class="term">-m <em class="replaceable"><code>module</code></em></span></dt>
++<dd><p>
++            Specify the PKCS#11 provider module.  This must be the full
++            path to a shared library object implementing the PKCS#11 API
++            for the device.
++          </p></dd>
++</dl></div>
++</div>
++<div class="refsect1" lang="en">
++<a name="id2543382"></a><h2>AUTHOR</h2>
++<p><span class="corpauthor">Internet Systems Consortium</span>
++    </p>
++</div>
++</div></body>
++</html>
+diff --git a/bin/rndc/Makefile.in b/bin/rndc/Makefile.in
+index f6100df..bc0657a 100644
+--- a/bin/rndc/Makefile.in
++++ b/bin/rndc/Makefile.in
+@@ -45,7 +45,8 @@ BIND9DEPLIBS =	../../lib/bind9/libbind9.@A@
+ LIBS =		${ISCLIBS} @LIBS@
+ NOSYMLIBS =	${ISCNOSYMLIBS} @LIBS@
+ 
+-RNDCDEPLIBS =	${ISCCFGDEPLIBS} ${ISCCCDEPLIBS} ${BIND9DEPLIBS} ${DNSDEPLIBS} ${ISCDEPLIBS}
++RNDCDEPLIBS =	${ISCCFGDEPLIBS} ${ISCCCDEPLIBS} ${BIND9DEPLIBS} \
++		${DNSDEPLIBS} ${ISCDEPLIBS}
+ 
+ CONFDEPLIBS =	${DNSDEPLIBS} ${ISCDEPLIBS}
+ 
+diff --git a/bin/tests/Makefile.in b/bin/tests/Makefile.in
+index bc040a3..2020bf4 100644
+--- a/bin/tests/Makefile.in
++++ b/bin/tests/Makefile.in
+@@ -42,7 +42,7 @@ LWRESDEPLIBS =	../../lib/lwres/liblwres.@A@
+ LIBS =		@LIBS@
+ 
+ SUBDIRS =	atomic db dst master mem hashes names net rbt resolver \
+-		sockaddr tasks timers system
++		sockaddr tasks timers system @PKCS11_TOOLS@
+ 
+ # Test programs that are built by default:
+ # cfg_test is needed for regenerating doc/misc/options
+@@ -173,139 +173,139 @@ backtrace_test@EXEEXT@: backtrace_test_nosymtbl@EXEEXT@
+ nsecify@EXEEXT@: nsecify.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ nsecify.@O@ \
+ 		${DNSLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ byaddr_test@EXEEXT@: byaddr_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ byaddr_test.@O@ \
+ 		${DNSLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ byname_test@EXEEXT@: byname_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ byname_test.@O@ \
+ 		${DNSLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ lex_test@EXEEXT@: lex_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ lex_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ lfsr_test@EXEEXT@: lfsr_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ lfsr_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ log_test@EXEEXT@: log_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ log_test.@O@ \
+ 		${DNSLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ name_test@EXEEXT@: name_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ name_test.@O@ \
+ 		${DNSLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ hash_test@EXEEXT@: hash_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ hash_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ entropy_test@EXEEXT@: entropy_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ entropy_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ entropy2_test@EXEEXT@: entropy2_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ entropy2_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ sock_test@EXEEXT@: sock_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ sock_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ sym_test@EXEEXT@: sym_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ sym_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ task_test@EXEEXT@: task_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ task_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ shutdown_test@EXEEXT@: shutdown_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ shutdown_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ timer_test@EXEEXT@: timer_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ timer_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ ratelimiter_test@EXEEXT@: ratelimiter_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ratelimiter_test.@O@ \
+ 		${DNSLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ rbt_test@EXEEXT@: rbt_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ rbt_test.@O@ \
+ 		${DNSLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ rdata_test@EXEEXT@: rdata_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ rdata_test.@O@ \
+ 		${DNSLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ rwlock_test@EXEEXT@: rwlock_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ rwlock_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ wire_test@EXEEXT@: wire_test.@O@ printmsg.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ wire_test.@O@ printmsg.@O@ \
+ 		${DNSLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ master_test@EXEEXT@: master_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ master_test.@O@ \
+ 		${DNSLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ db_test@EXEEXT@: db_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ db_test.@O@ \
+ 		${DNSLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ compress_test@EXEEXT@: compress_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ compress_test.@O@ \
+ 		${DNSLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ mempool_test@EXEEXT@: mempool_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ mempool_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ serial_test@EXEEXT@: serial_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ serial_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ zone_test@EXEEXT@: zone_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ zone_test.@O@ \
+ 		${DNSLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ fsaccess_test@EXEEXT@: fsaccess_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ fsaccess_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ inter_test@EXEEXT@: inter_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ inter_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ keyboard_test@EXEEXT@: keyboard_test.@O@ ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ keyboard_test.@O@ \
+ 		${ISCLIBS} ${LIBS}
+-
++ 
+ lwresconf_test@EXEEXT@: lwresconf_test.@O@ ${ISCDEPLIBS} ${LWRESDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ lwresconf_test.@O@ \
+ 		${LWRESLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ lwres_test@EXEEXT@: lwres_test.@O@ ${ISCDEPLIBS} ${LWRESDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ lwres_test.@O@ \
+-		${LWRESLIBS} ${ISCLIBS} ${LIBS}
+-
+-gxbn_test@EXEEXT@: gxbn_test.@O@ ${LWRESDEPLIBS}
++		${LWRESLIBS} ${ISCLIBS}  ${LIBS}
++ 
++ gxbn_test@EXEEXT@: gxbn_test.@O@ ${LWRESDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ gxbn_test.@O@ \
+ 		${LWRESLIBS} ${ISCLIBS} ${LIBS}
+-
+-gxba_test@EXEEXT@: gxba_test.@O@ ${LWRESDEPLIBS}
++ 
++ gxba_test@EXEEXT@: gxba_test.@O@ ${LWRESDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ gxba_test.@O@ \
+ 		${LWRESLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ sig0_test@EXEEXT@: sig0_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ sig0_test.@O@ \
+ 		${DNSLIBS} ${ISCLIBS} ${LIBS}
+-
++ 
+ cfg_test@EXEEXT@: cfg_test.@O@ ${ISCCFGDEPLIBS} ${ISCDEPLIBS}
+ 	${LIBTOOL_MODE_LINK} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ cfg_test.@O@ \
+ 		${ISCCFGLIBS} ${DNSLIBS} ${ISCLIBS} ${LIBS}
+diff --git a/bin/tests/dst/dst_test.c b/bin/tests/dst/dst_test.c
+index bf305d8..240dc6f 100644
+--- a/bin/tests/dst/dst_test.c
++++ b/bin/tests/dst/dst_test.c
+@@ -30,6 +30,7 @@
+ #include <isc/string.h>		/* Required for HP/UX (and others?) */
+ 
+ #include <dns/fixedname.h>
++#include <dns/log.h>
+ #include <dns/name.h>
+ #include <dns/result.h>
+ 
+@@ -58,7 +59,8 @@ use(dst_key_t *key, isc_mem_t *mctx) {
+ 	isc_buffer_add(&databuf, strlen(data));
+ 	isc_buffer_usedregion(&databuf, &datareg);
+ 
+-	ret = dst_context_create(key, mctx, &ctx);
++	ret = dst_context_create3(key, mctx,
++				  DNS_LOGCATEGORY_GENERAL, ISC_TRUE, &ctx);
+ 	if (ret != ISC_R_SUCCESS) {
+ 		printf("contextcreate(%d) returned: %s\n", dst_key_alg(key),
+ 		       isc_result_totext(ret));
+@@ -78,7 +80,8 @@ use(dst_key_t *key, isc_mem_t *mctx) {
+ 
+ 	isc_buffer_forward(&sigbuf, 1);
+ 	isc_buffer_remainingregion(&sigbuf, &sigreg);
+-	ret = dst_context_create(key, mctx, &ctx);
++	ret = dst_context_create3(key, mctx,
++				  DNS_LOGCATEGORY_GENERAL, ISC_FALSE, &ctx);
+ 	if (ret != ISC_R_SUCCESS) {
+ 		printf("contextcreate(%d) returned: %s\n", dst_key_alg(key),
+ 		       isc_result_totext(ret));
+diff --git a/bin/tests/dst/t_dst.c b/bin/tests/dst/t_dst.c
+index e431c95..59c7835 100644
+--- a/bin/tests/dst/t_dst.c
++++ b/bin/tests/dst/t_dst.c
+@@ -108,7 +108,8 @@ use(dst_key_t *key, isc_mem_t *mctx, isc_result_t exp_result, int *nfails) {
+ 	isc_buffer_add(&databuf, strlen(data));
+ 	isc_buffer_usedregion(&databuf, &datareg);
+ 
+-	ret = dst_context_create(key, mctx, &ctx);
++	ret = dst_context_create3(key, mctx,
++				  DNS_LOGCATEGORY_GENERAL, ISC_TRUE, &ctx);
+ 	if (ret != exp_result) {
+ 		t_info("dst_context_create(%d) returned (%s) expected (%s)\n",
+ 		       dst_key_alg(key), dst_result_totext(ret),
+@@ -137,7 +138,8 @@ use(dst_key_t *key, isc_mem_t *mctx, isc_result_t exp_result, int *nfails) {
+ 	dst_context_destroy(&ctx);
+ 
+ 	isc_buffer_remainingregion(&sigbuf, &sigreg);
+-	ret = dst_context_create(key, mctx, &ctx);
++	ret = dst_context_create3(key, mctx,
++				  DNS_LOGCATEGORY_GENERAL, ISC_FALSE, &ctx);
+ 	if (ret != ISC_R_SUCCESS) {
+ 		t_info("dst_context_create(%d) returned (%s)\n",
+ 		       dst_key_alg(key), dst_result_totext(ret));
+@@ -783,7 +785,9 @@ t2_sigchk(char *datapath, char *sigpath, char *keyname,
+ 	memset(sig, 0, sizeof(sig));
+ 	isc_buffer_init(&sigbuf, sig, sizeof(sig));
+ 
+-	isc_result = dst_context_create(key, mctx, &ctx);
++	isc_result = dst_context_create3(key, mctx,
++					 DNS_LOGCATEGORY_GENERAL,
++					 ISC_TRUE, &ctx);
+ 	if (isc_result != ISC_R_SUCCESS) {
+ 		t_info("dst_context_create(%d) failed %s\n",
+ 		       dst_result_totext(isc_result));
+@@ -849,7 +853,9 @@ t2_sigchk(char *datapath, char *sigpath, char *keyname,
+ 	if (strstr(expected_result, "!"))
+ 		exp_res = 1;
+ 
+-	isc_result = dst_context_create(key, mctx, &ctx);
++	isc_result = dst_context_create3(key, mctx,
++					 DNS_LOGCATEGORY_GENERAL,
++					 ISC_FALSE, &ctx);
+ 	if (isc_result != ISC_R_SUCCESS) {
+ 		t_info("dst_context_create returned %s\n",
+ 			isc_result_totext(isc_result));
+diff --git a/bin/tests/pkcs11/Makefile.in b/bin/tests/pkcs11/Makefile.in
+new file mode 100644
+index 0000000..0a6281f
+--- /dev/null
++++ b/bin/tests/pkcs11/Makefile.in
+@@ -0,0 +1,49 @@
++# Copyright (C) 2009, 2012  Internet Systems Consortium, Inc. ("ISC")
++#
++# Permission to use, copy, modify, and/or distribute this software for any
++# purpose with or without fee is hereby granted, provided that the above
++# copyright notice and this permission notice appear in all copies.
++#
++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++# PERFORMANCE OF THIS SOFTWARE.
++
++srcdir =	@srcdir@
++VPATH =		@srcdir@
++top_srcdir =	@top_srcdir@
++
++@BIND9_MAKE_INCLUDES@
++
++PROVIDER =	@PKCS11_PROVIDER@
++
++CINCLUDES =	${ISC_INCLUDES}
++
++CDEFINES =	-DPK11_LIB_LOCATION=\"${PROVIDER}\"
++
++ISCLIBS =	../../../lib/isc/libisc.@A@
++
++LIBS =		${ISCLIBS} @LIBS@
++
++SUBDIRS =	benchmarks
++
++TARGETS =	pkcs11-md5sum@EXEEXT@ pkcs11-hmacmd5@EXEEXT@
++SRCS =		pkcs11-md5sum.c pkcs11-hmacmd5.c
++
++@BIND9_MAKE_RULES@
++
++pkcs11-md5sum@EXEEXT@: @srcdir@/pkcs11-md5sum.c
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \
++	-o $@ @srcdir@/pkcs11-md5sum.c ${LIBS}
++
++pkcs11-hmacmd5@EXEEXT@: @srcdir@/pkcs11-hmacmd5.c
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \
++	-o $@ @srcdir@/pkcs11-hmacmd5.c ${LIBS}
++
++test:
++
++clean distclean::
++	rm -f ${TARGETS}
+diff --git a/bin/tests/pkcs11/benchmarks/Makefile.in b/bin/tests/pkcs11/benchmarks/Makefile.in
+new file mode 100644
+index 0000000..cd0347c
+--- /dev/null
++++ b/bin/tests/pkcs11/benchmarks/Makefile.in
+@@ -0,0 +1,79 @@
++# Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++#
++# Permission to use, copy, modify, and/or distribute this software for any
++# purpose with or without fee is hereby granted, provided that the above
++# copyright notice and this permission notice appear in all copies.
++#
++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++# PERFORMANCE OF THIS SOFTWARE.
++
++# $Id$
++
++srcdir =	@srcdir@
++VPATH =		@srcdir@
++top_srcdir =	@top_srcdir@
++
++@BIND9_MAKE_INCLUDES@
++
++PROVIDER =	@PKCS11_PROVIDER@
++
++CINCLUDES =	${ISC_INCLUDES}
++
++CDEFINES =	-DPK11_LIB_LOCATION=\"${PROVIDER}\"
++
++ISCLIBS =	../../../../lib/isc/libisc.@A@
++
++LIBS =		${ISCLIBS} @LIBS@
++
++SUBDIRS =
++
++TARGETS =	session@EXEEXT@ login@EXEEXT@ random@EXEEXT@ \
++		sha1@EXEEXT@ create@EXEEXT@ find@EXEEXT@ \
++		pubrsa@EXEEXT@ privrsa@EXEEXT@ genrsa@EXEEXT@ \
++		sign@EXEEXT@ verify@EXEEXT@
++
++SRCS =		session.c login.c random.c sha1.c create.c find.c \
++		pubrsa.c privrsa.c genrsa.c sign.c verify.c
++
++@BIND9_MAKE_RULES@
++
++session@EXEEXT@: @srcdir@/session.c
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/session.c ${LIBS}
++
++login@EXEEXT@: @srcdir@/login.c
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/login.c ${LIBS}
++
++random@EXEEXT@: @srcdir@/random.c
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/random.c ${LIBS}
++
++sha1@EXEEXT@: @srcdir@/sha1.c
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/sha1.c ${LIBS}
++
++create@EXEEXT@: @srcdir@/create.c
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/create.c ${LIBS}
++
++find@EXEEXT@: @srcdir@/find.c
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/find.c ${LIBS}
++
++pubrsa@EXEEXT@: @srcdir@/pubrsa.c
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/pubrsa.c ${LIBS}
++
++privrsa@EXEEXT@: @srcdir@/privrsa.c
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/privrsa.c ${LIBS}
++
++genrsa@EXEEXT@: @srcdir@/genrsa.c
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/genrsa.c ${LIBS}
++
++sign@EXEEXT@: @srcdir@/sign.c
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/sign.c ${LIBS}
++
++verify@EXEEXT@: @srcdir@/verify.c
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/verify.c ${LIBS}
++
++clean distclean::
++	rm -f ${TARGETS}
+diff --git a/bin/tests/pkcs11/benchmarks/create.c b/bin/tests/pkcs11/benchmarks/create.c
+new file mode 100644
+index 0000000..d0d8c77
+--- /dev/null
++++ b/bin/tests/pkcs11/benchmarks/create.c
+@@ -0,0 +1,260 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* $Id$ */
++
++/* create [-m module] [-s $slot] [-p pin] [-t] [-n count] */
++
++/*! \file */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++#include <unistd.h>
++
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/result.h>
++
++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
++#define getpassphrase(x)	getpass(x)
++#endif
++
++#ifndef HAVE_CLOCK_GETTIME
++#ifndef CLOCK_REALTIME
++#define CLOCK_REALTIME 0
++#endif
++
++int
++clock_gettime(int32_t id, struct timespec *tp)
++{
++	struct timeval tv;
++	int result;
++
++	result = gettimeofday(&tv, NULL);
++	if (result)
++		return (result);
++	tp->tv_sec = tv.tv_sec;
++	tp->tv_nsec = (long) tv.tv_usec * 1000;
++	return (result);
++}
++#endif
++
++CK_BYTE buf[1024];
++char label[16];
++
++static CK_BBOOL truevalue = TRUE;
++static CK_BBOOL falsevalue = FALSE;
++
++int
++main(int argc, char *argv[]) {
++	isc_result_t result;
++	CK_RV rv;
++	CK_SLOT_ID slot = 0;
++	CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
++	CK_OBJECT_HANDLE *hKey;
++	CK_OBJECT_CLASS kClass = CKO_DATA;
++	CK_ULONG len = sizeof(buf);
++	CK_ATTRIBUTE kTemplate[] =
++	{
++		{ CKA_CLASS, &kClass, (CK_ULONG) sizeof(kClass) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_LABEL, (CK_BYTE_PTR) label, (CK_ULONG) sizeof(label) },
++		{ CKA_VALUE, buf, (CK_ULONG) sizeof(buf) }
++	};
++	pk11_context_t pctx;
++	char *lib_name = NULL;
++	char *pin = NULL;
++	int error = 0;
++	int c, errflg = 0;
++	int ontoken  = 0;
++	unsigned int count = 1000;
++	unsigned int i;
++	struct timespec starttime;
++	struct timespec endtime;
++
++	while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) {
++		switch (c) {
++		case 'm':
++			lib_name = isc_commandline_argument;
++			break;
++		case 's':
++			slot = atoi(isc_commandline_argument);
++			break;
++		case 't':
++			ontoken = 1;
++			break;
++		case 'p':
++			pin = isc_commandline_argument;
++			break;
++		case 'n':
++			count = atoi(isc_commandline_argument);
++			break;
++		case ':':
++			fprintf(stderr,
++				"Option -%c requires an operand\n",
++				isc_commandline_option);
++			errflg++;
++			break;
++		case '?':
++		default:
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
++			errflg++;
++		}
++	}
++
++	if (errflg) {
++		fprintf(stderr, "Usage:\n");
++		fprintf(stderr,
++			"\tcreate [-m module] [-s slot] [-t] [-n count]\n");
++		exit(1);
++	}
++
++	pk11_result_register();
++
++	/* Allocate hanles */
++	hKey = (CK_SESSION_HANDLE *)
++		malloc(count * sizeof(CK_SESSION_HANDLE));
++	if (hKey == NULL) {
++		perror("malloc");
++		exit(1);
++	}
++	for (i = 0; i < count; i++)
++		hKey[i] = CK_INVALID_HANDLE;
++
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
++
++	if (pin == NULL)
++		pin = getpassphrase("Enter Pin: ");
++
++	result = pk11_get_session(&pctx, OP_ANY, ISC_TRUE, ISC_TRUE,
++				  ISC_TRUE, (const char *) pin, slot);
++	if ((result != ISC_R_SUCCESS) &&
++	    (result != PK11_R_NORANDOMSERVICE) &&
++	    (result != PK11_R_NODIGESTSERVICE) &&
++	    (result != PK11_R_NOAESSERVICE)) {
++		fprintf(stderr, "Error initializing PKCS#11: %s\n",
++			isc_result_totext(result));
++		exit(1);
++	}
++
++	if (pin != NULL)
++		memset(pin, 0, strlen((char *)pin));
++
++	hSession = pctx.session;
++
++	/* Randomize the buffer */
++	rv = pkcs_C_GenerateRandom(hSession, buf, len);
++	if (rv != CKR_OK) {
++		fprintf(stderr, "C_GenerateRandom: Error = 0x%.8lX\n", rv);
++		goto exit_objects;
++	}
++
++	if (ontoken)
++		kTemplate[1].pValue = &truevalue;
++
++	if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) {
++		perror("clock_gettime(start)");
++		goto exit_objects;
++	}
++
++	for (i = 0; i < count; i++) {
++		(void) snprintf(label, sizeof(label), "obj%u", i);
++		kTemplate[3].ulValueLen = strlen(label);
++		rv = pkcs_C_CreateObject(hSession, kTemplate, 5, &hKey[i]);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_CreateObject[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			if (i == 0)
++				goto exit_objects;
++			break;
++		}
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) {
++		perror("clock_gettime(end)");
++		goto exit_objects;
++	}
++
++	endtime.tv_sec -= starttime.tv_sec;
++	endtime.tv_nsec -= starttime.tv_nsec;
++	while (endtime.tv_nsec < 0) {
++		endtime.tv_sec -= 1;
++		endtime.tv_nsec += 1000000000;
++	}
++	printf("%u created objects in %ld.%09lds\n", i,
++	       endtime.tv_sec, endtime.tv_nsec);
++	if (i > 0)
++		printf("%g created objects/s\n",
++		       1024 * i / ((double) endtime.tv_sec +
++				   (double) endtime.tv_nsec / 1000000000.));
++
++    exit_objects:
++	for (i = 0; i < count; i++) {
++		/* Destroy objects */
++		if (hKey[i] == CK_INVALID_HANDLE)
++			continue;
++		rv = pkcs_C_DestroyObject(hSession, hKey[i]);
++		if ((rv != CKR_OK) && !errflg) {
++			fprintf(stderr,
++				"C_DestroyObject[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			errflg = 1;
++		}
++	}
++
++	free(hKey);
++	pk11_return_session(&pctx);
++	(void) pk11_finalize();
++
++	exit(error);
++}
+diff --git a/bin/tests/pkcs11/benchmarks/find.c b/bin/tests/pkcs11/benchmarks/find.c
+new file mode 100644
+index 0000000..e22b17e
+--- /dev/null
++++ b/bin/tests/pkcs11/benchmarks/find.c
+@@ -0,0 +1,227 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* find [-m module] [-s $slot] [-p pin] [-n count] */
++
++/*! \file */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++#include <unistd.h>
++
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/result.h>
++
++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
++#define getpassphrase(x)	getpass(x)
++#endif
++
++#ifndef HAVE_CLOCK_GETTIME
++#ifndef CLOCK_REALTIME
++#define CLOCK_REALTIME 0
++#endif
++
++int
++clock_gettime(int32_t id, struct timespec *tp)
++{
++	struct timeval tv;
++	int result;
++
++	result = gettimeofday(&tv, NULL);
++	if (result)
++		return (result);
++	tp->tv_sec = tv.tv_sec;
++	tp->tv_nsec = (long) tv.tv_usec * 1000;
++	return (result);
++}
++#endif
++
++CK_BYTE label[] = "foo??bar!!";
++
++int
++main(int argc, char *argv[]) {
++	isc_result_t result;
++	CK_RV rv;
++	CK_SLOT_ID slot = 0;
++	CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
++	CK_ATTRIBUTE sTemplate[] =
++	{
++		{ CKA_LABEL, label, (CK_ULONG) sizeof(label) },
++	};
++	CK_OBJECT_HANDLE sKey = CK_INVALID_HANDLE;
++	CK_ULONG found = 0;
++	pk11_context_t pctx;
++	pk11_optype_t op_type = OP_RSA;
++	char *lib_name = NULL;
++	char *pin = NULL;
++	int error = 0;
++	int c, errflg = 0;
++	unsigned int count = 1000;
++	unsigned int i;
++	struct timespec starttime;
++	struct timespec endtime;
++
++	while ((c = isc_commandline_parse(argc, argv, ":m:s:p:n:")) != -1) {
++		switch (c) {
++		case 'm':
++			lib_name = isc_commandline_argument;
++			break;
++		case 's':
++			op_type = OP_ANY;
++			slot = atoi(isc_commandline_argument);
++			break;
++		case 'p':
++			pin = isc_commandline_argument;
++			break;
++		case 'n':
++			count = atoi(isc_commandline_argument);
++			break;
++		case ':':
++			fprintf(stderr,
++				"Option -%c requires an operand\n",
++				isc_commandline_option);
++			errflg++;
++			break;
++		case '?':
++		default:
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
++			errflg++;
++		}
++	}
++
++	if (errflg) {
++		fprintf(stderr, "Usage:\n");
++		fprintf(stderr,
++			"\tfind [-m module] [-s slot] [-p pin] [-n count]\n");
++		exit(1);
++	}
++
++	pk11_result_register();
++
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
++
++	if (pin == NULL)
++		pin = getpassphrase("Enter Pin: ");
++
++	result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_FALSE,
++				  ISC_TRUE, (const char *) pin, slot);
++	if ((result != ISC_R_SUCCESS) &&
++	    (result != PK11_R_NORANDOMSERVICE) &&
++	    (result != PK11_R_NODIGESTSERVICE) &&
++	    (result != PK11_R_NOAESSERVICE)) {
++		fprintf(stderr, "Error initializing PKCS#11: %s\n",
++			isc_result_totext(result));
++		exit(1);
++	}
++
++	if (pin != NULL)
++		memset(pin, 0, strlen((char *)pin));
++
++	hSession = pctx.session;
++
++	if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) {
++		perror("clock_gettime(start)");
++		goto exit_objects;
++	}
++
++	for (i = 0; !error && (i < count); i++) {
++		rv = pkcs_C_FindObjectsInit(hSession, sTemplate, 1);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_FindObjectsInit[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			break;
++		}
++
++		rv = pkcs_C_FindObjects(hSession, &sKey, 1, &found);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_FindObjects[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			/* no break here! */
++		}
++
++		rv = pkcs_C_FindObjectsFinal(hSession);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_FindObjectsFinal[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			break;
++		}
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) {
++		perror("clock_gettime(end)");
++		goto exit_objects;
++	}
++
++	endtime.tv_sec -= starttime.tv_sec;
++	endtime.tv_nsec -= starttime.tv_nsec;
++	while (endtime.tv_nsec < 0) {
++		endtime.tv_sec -= 1;
++		endtime.tv_nsec += 1000000000;
++	}
++	printf("%u object searches in %ld.%09lds\n", i,
++	       endtime.tv_sec, endtime.tv_nsec);
++	if (i > 0)
++		printf("%g object searches/s\n",
++		       1024 * i / ((double) endtime.tv_sec +
++				   (double) endtime.tv_nsec / 1000000000.));
++
++    exit_objects:
++	pk11_return_session(&pctx);
++	(void) pk11_finalize();
++		
++	exit(error);
++}
+diff --git a/bin/tests/pkcs11/benchmarks/genrsa.c b/bin/tests/pkcs11/benchmarks/genrsa.c
+new file mode 100644
+index 0000000..e9d3c2a
+--- /dev/null
++++ b/bin/tests/pkcs11/benchmarks/genrsa.c
+@@ -0,0 +1,295 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* $Id$ */
++
++/* genrsa [-m module] [-s $slot] [-p pin] [-t] [-b bits] [-n count] */
++
++/*! \file */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++#include <unistd.h>
++
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/result.h>
++
++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
++#define getpassphrase(x)	getpass(x)
++#endif
++
++#ifndef HAVE_CLOCK_GETTIME
++#ifndef CLOCK_REALTIME
++#define CLOCK_REALTIME 0
++#endif
++
++int
++clock_gettime(int32_t id, struct timespec *tp)
++{
++	struct timeval tv;
++	int result;
++
++	result = gettimeofday(&tv, NULL);
++	if (result)
++		return (result);
++	tp->tv_sec = tv.tv_sec;
++	tp->tv_nsec = (long) tv.tv_usec * 1000;
++	return (result);
++}
++#endif
++
++static CK_BBOOL truevalue = TRUE;
++static CK_BBOOL falsevalue = FALSE;
++
++int
++main(int argc, char *argv[]) {
++	isc_result_t result;
++	CK_RV rv;
++	CK_SLOT_ID slot = 0;
++	CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
++	CK_MECHANISM mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0 };
++	CK_OBJECT_HANDLE *pubKey;
++	CK_OBJECT_HANDLE *privKey;
++	CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY;
++	CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY;
++	CK_KEY_TYPE kType = CKK_RSA;
++	CK_ULONG bits = 1024;
++	CK_BYTE exponent[] = { 0x01, 0x00, 0x01 };
++	CK_ATTRIBUTE pubTemplate[] =
++	{
++		{ CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) },
++		{ CKA_KEY_TYPE, &kType, (CK_ULONG) sizeof(kType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_MODULUS_BITS, &bits, (CK_ULONG) sizeof(bits) },
++		{ CKA_PUBLIC_EXPONENT, exponent, (CK_ULONG) sizeof(exponent) }
++	};
++	CK_ATTRIBUTE privTemplate[] =
++	{
++		{ CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) },
++		{ CKA_KEY_TYPE, &kType, (CK_ULONG) sizeof(kType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++	};
++	pk11_context_t pctx;
++	pk11_optype_t op_type = OP_RSA;
++	char *lib_name = NULL;
++	char *pin = NULL;
++	int error = 0;
++	int c, errflg = 0;
++	int ontoken  = 0;
++	unsigned int count = 1000;
++	unsigned int i;
++	struct timespec starttime;
++	struct timespec endtime;
++
++	while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tb:n:")) != -1) {
++		switch (c) {
++		case 'm':
++			lib_name = isc_commandline_argument;
++			break;
++		case 's':
++			op_type = OP_ANY;
++			slot = atoi(isc_commandline_argument);
++			break;
++		case 'p':
++			pin = isc_commandline_argument;
++			break;
++		case 't':
++			ontoken = 1;
++			break;
++		case 'b':
++			bits = (CK_ULONG)atoi(isc_commandline_argument);
++			break;
++		case 'n':
++			count = atoi(isc_commandline_argument);
++			break;
++		case ':':
++			fprintf(stderr,
++				"Option -%c requires an operand\n",
++				isc_commandline_option);
++			errflg++;
++			break;
++		case '?':
++		default:
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
++			errflg++;
++		}
++	}
++
++	if (errflg) {
++		fprintf(stderr, "Usage:\n");
++		fprintf(stderr,
++			"\tgenrsa [-m module] [-s slot] [-p pin] "
++			"[-t] [-b bits] [-n count]\n");
++		exit(1);
++	}
++
++	pk11_result_register();
++
++	/* Allocate hanles */
++	pubKey = (CK_SESSION_HANDLE *)
++		malloc(count * sizeof(CK_SESSION_HANDLE));
++	if (pubKey == NULL) {
++		perror("malloc");
++		exit(1);
++	}
++	privKey = (CK_SESSION_HANDLE *)
++		malloc(count * sizeof(CK_SESSION_HANDLE));
++	if (privKey == NULL) {
++		free(pubKey);
++		perror("malloc");
++		exit(1);
++	}
++	for (i = 0; i < count; i++) {
++		pubKey[i] = CK_INVALID_HANDLE;
++		privKey[i] = CK_INVALID_HANDLE;
++	}
++
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
++
++	if (pin == NULL)
++		pin = getpassphrase("Enter Pin: ");
++
++	result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_TRUE,
++				  ISC_TRUE, (const char *) pin, slot);
++	if ((result != ISC_R_SUCCESS) &&
++	    (result != PK11_R_NORANDOMSERVICE) &&
++	    (result != PK11_R_NODIGESTSERVICE) &&
++	    (result != PK11_R_NOAESSERVICE)) {
++		fprintf(stderr, "Error initializing PKCS#11: %s\n",
++			isc_result_totext(result));
++		exit(1);
++	}
++
++	if (pin != NULL)
++		memset(pin, 0, strlen((char *)pin));
++
++	hSession = pctx.session;
++
++	if (ontoken) {
++		pubTemplate[2].pValue = &truevalue;
++		privTemplate[2].pValue = &truevalue;
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) {
++		perror("clock_gettime(start)");
++		goto exit_keys;
++	}
++
++	for (i = 0; i < count; i++) {
++		rv = pkcs_C_GenerateKeyPair(hSession, &mech,
++				       pubTemplate, 7,
++				       privTemplate, 5,
++				       &pubKey[i], &privKey[i]);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_GenerateKeyPair[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			if (i == 0)
++				goto exit_keys;
++			break;
++		}
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) {
++		perror("clock_gettime(end)");
++		goto exit_keys;
++	}
++
++	endtime.tv_sec -= starttime.tv_sec;
++	endtime.tv_nsec -= starttime.tv_nsec;
++	while (endtime.tv_nsec < 0) {
++		endtime.tv_sec -= 1;
++		endtime.tv_nsec += 1000000000;
++	}
++	printf("%u generated RSA in %ld.%09lds\n", i,
++	       endtime.tv_sec, endtime.tv_nsec);
++	if (i > 0)
++		printf("%g generated RSA/s\n",
++		       1024 * i / ((double) endtime.tv_sec +
++				   (double) endtime.tv_nsec / 1000000000.));
++
++    exit_keys:
++	for (i = 0; i < count; i++) {
++		/* Destroy keys */
++		if (pubKey[i] == CK_INVALID_HANDLE)
++			goto destroy_priv;
++		rv = pkcs_C_DestroyObject(hSession, pubKey[i]);
++		if ((rv != CKR_OK) && !errflg) {
++			fprintf(stderr,
++				"C_DestroyObject[pub%u]: Error = 0x%.8lX\n",
++				i, rv);
++			errflg = 1;
++		}
++	    destroy_priv:
++		if (privKey[i] == CK_INVALID_HANDLE)
++			continue;
++		rv = pkcs_C_DestroyObject(hSession, privKey[i]);
++		if ((rv != CKR_OK) && !errflg) {
++			fprintf(stderr,
++				"C_DestroyObject[priv%u]: Error = 0x%.8lX\n",
++				i, rv);
++			errflg = 1;
++		}
++	}
++
++	free(pubKey);
++	free(privKey);
++
++	pk11_return_session(&pctx);
++	(void) pk11_finalize();
++		
++	exit(error);
++}
+diff --git a/bin/tests/pkcs11/benchmarks/login.c b/bin/tests/pkcs11/benchmarks/login.c
+new file mode 100644
+index 0000000..fe597fa
+--- /dev/null
++++ b/bin/tests/pkcs11/benchmarks/login.c
+@@ -0,0 +1,249 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* $Id$ */
++
++/* login [-m module] [-s $slot] [-p pin] [-n count] */
++
++/*! \file */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++#include <unistd.h>
++
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/internal.h>
++
++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
++#define getpassphrase(x)	getpass(x)
++#endif
++
++#ifndef HAVE_CLOCK_GETTIME
++#ifndef CLOCK_REALTIME
++#define CLOCK_REALTIME 0
++#endif
++
++int
++clock_gettime(int32_t id, struct timespec *tp)
++{
++	struct timeval tv;
++	int result;
++
++	result = gettimeofday(&tv, NULL);
++	if (result)
++		return (result);
++	tp->tv_sec = tv.tv_sec;
++	tp->tv_nsec = (long) tv.tv_usec * 1000;
++	return (result);
++}
++#endif
++
++int
++main(int argc, char *argv[]) {
++	CK_RV rv;
++	CK_SLOT_ID slot = 0;
++	CK_SESSION_HANDLE *hSession;
++	CK_UTF8CHAR *pin = NULL;
++	char *lib_name = NULL;
++	int error = 0;
++	int c, errflg = 0;
++	unsigned int count = 1000;
++	unsigned int i, j;
++	struct timespec starttime;
++	struct timespec endtime;
++
++	while ((c = isc_commandline_parse(argc, argv, ":m:s:p:n:")) != -1) {
++		switch (c) {
++		case 'm':
++			lib_name = isc_commandline_argument;
++			break;
++		case 's':
++			slot = atoi(isc_commandline_argument);
++			break;
++		case 'p':
++			pin = (CK_UTF8CHAR *)isc_commandline_argument;
++			break;
++		case 'n':
++			count = atoi(isc_commandline_argument);
++			break;
++		case ':':
++			fprintf(stderr,
++				"Option -%c requires an operand\n",
++				isc_commandline_option);
++			errflg++;
++			break;
++		case '?':
++		default:
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
++			errflg++;
++		}
++	}
++
++	if (errflg) {
++		fprintf(stderr, "Usage:\n");
++		fprintf(stderr,
++			"\tlogin [-m module] [-s slot] [-p pin] [-n count]\n");
++		exit(1);
++	}
++
++	/* allocate sessions */
++	hSession = (CK_SESSION_HANDLE *)
++		malloc(count * sizeof(CK_SESSION_HANDLE));
++	if (hSession == NULL) {
++		perror("malloc");
++		exit(1);
++	}
++	for (i = 0; i < count; i++)
++		hSession[i] = CK_INVALID_HANDLE;
++
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
++
++	if (pin == NULL)
++		pin = (CK_UTF8CHAR *)getpassphrase("Enter Pin: ");
++
++	rv = pkcs_C_Initialize(NULL_PTR);
++	if (rv != CKR_OK) {
++		if (rv == 0xfe)
++			fprintf(stderr,
++				"Can't load or link module \"%s\"\n",
++				pk11_get_lib_name());
++		else
++			fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv);
++		free(hSession);
++		exit(1);
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) {
++		perror("clock_gettime(start)");
++		goto exit_program;
++	}
++
++	/* loop */
++	for (i = 0; i < count; i++) {
++		/* Open sessions */
++		rv = pkcs_C_OpenSession(slot, CKF_SERIAL_SESSION,
++					NULL_PTR, NULL_PTR, &hSession[i]);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_OpenSession[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			if (i == 0)
++				goto exit_program;
++			break;
++		}
++
++		/* Logon */
++		rv = pkcs_C_Login(hSession[i], CKU_USER,
++				  pin, strlen((char *)pin));
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_Login[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			if (i == 0)
++				goto exit_program;
++			break;
++		}
++
++		/* Logoff */
++		rv = pkcs_C_Logout(hSession[i]);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_Logout[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			if (i == 0)
++				goto exit_program;
++			break;
++		}
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) {
++		perror("clock_gettime(end)");
++		goto exit_program;
++	}
++
++	endtime.tv_sec -= starttime.tv_sec;
++	endtime.tv_nsec -= starttime.tv_nsec;
++	while (endtime.tv_nsec < 0) {
++		endtime.tv_sec -= 1;
++		endtime.tv_nsec += 1000000000;
++	}
++	printf("%u logins in %ld.%09lds\n", i,
++	       endtime.tv_sec, endtime.tv_nsec);
++	if (i > 0)
++		printf("%g logins/s\n",
++		       i / ((double) endtime.tv_sec +
++			    (double) endtime.tv_nsec / 1000000000.));
++
++	for (j = 0; j < i; j++) {
++		if (hSession[j] == CK_INVALID_HANDLE)
++			continue;
++		/* Close sessions */
++		rv = pkcs_C_CloseSession(hSession[j]);
++		if ((rv != CKR_OK) && !errflg) {
++			fprintf(stderr,
++				"C_CloseSession[%u]: Error = 0x%.8lX\n",
++				j, rv);
++			errflg = 1;
++		}
++	}
++
++    exit_program:
++	free(hSession);
++
++	rv = pkcs_C_Finalize(NULL_PTR);
++	if (rv != CKR_OK)
++		fprintf(stderr, "C_Finalize: Error = 0x%.8lX\n", rv);
++		
++	exit(error);
++}
+diff --git a/bin/tests/pkcs11/benchmarks/privrsa.c b/bin/tests/pkcs11/benchmarks/privrsa.c
+new file mode 100644
+index 0000000..c50d8d2
+--- /dev/null
++++ b/bin/tests/pkcs11/benchmarks/privrsa.c
+@@ -0,0 +1,360 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* $Id$ */
++
++/* privrsa [-m module] [-s $slot] [-p pin] [-t] [-n count] */
++
++/*! \file */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++#include <unistd.h>
++
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/result.h>
++
++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
++#define getpassphrase(x)	getpass(x)
++#endif
++
++#ifndef HAVE_CLOCK_GETTIME
++#ifndef CLOCK_REALTIME
++#define CLOCK_REALTIME 0
++#endif
++
++int
++clock_gettime(int32_t id, struct timespec *tp)
++{
++	struct timeval tv;
++	int result;
++
++	result = gettimeofday(&tv, NULL);
++	if (result)
++		return (result);
++	tp->tv_sec = tv.tv_sec;
++	tp->tv_nsec = (long) tv.tv_usec * 1000;
++	return (result);
++}
++#endif
++
++CK_BYTE modulus[] = {
++	0x00, 0xb7, 0x9c, 0x1f, 0x05, 0xa3, 0xc2, 0x99,
++	0x44, 0x82, 0x20, 0x78, 0x43, 0x7f, 0x5f, 0x3b,
++	0x10, 0xd7, 0x9e, 0x61, 0x42, 0xd2, 0x7a, 0x90,
++	0x50, 0x8a, 0x99, 0x33, 0xe7, 0xca, 0xc8, 0x5f,
++	0x16, 0x1c, 0x56, 0xf8, 0xc1, 0x06, 0x2f, 0x96,
++	0xe7, 0x54, 0xf2, 0x85, 0x89, 0x41, 0x36, 0xf5,
++	0x4c, 0xa4, 0x0d, 0x62, 0xd3, 0x42, 0x51, 0x6b,
++	0x9f, 0xdc, 0x36, 0xcb, 0xad, 0x56, 0xf4, 0xbd,
++	0x2a, 0x60, 0x33, 0xb1, 0x7a, 0x99, 0xad, 0x08,
++	0x9f, 0x95, 0xe8, 0xe5, 0x14, 0xd9, 0x68, 0x79,
++	0xca, 0x4e, 0x72, 0xeb, 0xfb, 0x2c, 0xf1, 0x45,
++	0xd3, 0x33, 0x65, 0xe7, 0xc5, 0x11, 0xdd, 0xe7,
++	0x09, 0x83, 0x13, 0xd5, 0x17, 0x1b, 0xf4, 0xbd,
++	0x49, 0xdd, 0x8a, 0x3c, 0x3c, 0xf7, 0xa1, 0x5d,
++	0x7b, 0xb4, 0xd3, 0x80, 0x25, 0xf4, 0x05, 0x8f,
++	0xbc, 0x2c, 0x2a, 0x47, 0xff, 0xd1, 0xc8, 0x34,
++	0xbf
++};
++CK_BYTE pubexp[] = { 0x01, 0x00, 0x01 };
++CK_BYTE privexp[] = {
++	0x00, 0xae, 0x02, 0xf1, 0x47, 0xa8, 0x07, 0x02,
++	0xb8, 0xf1, 0xd6, 0x92, 0x03, 0xee, 0x50, 0x33,
++	0xab, 0x67, 0x9e, 0x3b, 0xb1, 0x57, 0xc7, 0x3e,
++	0xc4, 0x86, 0x46, 0x61, 0xf1, 0xf8, 0xb6, 0x63,
++	0x9f, 0x91, 0xe6, 0x3f, 0x44, 0xb8, 0x77, 0x1b,
++	0xbe, 0x4c, 0x3c, 0xb8, 0x9f, 0xf7, 0x45, 0x7d,
++	0xbf, 0x4f, 0xef, 0x3b, 0xcc, 0xda, 0x1a, 0x4e,
++	0x34, 0xa8, 0x40, 0xea, 0x51, 0x72, 0x8a, 0xea,
++	0x47, 0x06, 0x04, 0xd0, 0x62, 0x31, 0xa0, 0x6c,
++	0x09, 0x60, 0xf9, 0xc7, 0x95, 0x88, 0x4a, 0xd7,
++	0x19, 0xce, 0x89, 0x08, 0x87, 0x14, 0xef, 0xcc,
++	0x0a, 0xef, 0x72, 0xb9, 0x21, 0xf5, 0xf0, 0xcd,
++	0x6d, 0xe5, 0xfa, 0x15, 0x7f, 0xae, 0x33, 0x9f,
++	0x26, 0xac, 0x2e, 0x52, 0x02, 0x07, 0xfb, 0x1d,
++	0x4b, 0xec, 0x9a, 0x6b, 0x3b, 0x26, 0x1f, 0x52,
++	0xfc, 0x47, 0xf8, 0x66, 0x33, 0xfa, 0x50, 0x6c,
++	0x41
++};
++CK_BYTE prime1[] = {
++	0x00, 0xe8, 0x98, 0xeb, 0xa1, 0xf0, 0xce, 0xde,
++	0xc2, 0x74, 0x01, 0x18, 0x2b, 0xd3, 0x8f, 0x58,
++	0xcd, 0xe9, 0x8e, 0x97, 0xbe, 0xfe, 0xe8, 0x6f,
++	0xd6, 0x0c, 0x0a, 0x47, 0xf8, 0x56, 0x84, 0x36,
++	0x15, 0xe6, 0x75, 0x1c, 0x69, 0x48, 0x8b, 0xf5,
++	0x0f, 0x84, 0xd2, 0x60, 0x8b, 0xa2, 0x2a, 0xa1,
++	0xeb, 0xed, 0xbe, 0x2d, 0xe9, 0x41, 0x0b, 0xed,
++	0x17, 0x7c, 0xd3, 0xa6, 0x35, 0x6e, 0xa6, 0xd8,
++	0x21
++};
++CK_BYTE prime2[] = {
++	0x00, 0xca, 0x15, 0x6a, 0x43, 0x5e, 0x83, 0xc9,
++	0x09, 0xeb, 0x14, 0x1e, 0x46, 0x46, 0x97, 0xfa,
++	0xfa, 0x3c, 0x61, 0x7e, 0xc1, 0xf8, 0x8c, 0x5e,
++	0xcb, 0xbf, 0xe4, 0xb9, 0x78, 0x7f, 0x4f, 0xab,
++	0x82, 0x15, 0x53, 0xaa, 0x04, 0xee, 0x11, 0x21,
++	0x2e, 0x23, 0x08, 0xa0, 0x14, 0x6d, 0x3a, 0x88,
++	0xe6, 0xf8, 0xbe, 0x61, 0x38, 0x99, 0xca, 0x36,
++	0x0d, 0x3e, 0x42, 0x0f, 0x63, 0x4d, 0x73, 0xf0,
++	0xdf
++};
++CK_BYTE exp_1[] = {
++	0x66, 0x2d, 0xb7, 0x65, 0xbe, 0x99, 0xc2, 0x35,
++	0xfe, 0x2b, 0xf4, 0xe8, 0x5b, 0xd9, 0xdf, 0x13,
++	0x26, 0x04, 0xe4, 0x18, 0x9d, 0x76, 0x92, 0x9a,
++	0x9f, 0x53, 0x6c, 0xe6, 0x65, 0x6b, 0x53, 0x2f,
++	0x2f, 0xbc, 0x46, 0xac, 0xe1, 0x97, 0xca, 0x21,
++	0xf5, 0x21, 0x4e, 0x14, 0x49, 0x3b, 0x1d, 0x42,
++	0xbd, 0x80, 0x0c, 0x3f, 0x29, 0xba, 0x09, 0x7f,
++	0x85, 0xf0, 0x9c, 0x55, 0x60, 0xb4, 0x9e, 0xc1
++};
++CK_BYTE exp_2[] = {
++	0x00, 0x87, 0x22, 0x74, 0xf1, 0xe2, 0x15, 0x3c,
++	0x6d, 0xde, 0x7e, 0x90, 0x94, 0x2c, 0x06, 0xdb,
++	0xb5, 0x54, 0x85, 0x59, 0xcf, 0x7a, 0x56, 0xdb,
++	0xd9, 0x62, 0x54, 0x20, 0x56, 0xdc, 0xc3, 0xb9,
++	0x0b, 0xff, 0x18, 0xf8, 0x7b, 0xdd, 0x7b, 0x24,
++	0xf6, 0x06, 0x45, 0x71, 0x4e, 0xd7, 0x90, 0x2a,
++	0x16, 0x52, 0x46, 0x75, 0x1a, 0xf5, 0x74, 0x8c,
++	0x5a, 0xa4, 0xc4, 0x66, 0x27, 0xe0, 0x96, 0x64,
++	0x7f
++};
++CK_BYTE coeff[] = {
++	0x00, 0xd0, 0x1f, 0xb3, 0x47, 0x40, 0x93, 0x8b,
++	0x99, 0xd7, 0xb5, 0xc6, 0x09, 0x82, 0x65, 0x94,
++	0x9d, 0x56, 0x0a, 0x05, 0x55, 0x7d, 0x93, 0x04,
++	0xa4, 0x26, 0xee, 0x42, 0x86, 0xa3, 0xf1, 0xd5,
++	0x7a, 0x42, 0x84, 0x3c, 0x21, 0x96, 0x9a, 0xd9,
++	0x36, 0xd4, 0x62, 0x01, 0xb0, 0x8b, 0x77, 0xe5,
++	0xcc, 0x1b, 0xd2, 0x12, 0xd2, 0x9c, 0x89, 0x67,
++	0x0c, 0x00, 0x09, 0x56, 0x8c, 0x33, 0x57, 0xf9,
++	0x8c
++};
++
++char label[16];
++
++static CK_BBOOL truevalue = TRUE;
++static CK_BBOOL falsevalue = FALSE;
++
++int
++main(int argc, char *argv[]) {
++	isc_result_t result;
++	CK_RV rv;
++	CK_SLOT_ID slot = 0;
++	CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
++	CK_OBJECT_HANDLE *hKey;
++	CK_OBJECT_CLASS kClass = CKO_PRIVATE_KEY;
++	CK_KEY_TYPE kType = CKK_RSA;
++	CK_ATTRIBUTE kTemplate[] =
++	{
++		{ CKA_CLASS, &kClass, (CK_ULONG) sizeof(kClass) },
++		{ CKA_KEY_TYPE, &kType, (CK_ULONG) sizeof(kType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_LABEL, (CK_BYTE_PTR) label, (CK_ULONG) sizeof(label) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_MODULUS, modulus, (CK_ULONG) sizeof(modulus) },
++		{ CKA_PUBLIC_EXPONENT, pubexp, (CK_ULONG) sizeof(pubexp) },
++		{ CKA_PRIVATE_EXPONENT, privexp, (CK_ULONG) sizeof(privexp) },
++		{ CKA_PRIME_1, prime1, (CK_ULONG) sizeof(prime1) },
++		{ CKA_PRIME_2, prime2, (CK_ULONG) sizeof(prime2) },
++		{ CKA_EXPONENT_1, exp_1, (CK_ULONG) sizeof(exp_1) },
++		{ CKA_EXPONENT_2, exp_2, (CK_ULONG) sizeof(exp_2) },
++		{ CKA_COEFFICIENT, coeff, (CK_ULONG) sizeof(coeff) }
++	};
++	pk11_context_t pctx;
++	pk11_optype_t op_type = OP_RSA;
++	char *lib_name = NULL;
++	char *pin = NULL;
++	int error = 0;
++	int c, errflg = 0;
++	int ontoken  = 0;
++	unsigned int count = 1000;
++	unsigned int i;
++	struct timespec starttime;
++	struct timespec endtime;
++
++	while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) {
++		switch (c) {
++		case 'm':
++			lib_name = isc_commandline_argument;
++			break;
++		case 's':
++			op_type = OP_ANY;
++			slot = atoi(isc_commandline_argument);
++			break;
++		case 'p':
++			pin = isc_commandline_argument;
++			break;
++		case 't':
++			ontoken = 1;
++			break;
++		case 'n':
++			count = atoi(isc_commandline_argument);
++			break;
++		case ':':
++			fprintf(stderr,
++				"Option -%c requires an operand\n",
++				isc_commandline_option);
++			errflg++;
++			break;
++		case '?':
++		default:
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
++			errflg++;
++		}
++	}
++
++	if (errflg) {
++		fprintf(stderr, "Usage:\n");
++		fprintf(stderr,
++			"\tprivrsa [-m module] [-s slot] [-p pin] "
++			"[-t] [-n count]\n");
++		exit(1);
++	}
++
++	pk11_result_register();
++
++	/* Allocate hanles */
++	hKey = (CK_SESSION_HANDLE *)
++		malloc(count * sizeof(CK_SESSION_HANDLE));
++	if (hKey == NULL) {
++		perror("malloc");
++		exit(1);
++	}
++	for (i = 0; i < count; i++)
++		hKey[i] = CK_INVALID_HANDLE;
++
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
++
++	if (pin == NULL)
++		pin = getpassphrase("Enter Pin: ");
++
++	result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_TRUE,
++				  ISC_TRUE, (const char *) pin, slot);
++	if ((result != ISC_R_SUCCESS) &&
++	    (result != PK11_R_NORANDOMSERVICE) &&
++	    (result != PK11_R_NODIGESTSERVICE) &&
++	    (result != PK11_R_NOAESSERVICE)) {
++		fprintf(stderr, "Error initializing PKCS#11: %s\n",
++			isc_result_totext(result));
++		free(hKey);
++		exit(1);
++	}
++
++	if (pin != NULL)
++		memset(pin, 0, strlen((char *)pin));
++
++	hSession = pctx.session;
++
++	if (ontoken)
++		kTemplate[2].pValue = &truevalue;
++
++	if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) {
++		perror("clock_gettime(start)");
++		goto exit_objects;
++	}
++
++	for (i = 0; i < count; i++) {
++		(void) snprintf(label, sizeof(label), "obj%u", i);
++		kTemplate[4].ulValueLen = strlen(label);
++		rv = pkcs_C_CreateObject(hSession, kTemplate, 14, &hKey[i]);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_CreateObject[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			if (i == 0)
++				goto exit_objects;
++			break;
++		}
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) {
++		perror("clock_gettime(end)");
++		goto exit_objects;
++	}
++
++	endtime.tv_sec -= starttime.tv_sec;
++	endtime.tv_nsec -= starttime.tv_nsec;
++	while (endtime.tv_nsec < 0) {
++		endtime.tv_sec -= 1;
++		endtime.tv_nsec += 1000000000;
++	}
++	printf("%u private RSA keys in %ld.%09lds\n", i,
++	       endtime.tv_sec, endtime.tv_nsec);
++	if (i > 0)
++		printf("%g private RSA keys/s\n",
++		       1024 * i / ((double) endtime.tv_sec +
++				   (double) endtime.tv_nsec / 1000000000.));
++
++    exit_objects:
++	for (i = 0; i < count; i++) {
++		/* Destroy objects */
++		if (hKey[i] == CK_INVALID_HANDLE)
++			continue;
++		rv = pkcs_C_DestroyObject(hSession, hKey[i]);
++		if ((rv != CKR_OK) && !errflg) {
++			fprintf(stderr,
++				"C_DestroyObject[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			errflg = 1;
++		}
++	}
++
++	free(hKey);
++
++	pk11_return_session(&pctx);
++	(void) pk11_finalize();
++
++	exit(error);
++}
+diff --git a/bin/tests/pkcs11/benchmarks/pubrsa.c b/bin/tests/pkcs11/benchmarks/pubrsa.c
+new file mode 100644
+index 0000000..b27a999
+--- /dev/null
++++ b/bin/tests/pkcs11/benchmarks/pubrsa.c
+@@ -0,0 +1,281 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* $Id$ */
++
++/* pubrsa [-m module] [-s $slot] [-p pin] [-t] [-n count] */
++
++/*! \file */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++#include <unistd.h>
++
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/result.h>
++
++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
++#define getpassphrase(x)	getpass(x)
++#endif
++
++#ifndef HAVE_CLOCK_GETTIME
++#ifndef CLOCK_REALTIME
++#define CLOCK_REALTIME 0
++#endif
++
++int
++clock_gettime(int32_t id, struct timespec *tp)
++{
++	struct timeval tv;
++	int result;
++
++	result = gettimeofday(&tv, NULL);
++	if (result)
++		return (result);
++	tp->tv_sec = tv.tv_sec;
++	tp->tv_nsec = (long) tv.tv_usec * 1000;
++	return (result);
++}
++#endif
++
++CK_BYTE modulus[] = {
++	0x00, 0xb7, 0x9c, 0x1f, 0x05, 0xa3, 0xc2, 0x99,
++	0x44, 0x82, 0x20, 0x78, 0x43, 0x7f, 0x5f, 0x3b,
++	0x10, 0xd7, 0x9e, 0x61, 0x42, 0xd2, 0x7a, 0x90,
++	0x50, 0x8a, 0x99, 0x33, 0xe7, 0xca, 0xc8, 0x5f,
++	0x16, 0x1c, 0x56, 0xf8, 0xc1, 0x06, 0x2f, 0x96,
++	0xe7, 0x54, 0xf2, 0x85, 0x89, 0x41, 0x36, 0xf5,
++	0x4c, 0xa4, 0x0d, 0x62, 0xd3, 0x42, 0x51, 0x6b,
++	0x9f, 0xdc, 0x36, 0xcb, 0xad, 0x56, 0xf4, 0xbd,
++	0x2a, 0x60, 0x33, 0xb1, 0x7a, 0x99, 0xad, 0x08,
++	0x9f, 0x95, 0xe8, 0xe5, 0x14, 0xd9, 0x68, 0x79,
++	0xca, 0x4e, 0x72, 0xeb, 0xfb, 0x2c, 0xf1, 0x45,
++	0xd3, 0x33, 0x65, 0xe7, 0xc5, 0x11, 0xdd, 0xe7,
++	0x09, 0x83, 0x13, 0xd5, 0x17, 0x1b, 0xf4, 0xbd,
++	0x49, 0xdd, 0x8a, 0x3c, 0x3c, 0xf7, 0xa1, 0x5d,
++	0x7b, 0xb4, 0xd3, 0x80, 0x25, 0xf4, 0x05, 0x8f,
++	0xbc, 0x2c, 0x2a, 0x47, 0xff, 0xd1, 0xc8, 0x34,
++	0xbf
++};
++CK_BYTE exponent[] = { 0x01, 0x00, 0x01 };
++
++char label[16];
++
++static CK_BBOOL truevalue = TRUE;
++static CK_BBOOL falsevalue = FALSE;
++
++int
++main(int argc, char *argv[]) {
++	isc_result_t result;
++	CK_RV rv;
++	CK_SLOT_ID slot = 0;
++	CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
++	CK_OBJECT_HANDLE *hKey;
++	CK_OBJECT_CLASS kClass = CKO_PUBLIC_KEY;
++	CK_KEY_TYPE kType = CKK_RSA;
++	CK_ATTRIBUTE kTemplate[] =
++	{
++		{ CKA_CLASS, &kClass, (CK_ULONG) sizeof(kClass) },
++		{ CKA_KEY_TYPE, &kType, (CK_ULONG) sizeof(kType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_LABEL, (CK_BYTE_PTR) label, (CK_ULONG) sizeof(label) },
++		{ CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_MODULUS, modulus, (CK_ULONG) sizeof(modulus) },
++		{ CKA_PUBLIC_EXPONENT, exponent, (CK_ULONG) sizeof(exponent) }
++	};
++	pk11_context_t pctx;
++	pk11_optype_t op_type = OP_RSA;
++	char *lib_name = NULL;
++	char *pin = NULL;
++	int error = 0;
++	int c, errflg = 0;
++	int ontoken  = 0;
++	unsigned int count = 1000;
++	unsigned int i;
++	struct timespec starttime;
++	struct timespec endtime;
++
++	while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) {
++		switch (c) {
++		case 'm':
++			lib_name = isc_commandline_argument;
++			break;
++		case 's':
++			op_type = OP_ANY;
++			slot = atoi(isc_commandline_argument);
++			break;
++		case 'p':
++			pin = isc_commandline_argument;
++			break;
++		case 't':
++			ontoken = 1;
++			break;
++		case 'n':
++			count = atoi(isc_commandline_argument);
++			break;
++		case ':':
++			fprintf(stderr,
++				"Option -%c requires an operand\n",
++				isc_commandline_option);
++			errflg++;
++			break;
++		case '?':
++		default:
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
++			errflg++;
++		}
++	}
++
++	if (errflg) {
++		fprintf(stderr, "Usage:\n");
++		fprintf(stderr,
++			"\tpubrsa [-m module] [-s slot] [-p pin] "
++			"[-t] [-n count]\n");
++		exit(1);
++	}
++
++	pk11_result_register();
++
++	/* Allocate hanles */
++	hKey = (CK_SESSION_HANDLE *)
++		malloc(count * sizeof(CK_SESSION_HANDLE));
++	if (hKey == NULL) {
++		perror("malloc");
++		exit(1);
++	}
++	for (i = 0; i < count; i++)
++		hKey[i] = CK_INVALID_HANDLE;
++
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
++
++	if (pin == NULL)
++		pin = getpassphrase("Enter Pin: ");
++
++	result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_TRUE,
++				  ISC_TRUE, (const char *) pin, slot);
++	if ((result != ISC_R_SUCCESS) &&
++	    (result != PK11_R_NORANDOMSERVICE) &&
++	    (result != PK11_R_NODIGESTSERVICE) &&
++	    (result != PK11_R_NOAESSERVICE)) {
++		fprintf(stderr, "Error initializing PKCS#11: %s\n",
++			isc_result_totext(result));
++		free(hKey);
++		exit(1);
++	}
++
++	if (pin != NULL)
++		memset(pin, 0, strlen((char *)pin));
++
++	hSession = pctx.session;
++
++	if (ontoken)
++		kTemplate[2].pValue = &truevalue;
++
++	if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) {
++		perror("clock_gettime(start)");
++		goto exit_objects;
++	}
++
++	for (i = 0; i < count; i++) {
++		(void) snprintf(label, sizeof(label), "obj%u", i);
++		kTemplate[4].ulValueLen = strlen(label);
++		rv = pkcs_C_CreateObject(hSession, kTemplate, 8, &hKey[i]);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_CreateObject[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			if (i == 0)
++				goto exit_objects;
++			break;
++		}
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) {
++		perror("clock_gettime(end)");
++		goto exit_objects;
++	}
++
++	endtime.tv_sec -= starttime.tv_sec;
++	endtime.tv_nsec -= starttime.tv_nsec;
++	while (endtime.tv_nsec < 0) {
++		endtime.tv_sec -= 1;
++		endtime.tv_nsec += 1000000000;
++	}
++	printf("%u public RSA keys in %ld.%09lds\n", i,
++	       endtime.tv_sec, endtime.tv_nsec);
++	if (i > 0)
++		printf("%g public RSA keys/s\n",
++		       1024 * i / ((double) endtime.tv_sec +
++				   (double) endtime.tv_nsec / 1000000000.));
++
++    exit_objects:
++	for (i = 0; i < count; i++) {
++		/* Destroy objects */
++		if (hKey[i] == CK_INVALID_HANDLE)
++			continue;
++		rv = pkcs_C_DestroyObject(hSession, hKey[i]);
++		if ((rv != CKR_OK) && !errflg) {
++			fprintf(stderr,
++				"C_DestroyObject[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			errflg = 1;
++		}
++	}
++
++	free(hKey);
++
++	pk11_return_session(&pctx);
++	(void) pk11_finalize();
++
++	exit(error);
++}
+diff --git a/bin/tests/pkcs11/benchmarks/random.c b/bin/tests/pkcs11/benchmarks/random.c
+new file mode 100644
+index 0000000..10d6db0
+--- /dev/null
++++ b/bin/tests/pkcs11/benchmarks/random.c
+@@ -0,0 +1,192 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* $Id$ */
++
++/* random [-m module] [-s $slot] [-n count] */
++
++/*! \file */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++#include <unistd.h>
++
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/result.h>
++
++#ifndef HAVE_CLOCK_GETTIME
++#ifndef CLOCK_REALTIME
++#define CLOCK_REALTIME 0
++#endif
++
++int
++clock_gettime(int32_t id, struct timespec *tp)
++{
++	struct timeval tv;
++	int result;
++
++	result = gettimeofday(&tv, NULL);
++	if (result)
++		return (result);
++	tp->tv_sec = tv.tv_sec;
++	tp->tv_nsec = (long) tv.tv_usec * 1000;
++	return (result);
++}
++#endif
++
++CK_BYTE buf[1024];
++
++int
++main(int argc, char *argv[]) {
++	isc_result_t result;
++	CK_RV rv;
++	CK_SLOT_ID slot = 0;
++	CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
++	CK_ULONG len = sizeof(buf);
++	pk11_context_t pctx;
++	pk11_optype_t op_type = OP_RAND;
++	char *lib_name = NULL;
++	int error = 0;
++	int c, errflg = 0;
++	unsigned int count = 1000;
++	unsigned int i;
++	struct timespec starttime;
++	struct timespec endtime;
++
++	while ((c = isc_commandline_parse(argc, argv, ":m:s:n:")) != -1) {
++		switch (c) {
++		case 'm':
++			lib_name = isc_commandline_argument;
++			break;
++		case 's':
++			op_type = OP_ANY;
++			slot = atoi(isc_commandline_argument);
++			break;
++		case 'n':
++			count = atoi(isc_commandline_argument);
++			break;
++		case ':':
++			fprintf(stderr,
++				"Option -%c requires an operand\n",
++				isc_commandline_option);
++			errflg++;
++			break;
++		case '?':
++		default:
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
++			errflg++;
++		}
++	}
++
++	if (errflg) {
++		fprintf(stderr, "Usage:\n");
++		fprintf(stderr,
++			"\trandom [-m module] [-s slot] [-n count]\n");
++		exit(1);
++	}
++
++	pk11_result_register();
++
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
++
++	result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_FALSE,
++				  ISC_FALSE, NULL, slot);
++	if ((result != ISC_R_SUCCESS) &&
++	    (result != PK11_R_NODIGESTSERVICE) &&
++	    (result != PK11_R_NOAESSERVICE)) {
++		fprintf(stderr, "Error initializing PKCS#11: %s\n",
++			isc_result_totext(result));
++		exit(1);
++	}
++
++	hSession = pctx.session;
++
++	if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) {
++		perror("clock_gettime(start)");
++		goto exit_session;
++	}
++
++	for (i = 0; i < count; i++) {
++		/* Get random bytes */
++		rv = pkcs_C_GenerateRandom(hSession, buf, len);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_GenerateRandom[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			break;
++		}
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) {
++		perror("clock_gettime(end)");
++		goto exit_session;
++	}
++
++	endtime.tv_sec -= starttime.tv_sec;
++	endtime.tv_nsec -= starttime.tv_nsec;
++	while (endtime.tv_nsec < 0) {
++		endtime.tv_sec -= 1;
++		endtime.tv_nsec += 1000000000;
++	}
++	printf("%uK random bytes in %ld.%09lds\n", i,
++	       endtime.tv_sec, endtime.tv_nsec);
++	if (i > 0)
++		printf("%g random bytes/s\n",
++		       1024 * i / ((double) endtime.tv_sec +
++				   (double) endtime.tv_nsec / 1000000000.));
++
++    exit_session:
++	pk11_return_session(&pctx);
++	(void) pk11_finalize();
++
++	exit(error);
++}
+diff --git a/bin/tests/pkcs11/benchmarks/session.c b/bin/tests/pkcs11/benchmarks/session.c
+new file mode 100644
+index 0000000..74bd63a
+--- /dev/null
++++ b/bin/tests/pkcs11/benchmarks/session.c
+@@ -0,0 +1,213 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* $Id$ */
++
++/* session [-m module] [-s $slot] [-n count] */
++
++/*! \file */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++#include <unistd.h>
++
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/internal.h>
++
++#ifndef HAVE_CLOCK_GETTIME
++#ifndef CLOCK_REALTIME
++#define CLOCK_REALTIME 0
++#endif
++
++int
++clock_gettime(int32_t id, struct timespec *tp)
++{
++	struct timeval tv;
++	int result;
++
++	result = gettimeofday(&tv, NULL);
++	if (result)
++		return (result);
++	tp->tv_sec = tv.tv_sec;
++	tp->tv_nsec = (long) tv.tv_usec * 1000;
++	return (result);
++}
++#endif
++
++int
++main(int argc, char *argv[]) {
++	CK_RV rv;
++	CK_SLOT_ID slot = 0;
++	CK_SESSION_HANDLE *hSession;
++	char *lib_name = NULL;
++	int error = 0;
++	int c, errflg = 0;
++	unsigned int count = 1000;
++	unsigned int i;
++	struct timespec starttime;
++	struct timespec endtime;
++
++	while ((c = isc_commandline_parse(argc, argv, ":m:s:n:")) != -1) {
++		switch (c) {
++		case 'm':
++			lib_name = isc_commandline_argument;
++			break;
++		case 's':
++			slot = atoi(isc_commandline_argument);
++			break;
++		case 'n':
++			count = atoi(isc_commandline_argument);
++			break;
++		case ':':
++			fprintf(stderr,
++				"Option -%c requires an operand\n",
++				isc_commandline_option);
++			errflg++;
++			break;
++		case '?':
++		default:
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
++			errflg++;
++		}
++	}
++
++	if (errflg) {
++		fprintf(stderr, "Usage:\n");
++		fprintf(stderr,
++			"\tsession [-m module] [-s slot] [-n count]\n");
++		exit(1);
++	}
++
++	/* Allocate sessions */
++	hSession = (CK_SESSION_HANDLE *)
++		malloc(count * sizeof(CK_SESSION_HANDLE));
++	if (hSession == NULL) {
++		perror("malloc");
++		exit(1);
++	}
++	for (i = 0; i < count; i++)
++		hSession[i] = CK_INVALID_HANDLE;
++
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
++
++	rv = pkcs_C_Initialize(NULL_PTR);
++	if (rv != CKR_OK) {
++		if (rv == 0xfe)
++			fprintf(stderr,
++				"Can't load or link module \"%s\"\n",
++				pk11_get_lib_name());
++		else
++			fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv);
++		free(hSession);
++		exit(1);
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) {
++		perror("clock_gettime(start)");
++		goto exit_program;
++	}
++
++	/* loop */
++	for (i = 0; i < count; i++) {
++		/* Open sessions */
++		rv = pkcs_C_OpenSession(slot, CKF_SERIAL_SESSION,
++					NULL_PTR, NULL_PTR, &hSession[i]);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_OpenSession[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			if (i == 0)
++				goto exit_program;
++			break;
++		}
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) {
++		perror("clock_gettime(end)");
++		goto exit_program;
++	}
++
++	endtime.tv_sec -= starttime.tv_sec;
++	endtime.tv_nsec -= starttime.tv_nsec;
++	while (endtime.tv_nsec < 0) {
++		endtime.tv_sec -= 1;
++		endtime.tv_nsec += 1000000000;
++	}
++	printf("%u sessions in %ld.%09lds\n", i,
++	       endtime.tv_sec, endtime.tv_nsec);
++	if (i > 0)
++		printf("%g sessions/s\n",
++		       i / ((double) endtime.tv_sec +
++			    (double) endtime.tv_nsec / 1000000000.));
++
++	for (i = 0; i < count; i++) {
++		/* Close sessions */
++		if (hSession[i] == CK_INVALID_HANDLE)
++			continue;
++		rv = pkcs_C_CloseSession(hSession[i]);
++		if ((rv != CKR_OK) && !errflg) {
++			fprintf(stderr,
++				"C_CloseSession[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			errflg = 1;
++		}
++	}
++
++    exit_program:
++	free(hSession);
++
++	rv = pkcs_C_Finalize(NULL_PTR);
++	if (rv != CKR_OK)
++		fprintf(stderr, "C_Finalize: Error = 0x%.8lX\n", rv);
++		
++	exit(error);
++}
+diff --git a/bin/tests/pkcs11/benchmarks/sha1.c b/bin/tests/pkcs11/benchmarks/sha1.c
+new file mode 100644
+index 0000000..756aadb
+--- /dev/null
++++ b/bin/tests/pkcs11/benchmarks/sha1.c
+@@ -0,0 +1,214 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* $Id$ */
++
++/* sha1 [-m module] [-s $slot] [-n count] */
++
++/*! \file */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++#include <unistd.h>
++
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/result.h>
++
++#ifndef HAVE_CLOCK_GETTIME
++#ifndef CLOCK_REALTIME
++#define CLOCK_REALTIME 0
++#endif
++
++int
++clock_gettime(int32_t id, struct timespec *tp)
++{
++	struct timeval tv;
++	int result;
++
++	result = gettimeofday(&tv, NULL);
++	if (result)
++		return (result);
++	tp->tv_sec = tv.tv_sec;
++	tp->tv_nsec = (long) tv.tv_usec * 1000;
++	return (result);
++}
++#endif
++
++CK_BYTE buf[1024];
++
++int
++main(int argc, char *argv[]) {
++	isc_result_t result;
++	CK_RV rv;
++	CK_SLOT_ID slot = 0;
++	CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
++	CK_MECHANISM mech = { CKM_SHA_1, NULL, 0 };
++	CK_ULONG len = sizeof(buf);
++	pk11_context_t pctx;
++	pk11_optype_t op_type = OP_DIGEST;
++	char *lib_name = NULL;
++	int error = 0;
++	int c, errflg = 0;
++	unsigned int count = 1000;
++	unsigned int i;
++	struct timespec starttime;
++	struct timespec endtime;
++
++	while ((c = isc_commandline_parse(argc, argv, ":m:s:n:")) != -1) {
++		switch (c) {
++		case 'm':
++			lib_name = isc_commandline_argument;
++			break;
++		case 's':
++			op_type = OP_ANY;
++			slot = atoi(isc_commandline_argument);
++			break;
++		case 'n':
++			count = atoi(isc_commandline_argument);
++			break;
++		case ':':
++			fprintf(stderr,
++				"Option -%c requires an operand\n",
++				isc_commandline_option);
++			errflg++;
++			break;
++		case '?':
++		default:
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
++			errflg++;
++		}
++	}
++
++	if (errflg) {
++		fprintf(stderr, "Usage:\n");
++		fprintf(stderr,
++			"\tssha1 [-m module] [-s slot] [-n count]\n");
++		exit(1);
++	}
++
++	pk11_result_register();
++
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
++
++	result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_FALSE,
++				  ISC_FALSE, NULL, slot);
++	if ((result != ISC_R_SUCCESS) &&
++	    (result != PK11_R_NORANDOMSERVICE) &&
++	    (result != PK11_R_NOAESSERVICE)) {
++		fprintf(stderr, "Error initializing PKCS#11: %s\n",
++			isc_result_totext(result));
++		exit(1);
++	}
++
++	hSession = pctx.session;
++
++	/* Randomize the buffer */
++	rv = pkcs_C_GenerateRandom(hSession, buf, len);
++	if (rv != CKR_OK) {
++		fprintf(stderr, "C_GenerateRandom: Error = 0x%.8lX\n", rv);
++		goto exit_session;
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) {
++		perror("clock_gettime(start)");
++		goto exit_session;
++	}
++
++	/* Initialize Digest */
++	rv = pkcs_C_DigestInit(hSession, &mech);
++	if (rv != CKR_OK) {
++		fprintf(stderr, "C_DigestInit: Error = 0x%.8lX\n", rv);
++		goto exit_session;
++	}
++
++
++	for (i = 0; i < count; i++) {
++		/* Digest buffer */
++		rv = pkcs_C_DigestUpdate(hSession, buf, len);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_DigestUpdate[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			break;
++		}
++	}
++
++	/* Finalize Digest (unconditionally) */
++	len = 20U;
++	rv = pkcs_C_DigestFinal(hSession, buf, &len);
++	if ((rv != CKR_OK) && !error)
++		fprintf(stderr, "C_DigestFinal: Error = 0x%.8lX\n", rv);
++
++	if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) {
++		perror("clock_gettime(end)");
++		goto exit_session;
++	}
++
++	endtime.tv_sec -= starttime.tv_sec;
++	endtime.tv_nsec -= starttime.tv_nsec;
++	while (endtime.tv_nsec < 0) {
++		endtime.tv_sec -= 1;
++		endtime.tv_nsec += 1000000000;
++	}
++	printf("%uK digested bytes in %ld.%09lds\n", i,
++	       endtime.tv_sec, endtime.tv_nsec);
++	if (i > 0)
++		printf("%g digested bytes/s\n",
++		       1024 * i / ((double) endtime.tv_sec +
++				   (double) endtime.tv_nsec / 1000000000.));
++
++    exit_session:
++	pk11_return_session(&pctx);
++	(void) pk11_finalize();
++
++	exit(error);
++}
+diff --git a/bin/tests/pkcs11/benchmarks/sign.c b/bin/tests/pkcs11/benchmarks/sign.c
+new file mode 100644
+index 0000000..8425ba9
+--- /dev/null
++++ b/bin/tests/pkcs11/benchmarks/sign.c
+@@ -0,0 +1,368 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* $Id$ */
++
++/* signrsa [-m module] [-s $slot] [-p pin] [-t] [-n count] */
++
++/*! \file */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++#include <unistd.h>
++
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/result.h>
++
++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
++#define getpassphrase(x)	getpass(x)
++#endif
++
++#ifndef HAVE_CLOCK_GETTIME
++#ifndef CLOCK_REALTIME
++#define CLOCK_REALTIME 0
++#endif
++
++int
++clock_gettime(int32_t id, struct timespec *tp)
++{
++	struct timeval tv;
++	int result;
++
++	result = gettimeofday(&tv, NULL);
++	if (result)
++		return (result);
++	tp->tv_sec = tv.tv_sec;
++	tp->tv_nsec = (long) tv.tv_usec * 1000;
++	return (result);
++}
++#endif
++
++CK_BYTE modulus[] = {
++	0x00, 0xb7, 0x9c, 0x1f, 0x05, 0xa3, 0xc2, 0x99,
++	0x44, 0x82, 0x20, 0x78, 0x43, 0x7f, 0x5f, 0x3b,
++	0x10, 0xd7, 0x9e, 0x61, 0x42, 0xd2, 0x7a, 0x90,
++	0x50, 0x8a, 0x99, 0x33, 0xe7, 0xca, 0xc8, 0x5f,
++	0x16, 0x1c, 0x56, 0xf8, 0xc1, 0x06, 0x2f, 0x96,
++	0xe7, 0x54, 0xf2, 0x85, 0x89, 0x41, 0x36, 0xf5,
++	0x4c, 0xa4, 0x0d, 0x62, 0xd3, 0x42, 0x51, 0x6b,
++	0x9f, 0xdc, 0x36, 0xcb, 0xad, 0x56, 0xf4, 0xbd,
++	0x2a, 0x60, 0x33, 0xb1, 0x7a, 0x99, 0xad, 0x08,
++	0x9f, 0x95, 0xe8, 0xe5, 0x14, 0xd9, 0x68, 0x79,
++	0xca, 0x4e, 0x72, 0xeb, 0xfb, 0x2c, 0xf1, 0x45,
++	0xd3, 0x33, 0x65, 0xe7, 0xc5, 0x11, 0xdd, 0xe7,
++	0x09, 0x83, 0x13, 0xd5, 0x17, 0x1b, 0xf4, 0xbd,
++	0x49, 0xdd, 0x8a, 0x3c, 0x3c, 0xf7, 0xa1, 0x5d,
++	0x7b, 0xb4, 0xd3, 0x80, 0x25, 0xf4, 0x05, 0x8f,
++	0xbc, 0x2c, 0x2a, 0x47, 0xff, 0xd1, 0xc8, 0x34,
++	0xbf
++};
++CK_BYTE pubexp[] = { 0x01, 0x00, 0x01 };
++CK_BYTE privexp[] = {
++	0x00, 0xae, 0x02, 0xf1, 0x47, 0xa8, 0x07, 0x02,
++	0xb8, 0xf1, 0xd6, 0x92, 0x03, 0xee, 0x50, 0x33,
++	0xab, 0x67, 0x9e, 0x3b, 0xb1, 0x57, 0xc7, 0x3e,
++	0xc4, 0x86, 0x46, 0x61, 0xf1, 0xf8, 0xb6, 0x63,
++	0x9f, 0x91, 0xe6, 0x3f, 0x44, 0xb8, 0x77, 0x1b,
++	0xbe, 0x4c, 0x3c, 0xb8, 0x9f, 0xf7, 0x45, 0x7d,
++	0xbf, 0x4f, 0xef, 0x3b, 0xcc, 0xda, 0x1a, 0x4e,
++	0x34, 0xa8, 0x40, 0xea, 0x51, 0x72, 0x8a, 0xea,
++	0x47, 0x06, 0x04, 0xd0, 0x62, 0x31, 0xa0, 0x6c,
++	0x09, 0x60, 0xf9, 0xc7, 0x95, 0x88, 0x4a, 0xd7,
++	0x19, 0xce, 0x89, 0x08, 0x87, 0x14, 0xef, 0xcc,
++	0x0a, 0xef, 0x72, 0xb9, 0x21, 0xf5, 0xf0, 0xcd,
++	0x6d, 0xe5, 0xfa, 0x15, 0x7f, 0xae, 0x33, 0x9f,
++	0x26, 0xac, 0x2e, 0x52, 0x02, 0x07, 0xfb, 0x1d,
++	0x4b, 0xec, 0x9a, 0x6b, 0x3b, 0x26, 0x1f, 0x52,
++	0xfc, 0x47, 0xf8, 0x66, 0x33, 0xfa, 0x50, 0x6c,
++	0x41
++};
++CK_BYTE prime1[] = {
++	0x00, 0xe8, 0x98, 0xeb, 0xa1, 0xf0, 0xce, 0xde,
++	0xc2, 0x74, 0x01, 0x18, 0x2b, 0xd3, 0x8f, 0x58,
++	0xcd, 0xe9, 0x8e, 0x97, 0xbe, 0xfe, 0xe8, 0x6f,
++	0xd6, 0x0c, 0x0a, 0x47, 0xf8, 0x56, 0x84, 0x36,
++	0x15, 0xe6, 0x75, 0x1c, 0x69, 0x48, 0x8b, 0xf5,
++	0x0f, 0x84, 0xd2, 0x60, 0x8b, 0xa2, 0x2a, 0xa1,
++	0xeb, 0xed, 0xbe, 0x2d, 0xe9, 0x41, 0x0b, 0xed,
++	0x17, 0x7c, 0xd3, 0xa6, 0x35, 0x6e, 0xa6, 0xd8,
++	0x21
++};
++CK_BYTE prime2[] = {
++	0x00, 0xca, 0x15, 0x6a, 0x43, 0x5e, 0x83, 0xc9,
++	0x09, 0xeb, 0x14, 0x1e, 0x46, 0x46, 0x97, 0xfa,
++	0xfa, 0x3c, 0x61, 0x7e, 0xc1, 0xf8, 0x8c, 0x5e,
++	0xcb, 0xbf, 0xe4, 0xb9, 0x78, 0x7f, 0x4f, 0xab,
++	0x82, 0x15, 0x53, 0xaa, 0x04, 0xee, 0x11, 0x21,
++	0x2e, 0x23, 0x08, 0xa0, 0x14, 0x6d, 0x3a, 0x88,
++	0xe6, 0xf8, 0xbe, 0x61, 0x38, 0x99, 0xca, 0x36,
++	0x0d, 0x3e, 0x42, 0x0f, 0x63, 0x4d, 0x73, 0xf0,
++	0xdf
++};
++CK_BYTE exp_1[] = {
++	0x66, 0x2d, 0xb7, 0x65, 0xbe, 0x99, 0xc2, 0x35,
++	0xfe, 0x2b, 0xf4, 0xe8, 0x5b, 0xd9, 0xdf, 0x13,
++	0x26, 0x04, 0xe4, 0x18, 0x9d, 0x76, 0x92, 0x9a,
++	0x9f, 0x53, 0x6c, 0xe6, 0x65, 0x6b, 0x53, 0x2f,
++	0x2f, 0xbc, 0x46, 0xac, 0xe1, 0x97, 0xca, 0x21,
++	0xf5, 0x21, 0x4e, 0x14, 0x49, 0x3b, 0x1d, 0x42,
++	0xbd, 0x80, 0x0c, 0x3f, 0x29, 0xba, 0x09, 0x7f,
++	0x85, 0xf0, 0x9c, 0x55, 0x60, 0xb4, 0x9e, 0xc1
++};
++CK_BYTE exp_2[] = {
++	0x00, 0x87, 0x22, 0x74, 0xf1, 0xe2, 0x15, 0x3c,
++	0x6d, 0xde, 0x7e, 0x90, 0x94, 0x2c, 0x06, 0xdb,
++	0xb5, 0x54, 0x85, 0x59, 0xcf, 0x7a, 0x56, 0xdb,
++	0xd9, 0x62, 0x54, 0x20, 0x56, 0xdc, 0xc3, 0xb9,
++	0x0b, 0xff, 0x18, 0xf8, 0x7b, 0xdd, 0x7b, 0x24,
++	0xf6, 0x06, 0x45, 0x71, 0x4e, 0xd7, 0x90, 0x2a,
++	0x16, 0x52, 0x46, 0x75, 0x1a, 0xf5, 0x74, 0x8c,
++	0x5a, 0xa4, 0xc4, 0x66, 0x27, 0xe0, 0x96, 0x64,
++	0x7f
++};
++CK_BYTE coeff[] = {
++	0x00, 0xd0, 0x1f, 0xb3, 0x47, 0x40, 0x93, 0x8b,
++	0x99, 0xd7, 0xb5, 0xc6, 0x09, 0x82, 0x65, 0x94,
++	0x9d, 0x56, 0x0a, 0x05, 0x55, 0x7d, 0x93, 0x04,
++	0xa4, 0x26, 0xee, 0x42, 0x86, 0xa3, 0xf1, 0xd5,
++	0x7a, 0x42, 0x84, 0x3c, 0x21, 0x96, 0x9a, 0xd9,
++	0x36, 0xd4, 0x62, 0x01, 0xb0, 0x8b, 0x77, 0xe5,
++	0xcc, 0x1b, 0xd2, 0x12, 0xd2, 0x9c, 0x89, 0x67,
++	0x0c, 0x00, 0x09, 0x56, 0x8c, 0x33, 0x57, 0xf9,
++	0x8c
++};
++
++CK_BYTE buf[1024];
++CK_BYTE sig[128];
++
++static CK_BBOOL truevalue = TRUE;
++static CK_BBOOL falsevalue = FALSE;
++
++int
++main(int argc, char *argv[]) {
++	isc_result_t result;
++	CK_RV rv;
++	CK_SLOT_ID slot = 0;
++	CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
++	CK_ULONG len;
++	CK_ULONG slen; 
++	CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
++	CK_OBJECT_CLASS kClass = CKO_PRIVATE_KEY;
++	CK_KEY_TYPE kType = CKK_RSA;
++	CK_ATTRIBUTE kTemplate[] =
++	{
++		{ CKA_CLASS, &kClass, (CK_ULONG) sizeof(kClass) },
++		{ CKA_KEY_TYPE, &kType, (CK_ULONG) sizeof(kType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_MODULUS, modulus, (CK_ULONG) sizeof(modulus) },
++		{ CKA_PUBLIC_EXPONENT, pubexp, (CK_ULONG) sizeof(pubexp) },
++		{ CKA_PRIVATE_EXPONENT, privexp, (CK_ULONG) sizeof(privexp) },
++		{ CKA_PRIME_1, prime1, (CK_ULONG) sizeof(prime1) },
++		{ CKA_PRIME_2, prime2, (CK_ULONG) sizeof(prime2) },
++		{ CKA_EXPONENT_1, exp_1, (CK_ULONG) sizeof(exp_1) },
++		{ CKA_EXPONENT_2, exp_2, (CK_ULONG) sizeof(exp_2) },
++		{ CKA_COEFFICIENT, coeff, (CK_ULONG) sizeof(coeff) }
++	};
++	CK_MECHANISM mech = { CKM_SHA1_RSA_PKCS, NULL, 0 };
++	pk11_context_t pctx;
++	pk11_optype_t op_type = OP_RSA;
++	char *lib_name = NULL;
++	char *pin = NULL;
++	int error = 0;
++	int c, errflg = 0;
++	int ontoken  = 0;
++	unsigned int count = 1000;
++	unsigned int i;
++	struct timespec starttime;
++	struct timespec endtime;
++
++	while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) {
++		switch (c) {
++		case 'm':
++			lib_name = isc_commandline_argument;
++			break;
++		case 's':
++			op_type = OP_ANY;
++			slot = atoi(isc_commandline_argument);
++			break;
++		case 'p':
++			pin = isc_commandline_argument;
++			break;
++		case 't':
++			ontoken = 1;
++			break;
++		case 'n':
++			count = atoi(isc_commandline_argument);
++			break;
++		case ':':
++			fprintf(stderr,
++				"Option -%c requires an operand\n",
++				isc_commandline_option);
++			errflg++;
++			break;
++		case '?':
++		default:
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
++			errflg++;
++		}
++	}
++
++	if (errflg) {
++		fprintf(stderr, "Usage:\n");
++		fprintf(stderr,
++			"\tsign [-m module] [-s slot] [-p pin] "
++			"[-t] [-n count]\n");
++		exit(1);
++	}
++
++	pk11_result_register();
++
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
++
++	if (pin == NULL)
++		pin = getpassphrase("Enter Pin: ");
++
++	result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_TRUE,
++				  ISC_TRUE, (const char *) pin, slot);
++	if ((result != ISC_R_SUCCESS) &&
++	    (result != PK11_R_NORANDOMSERVICE) &&
++	    (result != PK11_R_NODIGESTSERVICE) &&
++	    (result != PK11_R_NOAESSERVICE)) {
++		fprintf(stderr, "Error initializing PKCS#11: %s\n",
++			isc_result_totext(result));
++		exit(1);
++	}
++
++	if (pin != NULL)
++		memset(pin, 0, strlen((char *)pin));
++
++	hSession = pctx.session;
++
++	/* Create the private RSA key */
++	if (ontoken)
++		kTemplate[2].pValue = &truevalue;
++
++	rv = pkcs_C_CreateObject(hSession, kTemplate, 13, &hKey);
++	if (rv != CKR_OK) {
++		fprintf(stderr, "C_CreateObject: Error = 0x%.8lX\n", rv);
++		goto exit_key;
++	}
++
++	/* Randomize the buffer */
++	len = (CK_ULONG) sizeof(buf);
++	rv = pkcs_C_GenerateRandom(hSession, buf, len);
++	if (rv != CKR_OK) {
++		fprintf(stderr, "C_GenerateRandom: Error = 0x%.8lX\n", rv);
++		goto exit_key;
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) {
++		perror("clock_gettime(start)");
++		goto exit_key;
++	}
++
++	for (i = 0; i < count; i++) {
++		/* Initialize Sign */
++		rv = pkcs_C_SignInit(hSession, &mech, hKey);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_SignInit[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			break;
++		}
++
++		/* Perform Sign */
++		slen = (CK_ULONG) sizeof(sig);
++		rv = pkcs_C_Sign(hSession, buf, len, sig, &slen);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_Sign[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			break;
++		}
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) {
++		perror("clock_gettime(end)");
++		goto exit_key;
++	}
++
++	endtime.tv_sec -= starttime.tv_sec;
++	endtime.tv_nsec -= starttime.tv_nsec;
++	while (endtime.tv_nsec < 0) {
++		endtime.tv_sec -= 1;
++		endtime.tv_nsec += 1000000000;
++	}
++	printf("%u RSA signs in %ld.%09lds\n", i,
++	       endtime.tv_sec, endtime.tv_nsec);
++	if (i > 0)
++		printf("%g RSA signs/s\n",
++		       1024 * i / ((double) endtime.tv_sec +
++				   (double) endtime.tv_nsec / 1000000000.));
++
++    exit_key:
++	if (hKey != CK_INVALID_HANDLE) {
++		rv = pkcs_C_DestroyObject(hSession, hKey);
++		if (rv != CKR_OK)
++			fprintf(stderr,
++				"C_DestroyObject: Error = 0x%.8lX\n",
++				rv);
++	}
++
++	pk11_return_session(&pctx);
++	(void) pk11_finalize();
++
++	exit(error);
++}
+diff --git a/bin/tests/pkcs11/benchmarks/verify.c b/bin/tests/pkcs11/benchmarks/verify.c
+new file mode 100644
+index 0000000..0a8f2c2
+--- /dev/null
++++ b/bin/tests/pkcs11/benchmarks/verify.c
+@@ -0,0 +1,292 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* $Id$ */
++
++/* verify [-m module] [-s $slot] [-p pin] [-t] [-n count] */
++
++/*! \file */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++#include <unistd.h>
++
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/result.h>
++
++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
++#define getpassphrase(x)	getpass(x)
++#endif
++
++#ifndef HAVE_CLOCK_GETTIME
++#ifndef CLOCK_REALTIME
++#define CLOCK_REALTIME 0
++#endif
++
++int
++clock_gettime(int32_t id, struct timespec *tp)
++{
++	struct timeval tv;
++	int result;
++
++	result = gettimeofday(&tv, NULL);
++	if (result)
++		return (result);
++	tp->tv_sec = tv.tv_sec;
++	tp->tv_nsec = (long) tv.tv_usec * 1000;
++	return (result);
++}
++#endif
++
++CK_BYTE modulus[] = {
++	0x00, 0xb7, 0x9c, 0x1f, 0x05, 0xa3, 0xc2, 0x99,
++	0x44, 0x82, 0x20, 0x78, 0x43, 0x7f, 0x5f, 0x3b,
++	0x10, 0xd7, 0x9e, 0x61, 0x42, 0xd2, 0x7a, 0x90,
++	0x50, 0x8a, 0x99, 0x33, 0xe7, 0xca, 0xc8, 0x5f,
++	0x16, 0x1c, 0x56, 0xf8, 0xc1, 0x06, 0x2f, 0x96,
++	0xe7, 0x54, 0xf2, 0x85, 0x89, 0x41, 0x36, 0xf5,
++	0x4c, 0xa4, 0x0d, 0x62, 0xd3, 0x42, 0x51, 0x6b,
++	0x9f, 0xdc, 0x36, 0xcb, 0xad, 0x56, 0xf4, 0xbd,
++	0x2a, 0x60, 0x33, 0xb1, 0x7a, 0x99, 0xad, 0x08,
++	0x9f, 0x95, 0xe8, 0xe5, 0x14, 0xd9, 0x68, 0x79,
++	0xca, 0x4e, 0x72, 0xeb, 0xfb, 0x2c, 0xf1, 0x45,
++	0xd3, 0x33, 0x65, 0xe7, 0xc5, 0x11, 0xdd, 0xe7,
++	0x09, 0x83, 0x13, 0xd5, 0x17, 0x1b, 0xf4, 0xbd,
++	0x49, 0xdd, 0x8a, 0x3c, 0x3c, 0xf7, 0xa1, 0x5d,
++	0x7b, 0xb4, 0xd3, 0x80, 0x25, 0xf4, 0x05, 0x8f,
++	0xbc, 0x2c, 0x2a, 0x47, 0xff, 0xd1, 0xc8, 0x34,
++	0xbf
++};
++CK_BYTE exponent[] = { 0x01, 0x00, 0x01 };
++
++CK_BYTE buf[1024];
++CK_BYTE sig[128];
++
++static CK_BBOOL truevalue = TRUE;
++static CK_BBOOL falsevalue = FALSE;
++
++int
++main(int argc, char *argv[]) {
++	isc_result_t result;
++	CK_RV rv;
++	CK_SLOT_ID slot = 0;
++	CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
++	CK_ULONG len;
++	CK_ULONG slen; 
++	CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
++	CK_OBJECT_CLASS kClass = CKO_PUBLIC_KEY;
++	CK_KEY_TYPE kType = CKK_RSA;
++	CK_ATTRIBUTE kTemplate[] =
++	{
++		{ CKA_CLASS, &kClass, (CK_ULONG) sizeof(kClass) },
++		{ CKA_KEY_TYPE, &kType, (CK_ULONG) sizeof(kType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_MODULUS, modulus, (CK_ULONG) sizeof(modulus) },
++		{ CKA_PUBLIC_EXPONENT, exponent, (CK_ULONG) sizeof(exponent) }
++	};
++	CK_MECHANISM mech = { CKM_SHA1_RSA_PKCS, NULL, 0 };
++	pk11_context_t pctx;
++	pk11_optype_t op_type = OP_RSA;
++	char *lib_name = NULL;
++	char *pin = NULL;
++	int error = 0;
++	int c, errflg = 0;
++	int ontoken  = 0;
++	unsigned int count = 1000;
++	unsigned int i;
++	struct timespec starttime;
++	struct timespec endtime;
++
++	while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) {
++		switch (c) {
++		case 'm':
++			lib_name = isc_commandline_argument;
++			break;
++		case 's':
++			op_type = OP_ANY;
++			slot = atoi(isc_commandline_argument);
++			break;
++		case 'p':
++			pin = isc_commandline_argument;
++			break;
++		case 't':
++			ontoken = 1;
++			break;
++		case 'n':
++			count = atoi(isc_commandline_argument);
++			break;
++		case ':':
++			fprintf(stderr,
++				"Option -%c requires an operand\n",
++				isc_commandline_option);
++			errflg++;
++			break;
++		case '?':
++		default:
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
++			errflg++;
++		}
++	}
++
++	if (errflg) {
++		fprintf(stderr, "Usage:\n");
++		fprintf(stderr,
++			"\tverify [-m module] [-s slot] [-p pin] "
++			"[-t] [-n count]\n");
++		exit(1);
++	}
++
++	pk11_result_register();
++
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
++
++	if (pin == NULL)
++		pin = getpassphrase("Enter Pin: ");
++
++	result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_TRUE,
++				  ISC_TRUE, (const char *) pin, slot);
++	if ((result != ISC_R_SUCCESS) &&
++	    (result != PK11_R_NORANDOMSERVICE) &&
++	    (result != PK11_R_NODIGESTSERVICE) &&
++	    (result != PK11_R_NOAESSERVICE)) {
++		fprintf(stderr, "Error initializing PKCS#11: %s\n",
++			isc_result_totext(result));
++		exit(1);
++	}
++
++	if (pin != NULL)
++		memset(pin, 0, strlen((char *)pin));
++
++	hSession = pctx.session;
++
++	/* Create the private RSA key */
++	if (ontoken)
++		kTemplate[2].pValue = &truevalue;
++
++	rv = pkcs_C_CreateObject(hSession, kTemplate, 7, &hKey);
++	if (rv != CKR_OK) {
++		fprintf(stderr, "C_CreateObject: Error = 0x%.8lX\n", rv);
++		error = 1;
++		goto exit_key;
++	}
++
++	/* Randomize the buffer */
++	len = (CK_ULONG) sizeof(buf);
++	rv = pkcs_C_GenerateRandom(hSession, buf, len);
++	if (rv != CKR_OK) {
++		fprintf(stderr, "C_GenerateRandom: Error = 0x%.8lX\n", rv);
++		goto exit_key;
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) {
++		perror("clock_gettime(start)");
++		goto exit_key;
++	}
++
++	for (i = 0; i < count; i++) {
++		/* Initialize Verify */
++		rv = pkcs_C_VerifyInit(hSession, &mech, hKey);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_VerifyInit[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			break;
++		}
++
++		/* Perform Verify */
++		slen = (CK_ULONG) sizeof(sig);
++		rv = pkcs_C_Verify(hSession, buf, len, sig, slen);
++		if ((rv != CKR_OK) && (rv != CKR_SIGNATURE_INVALID)) {
++			fprintf(stderr,
++				"C_Verify[%u]: Error = 0x%.8lX\n",
++				i, rv);
++			error = 1;
++			break;
++		}
++	}
++
++	if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) {
++		perror("clock_gettime(end)");
++		goto exit_key;
++	}
++
++	endtime.tv_sec -= starttime.tv_sec;
++	endtime.tv_nsec -= starttime.tv_nsec;
++	while (endtime.tv_nsec < 0) {
++		endtime.tv_sec -= 1;
++		endtime.tv_nsec += 1000000000;
++	}
++	printf("%u RSA verify in %ld.%09lds\n", i,
++	       endtime.tv_sec, endtime.tv_nsec);
++	if (i > 0)
++		printf("%g RSA verify/s\n",
++		       1024 * i / ((double) endtime.tv_sec +
++				   (double) endtime.tv_nsec / 1000000000.));
++
++    exit_key:
++	if (hKey != CK_INVALID_HANDLE) {
++		rv = pkcs_C_DestroyObject(hSession, hKey);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_DestroyObject: Error = 0x%.8lX\n",
++				rv);
++			errflg = 1;
++		}
++	}
++
++	pk11_return_session(&pctx);
++	(void) pk11_finalize();
++
++	exit(error);
++}
+diff --git a/bin/tests/pkcs11/pkcs11-hmacmd5.c b/bin/tests/pkcs11/pkcs11-hmacmd5.c
+new file mode 100644
+index 0000000..00a1df1
+--- /dev/null
++++ b/bin/tests/pkcs11/pkcs11-hmacmd5.c
+@@ -0,0 +1,332 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* $Id$ */
++
++/*
++ * pkcs11-hmacmd5
++ *
++ * Prints the MD5 HMAC of the standard input, using the PKCS#11 device.
++ *
++ * Usage:
++ * pkcs11-hmacmd5 [-m module] [-s $slot] [-n] [-p $pin]
++ *  -m: PKCS#11 provider module.  This must be the full
++ *      path to a shared library object implementing the
++ *      PKCS#11 API for a device.
++ *  -s: Slot
++ *  -p: PIN
++ *  -n: don't log in to the PKCS#11 device
++ *  -k: key name for the HMAC
++ */
++
++/*! \file */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <string.h>
++#include <sys/types.h>
++
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/result.h>
++
++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
++#define getpassphrase(x)	getpass(x)
++#endif
++
++/* Define static key template values */
++static CK_BBOOL truevalue = TRUE;
++static CK_BBOOL falsevalue = FALSE;
++
++#define BLOCKSIZE	32768
++
++char buffer[BLOCKSIZE + 72];
++char digest[16];
++
++int
++main(int argc, char *argv[]) {
++	isc_result_t result;
++	CK_RV rv;
++	CK_SLOT_ID slot = 0;
++	CK_SESSION_HANDLE hSession;
++	CK_MECHANISM mech = { CKM_MD5_HMAC, NULL, 0 };
++	CK_ULONG len;
++	CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
++	CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
++	CK_KEY_TYPE keyType = CKK_MD5_HMAC;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_VALUE, NULL, 0 }
++	};
++	pk11_context_t pctx;
++	pk11_optype_t op_type = OP_DIGEST;
++	char *lib_name = NULL;
++	char *pin = NULL;
++	int error = 0;
++	isc_boolean_t logon = ISC_TRUE;
++	int c, errflg = 0;
++	char *key = NULL;
++	size_t sum = 0;
++	unsigned int i;
++
++	while ((c = isc_commandline_parse(argc, argv, ":m:s:np:k:")) != -1) {
++		switch (c) {
++		case 'm':
++			lib_name = isc_commandline_argument;
++			break;
++		case 's':
++			op_type = OP_ANY;
++			slot = atoi(isc_commandline_argument);
++			break;
++		case 'n':
++			logon = ISC_FALSE;
++			break;
++		case 'p':
++			pin = isc_commandline_argument;
++			break;
++		case 'k':
++			key = isc_commandline_argument;
++			break;
++		case ':':
++			fprintf(stderr,
++				"Option -%c requires an operand\n",
++				isc_commandline_option);
++			errflg++;
++			break;
++		case '?':
++		default:
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
++			errflg++;
++		}
++	}
++
++	if (errflg || (key == NULL)) {
++		fprintf(stderr, "Usage:\n");
++		fprintf(stderr,
++			"\tpkcs11-hmacmd5 [-m module] [-s slot] "
++			"[-n|-p pin] -k key\n");
++		exit(1);
++	}
++
++	/* Decode the key */
++	for (i = 0; i < BLOCKSIZE / 2; i++) {
++		switch (c = *key++) {
++		case 0:
++			goto key_done;
++		case '0':
++		case '1':
++		case '2':
++		case '3':
++		case '4':
++		case '5':
++		case '6':
++		case '7':
++		case '8':
++		case '9':
++			if ((i & 1) == 0)
++				buffer[i >> 1] = (c - '0') << 4;
++			else
++				buffer[i >> 1] |= c - '0';
++			break;
++		case 'A':
++		case 'B':
++		case 'C':
++		case 'D':
++		case 'E':
++		case 'F':
++			if ((i & 1) == 0)
++				buffer[i >> 1] = (c - 'A' + 10) << 4;
++			else
++				buffer[i >> 1] |= c - 'A' + 10;
++			break;
++		case 'a':
++		case 'b':
++		case 'c':
++		case 'd':
++		case 'e':
++		case 'f':
++			if ((i & 1) == 0)
++				buffer[i >> 1] = (c - 'a' + 10) << 4;
++			else
++				buffer[i >> 1] |= c - 'a' + 10;
++			break;
++		default:
++			fprintf(stderr, "Not hexdigit '%c' in key\n", c);
++			exit(1);
++		}
++	}
++    key_done:
++	if ((i & 1) != 0) {
++		fprintf(stderr, "Even number of hexdigits in key\n");
++		exit(1);
++	}
++	len = i >> 1;
++	keyTemplate[5].pValue = buffer;
++	keyTemplate[5].ulValueLen = (CK_ULONG) len;
++
++	pk11_result_register();
++
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
++
++	if (logon && pin == NULL)
++		pin = getpassphrase("Enter Pin: ");
++
++	result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_FALSE, logon,
++				  (const char *) pin, slot);
++	if ((result != ISC_R_SUCCESS) &&
++	    (result != PK11_R_NORANDOMSERVICE) &&
++	    (result != PK11_R_NOAESSERVICE)) {
++		fprintf(stderr, "Error initializing PKCS#11: %s\n",
++			isc_result_totext(result));
++		exit(1);
++	}
++
++	if (pin != NULL)
++		memset(pin, 0, strlen((char *)pin));
++
++	hSession = pctx.session;
++
++	rv = pkcs_C_CreateObject(hSession, keyTemplate, (CK_ULONG) 6, &hKey);
++	if (rv != CKR_OK) {
++		fprintf(stderr, "C_CreateObject: Error = 0x%.8lX\n", rv);
++		error = 1;
++		goto exit_session;
++	}
++	if (hKey == CK_INVALID_HANDLE) {
++		fprintf(stderr, "C_CreateObject failed\n");
++		error = 1;
++		goto exit_session;
++	}
++
++	rv = pkcs_C_SignInit(hSession, &mech, hKey);
++	if (rv != CKR_OK) {
++		fprintf(stderr, "C_SignInit: Error = 0x%.8lX\n", rv);
++		error = 1;
++		goto exit_sign;
++	}
++	
++	for (;;) {
++		size_t n;
++
++		for (;;) {
++			n = fread(buffer + sum, 1, BLOCKSIZE - sum, stdin);
++			sum += n;
++			if (sum == BLOCKSIZE)
++				break;
++			if (n == 0) {
++				if (ferror(stdin)) {
++					fprintf(stderr, "fread failed\n");
++					error = 1;
++					goto exit_sign;
++				}
++				goto partial_block;
++			}
++			if (feof(stdin))
++				goto partial_block;
++		}
++
++		rv = pkcs_C_SignUpdate(hSession, (CK_BYTE_PTR) buffer,
++				       (CK_ULONG) BLOCKSIZE);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_SignUpdate: Error = 0x%.8lX\n",
++				rv);
++			error = 1;
++			goto exit_sign;
++		}
++	}
++
++partial_block:
++	if (sum > 0) {
++		rv = pkcs_C_SignUpdate(hSession, (CK_BYTE_PTR) buffer,
++				       (CK_ULONG) sum);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_SignUpdate: Error = 0x%.8lX\n",
++				rv);
++			error = 1;
++			goto exit_sign;
++		}
++	}
++
++	len = 16;
++	rv = pkcs_C_SignFinal(hSession, (CK_BYTE_PTR) digest, &len);
++	if (rv != CKR_OK) {
++		fprintf(stderr, "C_SignFinal: Error = 0x%.8lX\n", rv);
++		error = 1;
++		goto exit_sign;
++	}
++	if (len != 16) {
++		fprintf(stderr, "C_SignFinal: bad length = %lu\n", len);
++		error = 1;
++	}
++
++	for (i = 0; i < 16; i++)
++		printf("%02x", digest[i] & 0xff);
++	printf("\n");
++
++    exit_sign:
++	rv = pkcs_C_DestroyObject(hSession, hKey);
++	if ((error == 0) && (rv != CKR_OK)) {
++		fprintf(stderr, "C_DestroyObject: Error = 0x%.8lX\n", rv);
++		error = 1;
++	}
++
++    exit_session:
++	pk11_return_session(&pctx);
++	(void) pk11_finalize();
++
++	exit(error);
++}
+diff --git a/bin/tests/pkcs11/pkcs11-md5sum.c b/bin/tests/pkcs11/pkcs11-md5sum.c
+new file mode 100644
+index 0000000..fd50648
+--- /dev/null
++++ b/bin/tests/pkcs11/pkcs11-md5sum.c
+@@ -0,0 +1,235 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/* $Id$ */
++
++/*
++ * pkcs11-md5sum
++ *
++ * Prints the MD5 checksum of the standard input, using the PKCS#11 device.
++ *
++ * Usage:
++ * pkcs11-md5sum [-m module] [-s $slot] [-n] [-p $pin]
++ *  -m: PKCS#11 provider module.  This must be the full
++ *      path to a shared library object implementing the
++ *      PKCS#11 API for a device.
++ *  -s: Slot
++ *  -p: PIN
++ *  -n: don't log in to the PKCS#11 device
++ */
++
++/*! \file */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <string.h>
++#include <sys/types.h>
++
++#include <isc/commandline.h>
++#include <isc/result.h>
++#include <isc/types.h>
++
++#include <pk11/pk11.h>
++#include <pk11/result.h>
++
++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun)))
++#define getpassphrase(x)	getpass(x)
++#endif
++
++#define BLOCKSIZE	32768
++
++char buffer[BLOCKSIZE + 72];
++char digest[16];
++
++int
++main(int argc, char *argv[]) {
++	isc_result_t result;
++	CK_RV rv;
++	CK_SLOT_ID slot = 0;
++	CK_SESSION_HANDLE hSession;
++	CK_MECHANISM mech = { CKM_MD5, NULL, 0 };
++	CK_ULONG len;
++	pk11_context_t pctx;
++	pk11_optype_t op_type = OP_DIGEST;
++	char *lib_name = NULL;
++	char *pin = NULL;
++	int error = 0;
++	isc_boolean_t logon = ISC_TRUE;
++	int c, errflg = 0;
++	size_t sum = 0;
++	unsigned int i;
++
++	while ((c = isc_commandline_parse(argc, argv, ":m:s:np:")) != -1) {
++		switch (c) {
++		case 'm':
++			lib_name = isc_commandline_argument;
++			break;
++		case 's':
++			op_type = OP_ANY;
++			slot = atoi(isc_commandline_argument);
++			break;
++		case 'n':
++			logon = ISC_FALSE;
++			break;
++		case 'p':
++			pin = isc_commandline_argument;
++			break;
++		case ':':
++			fprintf(stderr,
++				"Option -%c requires an operand\n",
++				isc_commandline_option);
++			errflg++;
++			break;
++		case '?':
++		default:
++			fprintf(stderr, "Unrecognised option: -%c\n",
++				isc_commandline_option);
++			errflg++;
++		}
++	}
++
++	if (errflg) {
++		fprintf(stderr, "Usage:\n");
++		fprintf(stderr,
++			"\tpkcs11-md5sum [-m module] [-s slot] [-n|-p pin]\n");
++		exit(1);
++	}
++
++	pk11_result_register();
++
++	/* Initialize the CRYPTOKI library */
++	if (lib_name != NULL)
++		pk11_set_lib_name(lib_name);
++
++	if (logon && pin == NULL)
++		pin = getpassphrase("Enter Pin: ");
++
++	result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_FALSE, logon,
++				  (const char *) pin, slot);
++	if ((result != ISC_R_SUCCESS) &&
++	    (result != PK11_R_NORANDOMSERVICE) &&
++	    (result != PK11_R_NOAESSERVICE)) {
++		fprintf(stderr, "Error initializing PKCS#11: %s\n",
++			isc_result_totext(result));
++		exit(1);
++	}
++
++	if (pin != NULL)
++		memset(pin, 0, strlen((char *)pin));
++
++	hSession = pctx.session;
++
++	rv = pkcs_C_DigestInit(hSession, &mech);
++	if (rv != CKR_OK) {
++		fprintf(stderr, "C_DigestInit: Error = 0x%.8lX\n", rv);
++		error = 1;
++		goto exit_session;
++	}
++	
++	for (;;) {
++		size_t n;
++
++		for (;;) {
++			n = fread(buffer + sum, 1, BLOCKSIZE - sum, stdin);
++			sum += n;
++			if (sum == BLOCKSIZE)
++				break;
++			if (n == 0) {
++				if (ferror(stdin)) {
++					fprintf(stderr, "fread failed\n");
++					error = 1;
++					goto exit_session;
++				}
++				goto partial_block;
++			}
++			if (feof(stdin))
++				goto partial_block;
++		}
++
++		rv = pkcs_C_DigestUpdate(hSession, (CK_BYTE_PTR) buffer,
++					 (CK_ULONG) BLOCKSIZE);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_DigestUpdate: Error = 0x%.8lX\n",
++				rv);
++			error = 1;
++			goto exit_session;
++		}
++	}
++
++partial_block:
++	if (sum > 0) {
++		rv = pkcs_C_DigestUpdate(hSession, (CK_BYTE_PTR) buffer,
++					 (CK_ULONG) sum);
++		if (rv != CKR_OK) {
++			fprintf(stderr,
++				"C_DigestUpdate: Error = 0x%.8lX\n",
++				rv);
++			error = 1;
++			goto exit_session;
++		}
++	}
++
++	len = 16;
++	rv = pkcs_C_DigestFinal(hSession, (CK_BYTE_PTR) digest, &len);
++	if (rv != CKR_OK) {
++		fprintf(stderr, "C_DigestFinal: Error = 0x%.8lX\n", rv);
++		error = 1;
++		goto exit_session;
++	}
++	if (len != 16) {
++		fprintf(stderr, "C_DigestFinal: bad length = %lu\n", len);
++		error = 1;
++	}
++
++	for (i = 0; i < 16; i++)
++		printf("%02x", digest[i] & 0xff);
++	printf("\n");
++
++    exit_session:
++	pk11_return_session(&pctx);
++	(void) pk11_finalize();
++
++	exit(error);
++}
+diff --git a/bin/tests/system/autosign/prereq.sh b/bin/tests/system/autosign/prereq.sh
+index 34cd4a1..53807a2 100644
+--- a/bin/tests/system/autosign/prereq.sh
++++ b/bin/tests/system/autosign/prereq.sh
+@@ -25,6 +25,7 @@ if $KEYGEN -q -a RSAMD5 -b 512 -n zone -r random.data foo > /dev/null 2>&1
+ then
+     rm -f Kfoo*
+ else
+-    echo "I:This test requires that --with-openssl was used." >&2
++    echo "I:This test requires cryptography" >&2
++    echo "I:--with-openssl, or --with-pkcs11 and --enable-native-pkcs11" >&2
+     exit 1
+ fi
+diff --git a/bin/tests/system/cleanpkcs11.sh b/bin/tests/system/cleanpkcs11.sh
+index e1cbc6f..ba541ed 100644
+--- a/bin/tests/system/cleanpkcs11.sh
++++ b/bin/tests/system/cleanpkcs11.sh
+@@ -16,6 +16,10 @@
+ 
+ # $Id: cleanpkcs11.sh,v 1.3 2010/06/08 23:50:24 tbox Exp $
+ 
++SYSTEMTESTTOP=.
++. $SYSTEMTESTTOP/conf.sh
++
++
+ if [ ! -x ../../pkcs11/pkcs11-destroy ]; then exit 1; fi
+ 
+-../../pkcs11/pkcs11-destroy -s ${SLOT:-0} -p 1234
++$PK11DEL -w0 > /dev/null 2>&1
+diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in
+index d6e902f..c40e8f1 100644
+--- a/bin/tests/system/conf.sh.in
++++ b/bin/tests/system/conf.sh.in
+@@ -47,9 +47,9 @@ CHECKDS=$TOP/bin/python/dnssec-checkds
+ COVERAGE=$TOP/bin/python/dnssec-coverage
+ CHECKZONE=$TOP/bin/check/named-checkzone
+ CHECKCONF=$TOP/bin/check/named-checkconf
+-PK11GEN="$TOP/bin/pkcs11/pkcs11-keygen -s ${SLOT:-0} -p 1234"
+-PK11LIST="$TOP/bin/pkcs11/pkcs11-list -s ${SLOT:-0} -p 1234"
+-PK11DEL="$TOP/bin/pkcs11/pkcs11-destroy -s ${SLOT:-0} -p 1234"
++PK11GEN="$TOP/bin/pkcs11/pkcs11-keygen -q -s ${SLOT:-0} -p ${HSMPIN:-1234}"
++PK11LIST="$TOP/bin/pkcs11/pkcs11-list -s ${SLOT:-0} -p ${HSMPIN:-1234}"
++PK11DEL="$TOP/bin/pkcs11/pkcs11-destroy -s ${SLOT:-0} -p ${HSMPIN:-1234} -w 0"
+ JOURNALPRINT=$TOP/bin/tools/named-journalprint
+ VERIFY=$TOP/bin/dnssec/dnssec-verify
+ ARPANAME=$TOP/bin/tools/arpaname
+@@ -63,7 +63,7 @@ SUBDIRS="acl additional allow_query addzone autosign builtin
+          database dlv dlvauto dlz dlzexternal dname dns64 dnssec ecdsa
+          formerr forward glue gost ixfr inline limits logfileconfig
+          lwresd masterfile masterformat metadata notify nsupdate pending
+-	 pkcs11 redirect resolver rndc rpz rrl rrsetorder rsabigexponent
++	 @PKCS11_TEST@ redirect resolver rndc rpz rrl rrsetorder rsabigexponent
+ 	 smartsign sortlist spf staticstub stub tkey tsig tsiggss unknown
+ 	 upforwd verify views wildcard xfer xferquota zero zonechecks"
+ 
+diff --git a/bin/tests/system/dnssec/prereq.sh b/bin/tests/system/dnssec/prereq.sh
+index cb7c0c7..113e372 100644
+--- a/bin/tests/system/dnssec/prereq.sh
++++ b/bin/tests/system/dnssec/prereq.sh
+@@ -23,6 +23,7 @@ if $KEYGEN -q -a RSAMD5 -b 512 -n zone -r random.data foo > /dev/null 2>&1
+ then
+     rm -f Kfoo*
+ else
+-    echo "I:This test requires that --with-openssl was used." >&2
++    echo "I:This test requires cryptography" >&2
++    echo "I:--with-openssl, or --with-pkcs11 and --enable-native-pkcs11" >&2
+     exit 1
+ fi
+diff --git a/bin/tests/system/ecdsa/prereq.sh.in b/bin/tests/system/ecdsa/prereq.sh.in
+index 434b53c..4214a30 100644
+--- a/bin/tests/system/ecdsa/prereq.sh.in
++++ b/bin/tests/system/ecdsa/prereq.sh.in
+@@ -16,9 +16,16 @@
+ 
+ # $Id$
+ 
+-OPENSSL_ECDSA="@OPENSSL_ECDSA@"
+-if test -z "$OPENSSL_ECDSA"
+-then
+-    echo "I:This test requires a openssl version with ecdsa support." >&2
++SYSTEMTESTTOP=..
++. $SYSTEMTESTTOP/conf.sh
++../../../tools/genrandom 400 random.data
++
++fail=0
++$KEYGEN -q -a ecdsap256sha256 test > /dev/null 2>&1 || fail=1
++rm -f Ktest* random.data
++
++if [ $fail != 0 ]
++ then
++    echo "I:This test requires support for ECDSA cryptography." >&2
+     exit 255
+ fi
+diff --git a/bin/tests/system/gost/prereq.sh.in b/bin/tests/system/gost/prereq.sh.in
+index 98ec507..0e4079e 100644
+--- a/bin/tests/system/gost/prereq.sh.in
++++ b/bin/tests/system/gost/prereq.sh.in
+@@ -16,9 +16,16 @@
+ 
+ # $Id: prereq.sh.in,v 1.4 2010/12/27 13:38:43 marka Exp $
+ 
+-OPENSSL_GOST="@OPENSSL_GOST@"
+-if test -z "$OPENSSL_GOST"
+-then
+-    echo "I:This test requires a openssl version with gost support." >&2
++SYSTEMTESTTOP=..
++. $SYSTEMTESTTOP/conf.sh
++../../../tools/genrandom 400 random.data
++
++fail=0
++$KEYGEN -q -a eccgost test > /dev/null 2>&1 || fail=1
++rm -f Ktest* random.data
++
++if [ $fail != 0 ]
++ then
++    echo "I:This test requires support for GOST cryptography." >&2
+     exit 255
+ fi
+diff --git a/bin/tests/system/inline/clean.sh b/bin/tests/system/inline/clean.sh
+index dae21e5..b6dda0b 100644
+--- a/bin/tests/system/inline/clean.sh
++++ b/bin/tests/system/inline/clean.sh
+@@ -74,7 +74,7 @@ rm -f ns5/bits.bk.signed
+ rm -f ns5/bits.bk.signed.jnl
+ rm -f */*.jbk
+ rm -f random.data
+-rm -f dig.out.ns*.test*
++rm -f dig.out.ns*
+ rm -f signing.out*
+ rm -f freeze.test*
+ rm -f thaw.test*
+diff --git a/bin/tests/system/metadata/prereq.sh b/bin/tests/system/metadata/prereq.sh
+index b7ce1ea..006bcf5 100644
+--- a/bin/tests/system/metadata/prereq.sh
++++ b/bin/tests/system/metadata/prereq.sh
+@@ -22,6 +22,7 @@ if $KEYGEN -q -r random.data foo > /dev/null 2>&1
+ then
+     rm -f Kfoo*
+ else
+-    echo "I:This test requires that --with-openssl was used." >&2
++    echo "I:This test requires cryptography" >&2
++    echo "I:--with-openssl, or --with-pkcs11 and --enable-native-pkcs11" >&2
+     exit 1
+ fi
+diff --git a/bin/tests/system/pending/prereq.sh b/bin/tests/system/pending/prereq.sh
+index 0b6998e..f0848d7 100644
+--- a/bin/tests/system/pending/prereq.sh
++++ b/bin/tests/system/pending/prereq.sh
+@@ -16,12 +16,25 @@
+ 
+ # $Id: prereq.sh,v 1.3 2009/11/18 23:48:06 tbox Exp $
+ 
++SYSTEMTESTTOP=..
++. $SYSTEMTESTTOP/conf.sh
+ ../../../tools/genrandom 400 random.data
+ 
+-if $KEYGEN -q -a RSAMD5 -b 512 -n zone -r random.data foo > /dev/null 2>&1
+-then
+-    rm -f Kfoo*
++rsafail=0 eccfail=0
++
++$KEYGEN -q -r random.data foo > /dev/null 2>&1 || rsafail=1
++rm -f Kfoo*
++
++$KEYGEN -q -a ECDSAP256SHA256 -r random.data foo > /dev/null 2>&1 || eccfail=1
++rm -f Kfoo*
++
++if [ $rsafail = 0 -a $eccfail = 0 ]; then
++	echo both > supported
++elif [ $rsafail = 1 -a $eccfail = 1 ]; then
++	echo "I:This test requires PKCS#11 support for either RSA or ECDSA cryptography." >&2
++	exit 255
++elif [ $rsafail = 0 ]; then
++	echo rsaonly > supported
+ else
+-    echo "I:This test requires that --with-openssl was used." >&2
+-    exit 1
++    echo ecconly > supported
+ fi
+diff --git a/bin/tests/system/pkcs11/clean.sh b/bin/tests/system/pkcs11/clean.sh
+index d7a557b..29d0149 100644
+--- a/bin/tests/system/pkcs11/clean.sh
++++ b/bin/tests/system/pkcs11/clean.sh
+@@ -17,5 +17,6 @@
+ # $Id: clean.sh,v 1.3 2010/06/08 23:50:24 tbox Exp $
+ 
+ rm -f K* ns1/K* keyset-* dsset-* ns1/*.db ns1/*.signed ns1/*.jnl
+-rm -f dig.out random.data
+-rm -f ns1/key ns1/named.memstats
++rm -f dig.out random.data pin
++rm -f ns1/*.key ns1/named.memstats
++rm -f supported
+diff --git a/bin/tests/system/pkcs11/ns1/named.conf b/bin/tests/system/pkcs11/ns1/named.conf
+index 09a850f..48b8adf 100644
+--- a/bin/tests/system/pkcs11/ns1/named.conf
++++ b/bin/tests/system/pkcs11/ns1/named.conf
+@@ -39,8 +39,14 @@ controls {
+ 	inet 10.53.0.1 port 9953 allow { any; } keys { rndc_key; };
+ };
+ 
+-zone "example." {
++zone "rsa.example." {
++ 	type master;
++	file "rsa.example.db.signed";
++	allow-update { any; };
++};
++
++zone "ecc.example." {
+ 	type master;
+-	file "example.db.signed";
++	file "ecc.example.db.signed";
+ 	allow-update { any; };
+ };
+diff --git a/bin/tests/system/pkcs11/setup.sh b/bin/tests/system/pkcs11/setup.sh
+index c044d75..a17a83d 100644
+--- a/bin/tests/system/pkcs11/setup.sh
++++ b/bin/tests/system/pkcs11/setup.sh
+@@ -21,21 +21,59 @@ SYSTEMTESTTOP=..
+ 
+ RANDFILE=random.data
+ 
+-zone=example
+ infile=ns1/example.db.in
+-zonefile=ns1/example.db
+ 
+-$PK11GEN -b 1024 -l robie-zsk1 -i 01
+-$PK11GEN -b 1024 -l robie-zsk2 -i 02
+-$PK11GEN -b 2048 -l robie-ksk
++/bin/echo -n ${HSMPIN:-1234}> pin
++PWD=`pwd`
+ 
+-zsk1=`$KEYFRLAB -a RSASHA1 -l robie-zsk1 example`
+-zsk2=`$KEYFRLAB -a RSASHA1 -l robie-zsk2 example`
+-ksk=`$KEYFRLAB -a RSASHA1 -f ksk -l robie-ksk example`
++supported=`cat supported`
+ 
+-cat $infile $zsk1.key $ksk.key > $zonefile
+-$SIGNER -a -P -g -r $RANDFILE -o $zone $zonefile > /dev/null 2> signer.err || cat signer.err
+-rm -f signer.err
++zone=rsa.example
++zonefile=ns1/rsa.example.db
++if [ "$supported" != "ecconly" ]; then
++    $PK11GEN -a RSA -b 1024 -l robie-rsa-zsk1 -i 01
++    $PK11GEN -a RSA -b 1024 -l robie-rsa-zsk2 -i 02
++    $PK11GEN -a RSA -b 2048 -l robie-rsa-ksk
++
++    rsazsk1=`$KEYFRLAB -a RSASHA1 \
++            -l "object=robie-rsa-zsk1;pin-source=$PWD/pin" rsa.example`
++    rsazsk2=`$KEYFRLAB -a RSASHA1 \
++            -l "object=robie-rsa-zsk2;pin-source=$PWD/pin" rsa.example`
++    rsaksk=`$KEYFRLAB -a RSASHA1 -f ksk \
++            -l "object=robie-rsa-ksk;pin-source=$PWD/pin" rsa.example`
++
++    cat $infile $rsazsk1.key $rsaksk.key > $zonefile
++    $SIGNER -a -P -g -r $RANDFILE -o $zone $zonefile \
++            > /dev/null 2> signer.err || cat signer.err
++    cp $rsazsk2.key ns1/rsa.key
++    mv Krsa* ns1
++else
++    # RSA not available and will not be tested; make a placeholder
++    cp $infile ${zonefile}.signed
++fi
++
++zone=ecc.example
++zonefile=ns1/ecc.example.db
++if [ "$supported" != "rsaonly" ]; then
++    $PK11GEN -a ECC -b 256 -l robie-ecc-zsk1 -i 03
++    $PK11GEN -a ECC -b 256 -l robie-ecc-zsk2 -i 04
++    $PK11GEN -a ECC -b 384 -l robie-ecc-ksk
+ 
+-cp $zsk2.key ns1/key
+-mv Kexample* ns1
++    ecczsk1=`$KEYFRLAB -a ECDSAP256SHA256 \
++            -l "object=robie-ecc-zsk1;pin-source=$PWD/pin" ecc.example`
++    ecczsk2=`$KEYFRLAB -a ECDSAP256SHA256 \
++            -l "object=robie-ecc-zsk2;pin-source=$PWD/pin" ecc.example`
++    eccksk=`$KEYFRLAB -a ECDSAP384SHA384 -f ksk \
++            -l "object=robie-ecc-ksk;pin-source=$PWD/pin" ecc.example`
++
++    cat $infile $ecczsk1.key $eccksk.key > $zonefile
++    $SIGNER -a -P -g -r $RANDFILE -o $zone $zonefile \
++        > /dev/null 2> signer.err || cat signer.err
++    cp $ecczsk2.key ns1/ecc.key
++    mv Kecc* ns1
++else
++    # ECC not available and will not be tested; make a placeholder
++    cp $infile ${zonefile}.signed
++fi
++
++rm -f signer.err
+diff --git a/bin/tests/system/pkcs11/tests.sh b/bin/tests/system/pkcs11/tests.sh
+index 4694afc..01f1523 100644
+--- a/bin/tests/system/pkcs11/tests.sh
++++ b/bin/tests/system/pkcs11/tests.sh
+@@ -26,47 +26,59 @@ DIGOPTS="+tcp +noadd +nosea +nostat +nocmd +dnssec -p 5300"
+ status=0
+ ret=0
+ 
+-zonefile=ns1/example.db
++supported=`cat supported`
++case $supported in
++    rsaonly) algs="rsa" ;;
++    ecconly) algs="ecc" ;;
++    both) algs="rsa ecc" ;;
++esac
+ 
+-echo "I:testing PKCS#11 key generation"
++for alg in $algs; do
++    zonefile=ns1/$alg.example.db 
++    echo "I:testing PKCS#11 key generation ($alg)"
++    count=`$PK11LIST | grep robie-$alg-ksk | wc -l`
++    if [ $count != 2 ]; then echo "I:failed"; status=1; fi
+ 
+-count=`$PK11LIST | grep robie-ksk | wc -l`
+-if [ $count != 2 ]; then echo "I:failed"; status=1; fi
++    echo "I:testing offline signing with PKCS#11 keys ($alg)"
+ 
+-echo "I:testing offline signing with PKCS#11 keys"
++    count=`grep RRSIG $zonefile.signed | wc -l`
++    if [ $count != 12 ]; then echo "I:failed"; status=1; fi
+ 
+-count=`grep RRSIG $zonefile.signed | wc -l`
+-if [ $count != 12 ]; then echo "I:failed"; status=1; fi
++    echo "I:testing inline signing with PKCS#11 keys ($alg)"
+ 
+-echo "I:testing inline signing with PKCS#11 keys"
++    $NSUPDATE > /dev/null <<END || status=1
+ 
+-$NSUPDATE > /dev/null <<END || status=1
+ server 10.53.0.1 5300
+ ttl 300
+-zone example.
+-update add `grep -v ';' ns1/key`
++zone $alg.example.
++update add `grep -v ';' ns1/${alg}.key`
+ send
+ END
+ 
+-echo "I:waiting 20 seconds for key changes to take effect"
+-sleep 20
+-
+-$DIG $DIGOPTS ns.example. @10.53.0.1 a > dig.out || ret=1
+-if [ $ret != 0 ]; then echo "I:failed"; fi
+-status=`expr $status + $ret`
+-count=`grep RRSIG dig.out | wc -l`
+-if [ $count != 4 ]; then echo "I:failed"; status=1; fi
+-
+-echo "I:testing PKCS#11 key destroy"
+-
+-ret=0
+-$PK11DEL -l robie-zsk1 || ret=1
+-$PK11DEL -i 02 || ret=1
+-if [ $ret != 0 ]; then echo "I:failed"; fi
+-status=`expr $status + $ret`
+-count=`$PK11LIST | grep robie-zsk | wc -l`
+-if [ $count != 0 ]; then echo "I:failed"; fi
+-status=`expr $status + $count`
++    echo "I:waiting 20 seconds for key changes to take effect"
++    sleep 20
++
++    $DIG $DIGOPTS ns.$alg.example. @10.53.0.1 a > dig.out || ret=1
++    if [ $ret != 0 ]; then echo "I:failed"; fi
++    status=`expr $status + $ret`
++    count=`grep RRSIG dig.out | wc -l`
++    if [ $count != 4 ]; then echo "I:failed"; status=1; fi
++
++    echo "I:testing PKCS#11 key destroy ($alg)"
++    ret=0
++    $PK11DEL -l robie-$alg-ksk -w0 > /dev/null 2>&1 || ret=1
++    $PK11DEL -l robie-$alg-zsk1 -w0 > /dev/null 2>&1 || ret=1
++    case $alg in
++        rsa) id=02 ;;
++        ecc) id=04 ;;
++    esac
++    $PK11DEL -i $id -w0 > /dev/null 2>&1 || ret=1
++    if [ $ret != 0 ]; then echo "I:failed"; fi
++    status=`expr $status + $ret`
++    count=`$PK11LIST | grep robie-$alg | wc -l`
++    if [ $count != 0 ]; then echo "I:failed"; fi
++    status=`expr $status + $count`
++done
+ 
+ echo "I:exit status: $status"
+ exit $status
+diff --git a/bin/tests/system/pkcs11ssl/clean.sh b/bin/tests/system/pkcs11ssl/clean.sh
+new file mode 100644
+index 0000000..14ec725
+--- /dev/null
++++ b/bin/tests/system/pkcs11ssl/clean.sh
+@@ -0,0 +1,20 @@
++#!/bin/sh
++#
++# Copyright (C) 2010, 2012  Internet Systems Consortium, Inc. ("ISC")
++#
++# Permission to use, copy, modify, and/or distribute this software for any
++# purpose with or without fee is hereby granted, provided that the above
++# copyright notice and this permission notice appear in all copies.
++#
++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++# PERFORMANCE OF THIS SOFTWARE.
++
++rm -f K* ns1/K* keyset-* dsset-* ns1/*.db ns1/*.signed ns1/*.jnl
++rm -f dig.out random.data pin
++rm -f ns1/*.key ns1/named.memstats
++rm -f supported
+diff --git a/bin/tests/system/pkcs11ssl/ns1/example.db.in b/bin/tests/system/pkcs11ssl/ns1/example.db.in
+new file mode 100644
+index 0000000..7166fa8
+--- /dev/null
++++ b/bin/tests/system/pkcs11ssl/ns1/example.db.in
+@@ -0,0 +1,29 @@
++; Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
++;
++; Permission to use, copy, modify, and/or distribute this software for any
++; purpose with or without fee is hereby granted, provided that the above
++; copyright notice and this permission notice appear in all copies.
++;
++; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++; AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++; PERFORMANCE OF THIS SOFTWARE.
++
++; $Id: example.db.in,v 1.3 2010/06/08 23:50:24 tbox Exp $
++
++$TTL 300	; 5 minutes
++@			IN SOA	ns root (
++				2000082401 ; serial
++				1800       ; refresh (30 minutes)
++				1800       ; retry (30 minutes)
++				1814400    ; expire (3 weeks)
++				3600       ; minimum (1 hour)
++				)
++			NS	ns
++ns			A	10.53.0.1
++
++txt			TXT	"recursed"
++
+diff --git a/bin/tests/system/pkcs11ssl/ns1/named.conf b/bin/tests/system/pkcs11ssl/ns1/named.conf
+new file mode 100644
+index 0000000..90b8117
+--- /dev/null
++++ b/bin/tests/system/pkcs11ssl/ns1/named.conf
+@@ -0,0 +1,52 @@
++/*
++ * Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* $Id: named.conf,v 1.3 2010/06/08 23:50:24 tbox Exp $ */
++
++controls { /* empty */ };
++
++options {
++	query-source address 10.53.0.1;
++	notify-source 10.53.0.1;
++	transfer-source 10.53.0.1;
++	port 5300;
++	pid-file "named.pid";
++	listen-on { 10.53.0.1; };
++	listen-on-v6 { none; };
++	recursion no;
++	notify no;
++};
++
++key rndc_key {
++	secret "1234abcd8765";
++	algorithm hmac-md5;
++};
++
++controls {
++	inet 10.53.0.1 port 9953 allow { any; } keys { rndc_key; };
++};
++
++zone "rsa.example." {
++	type master;
++	file "rsa.example.db.signed";
++	allow-update { any; };
++};
++
++zone "ecc.example." {
++	type master;
++	file "ecc.example.db.signed";
++	allow-update { any; };
++};
+diff --git a/bin/tests/system/pkcs11ssl/prereq.sh b/bin/tests/system/pkcs11ssl/prereq.sh
+new file mode 100644
+index 0000000..b5133f4
+--- /dev/null
++++ b/bin/tests/system/pkcs11ssl/prereq.sh
+@@ -0,0 +1,34 @@
++#!/bin/sh
++#
++# Copyright (C) 2010, 2012  Internet Systems Consortium, Inc. ("ISC")
++#
++# Permission to use, copy, modify, and/or distribute this software for any
++# purpose with or without fee is hereby granted, provided that the above
++# copyright notice and this permission notice appear in all copies.
++#
++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++# PERFORMANCE OF THIS SOFTWARE.
++
++# $Id: prereq.sh,v 1.3 2010/06/08 23:50:24 tbox Exp $
++
++SYSTEMTESTTOP=..
++. $SYSTEMTESTTOP/conf.sh
++../../../tools/genrandom 400 random.data
++
++echo rsaonly > supported
++exit 0
++
++rsafail=0 eccfail=0
++
++$KEYGEN -q -r random.data foo > /dev/null 2>&1 || rsafail=1
++rm -f Kfoo*
++
++if [ $rsafail = 1 ]; then
++	echo "I:This test requires OpenSSL built with PKCS#11 support." >&2
++	exit 255
++fi
+diff --git a/bin/tests/system/pkcs11ssl/setup.sh b/bin/tests/system/pkcs11ssl/setup.sh
+new file mode 100644
+index 0000000..c13b275
+--- /dev/null
++++ b/bin/tests/system/pkcs11ssl/setup.sh
+@@ -0,0 +1,46 @@
++#!/bin/sh
++#
++# Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
++#
++# Permission to use, copy, modify, and/or distribute this software for any
++# purpose with or without fee is hereby granted, provided that the above
++# copyright notice and this permission notice appear in all copies.
++#
++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++# PERFORMANCE OF THIS SOFTWARE.
++
++SYSTEMTESTTOP=..
++. $SYSTEMTESTTOP/conf.sh
++
++RANDFILE=random.data
++infile=ns1/example.db.in
++
++/bin/echo -n ${HSMPIN:-1234}> pin
++PWD=`pwd`
++
++zone=rsa.example
++zonefile=ns1/rsa.example.db
++
++$PK11GEN -a RSA -b 1024 -l robie-rsa-zsk1 -i 01
++$PK11GEN -a RSA -b 1024 -l robie-rsa-zsk2 -i 02
++$PK11GEN -a RSA -b 2048 -l robie-rsa-ksk
++
++rsazsk1=`$KEYFRLAB -a RSASHA1 \
++        -l "robie-rsa-zsk1" rsa.example`
++rsazsk2=`$KEYFRLAB -a RSASHA1 \
++        -l "robie-rsa-zsk2" rsa.example`
++rsaksk=`$KEYFRLAB -a RSASHA1 -f ksk \
++        -l "robie-rsa-ksk" rsa.example`
++
++cat $infile $rsazsk1.key $rsaksk.key > $zonefile
++$SIGNER -a -P -g -r $RANDFILE -o $zone $zonefile \
++        > /dev/null 2> signer.err || cat signer.err
++cp $rsazsk2.key ns1/rsa.key
++mv Krsa* ns1
++
++rm -f signer.err
+diff --git a/bin/tests/system/pkcs11ssl/tests.sh b/bin/tests/system/pkcs11ssl/tests.sh
+new file mode 100644
+index 0000000..7785d5a
+--- /dev/null
++++ b/bin/tests/system/pkcs11ssl/tests.sh
+@@ -0,0 +1,71 @@
++#!/bin/sh
++#
++# Copyright (C) 2010, 2012  Internet Systems Consortium, Inc. ("ISC")
++#
++# Permission to use, copy, modify, and/or distribute this software for any
++# purpose with or without fee is hereby granted, provided that the above
++# copyright notice and this permission notice appear in all copies.
++#
++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++# PERFORMANCE OF THIS SOFTWARE.
++
++# $Id: tests.sh,v 1.3 2010/06/08 23:50:24 tbox Exp $
++
++SYSTEMTESTTOP=..
++. $SYSTEMTESTTOP/conf.sh
++
++RANDFILE=random.data
++
++DIGOPTS="+tcp +noadd +nosea +nostat +nocmd +dnssec -p 5300"
++
++status=0
++ret=0
++
++alg=rsa
++zonefile=ns1/rsa.example.db 
++echo "I:testing PKCS#11 key generation (rsa)"
++count=`$PK11LIST | grep robie-rsa-ksk | wc -l`
++if [ $count != 2 ]; then echo "I:failed"; status=1; fi
++
++echo "I:testing offline signing with PKCS#11 keys (rsa)"
++
++count=`grep RRSIG $zonefile.signed | wc -l`
++if [ $count != 12 ]; then echo "I:failed"; status=1; fi
++
++echo "I:testing inline signing with PKCS#11 keys (rsa)"
++
++$NSUPDATE > /dev/null <<END || status=1
++server 10.53.0.1 5300
++ttl 300
++zone rsa.example.
++update add `grep -v ';' ns1/${alg}.key`
++send
++END
++
++echo "I:waiting 20 seconds for key changes to take effect"
++sleep 20
++
++$DIG $DIGOPTS ns.rsa.example. @10.53.0.1 a > dig.out || ret=1
++if [ $ret != 0 ]; then echo "I:failed"; fi
++status=`expr $status + $ret`
++count=`grep RRSIG dig.out | wc -l`
++if [ $count != 4 ]; then echo "I:failed"; status=1; fi
++
++echo "I:testing PKCS#11 key destroy (rsa)"
++ret=0
++$PK11DEL -l robie-rsa-ksk -w0 > /dev/null 2>&1 || ret=1
++$PK11DEL -l robie-rsa-zsk1 -w0 > /dev/null 2>&1 || ret=1
++$PK11DEL -i $id -w0 > /dev/null 2>&1 || ret=1
++if [ $ret != 0 ]; then echo "I:failed"; fi
++status=`expr $status + $ret`
++count=`$PK11LIST | grep robie-rsa | wc -l`
++if [ $count != 0 ]; then echo "I:failed"; fi
++status=`expr $status + $count`
++
++echo "I:exit status: $status"
++exit $status
+diff --git a/bin/tests/system/pkcs11ssl/usepkcs11 b/bin/tests/system/pkcs11ssl/usepkcs11
+new file mode 100644
+index 0000000..ef46412
+--- /dev/null
++++ b/bin/tests/system/pkcs11ssl/usepkcs11
+@@ -0,0 +1 @@
++This test relies on PKCS#11!
+diff --git a/bin/tests/system/rsabigexponent/Makefile.in b/bin/tests/system/rsabigexponent/Makefile.in
+index d32eb15..ce8958b 100644
+--- a/bin/tests/system/rsabigexponent/Makefile.in
++++ b/bin/tests/system/rsabigexponent/Makefile.in
+@@ -24,7 +24,7 @@ top_srcdir =	@top_srcdir@
+ 
+ CINCLUDES =	${DNS_INCLUDES} ${ISC_INCLUDES} @DST_OPENSSL_INC@
+ 
+-CDEFINES =	@USE_OPENSSL@
++CDEFINES =	@CRYPTO@
+ CWARNINGS =
+ 
+ DNSLIBS =	../../../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@
+diff --git a/bin/tests/system/rsabigexponent/bigkey.c b/bin/tests/system/rsabigexponent/bigkey.c
+index aa2e8ec..436254c 100644
+--- a/bin/tests/system/rsabigexponent/bigkey.c
++++ b/bin/tests/system/rsabigexponent/bigkey.c
+@@ -16,7 +16,7 @@
+ 
+ /* $Id$ */
+ 
+-#ifdef OPENSSL
++#if defined(OPENSSL) || defined(PKCS11CRYPTO)
+ #include <config.h>
+ 
+ #include <stdio.h>
+@@ -44,8 +44,16 @@
+ #include <dst/dst.h>
+ #include <dst/result.h>
+ 
++#ifdef OPENSSL
+ #include <openssl/opensslv.h>
+ #if OPENSSL_VERSION_NUMBER <= 0x00908000L
++#define USE_FIX_KEY_FILES
++#endif
++#else
++#define USE_FIX_KEY_FILES
++#endif
++
++#ifdef USE_FIX_KEY_FILES
+ 
+ /*
+  * Use a fixed key file pair if OpenSSL doesn't support > 32 bit exponents.
+@@ -235,16 +243,16 @@ main(int argc, char **argv) {
+ }
+ #endif
+ 
+-#else /* OPENSSL */
++#else /* OPENSSL || PKCS11CRYPTO */
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
+ 
+ int
+-main(int argc, char **argv) {
+-	fprintf(stderr, "Compiled without OpenSSL\n");
++main() {
++	fprintf(stderr, "Compiled without Crypto\n");
+ 	exit(1);
+ }
+ 
+-#endif /* OPENSSL */
++#endif /* OPENSSL || PKCS11CRYPTO */
+ /*! \file */
+diff --git a/bin/tests/system/rsabigexponent/prereq.sh b/bin/tests/system/rsabigexponent/prereq.sh
+index 8edbf1d..6259fb6 100644
+--- a/bin/tests/system/rsabigexponent/prereq.sh
++++ b/bin/tests/system/rsabigexponent/prereq.sh
+@@ -22,6 +22,7 @@ if ./bigkey > /dev/null 2>&1
+ then
+     rm -f Kexample.*
+ else
+-    echo "I:This test requires that --with-openssl was used." >&2
++    echo "I:This test requires cryptography" >&2
++    echo "I:--with-openssl, or --with-pkcs11 and --enable-native-pkcs11" >&2
+     exit 1
+ fi
+diff --git a/bin/tests/system/smartsign/prereq.sh b/bin/tests/system/smartsign/prereq.sh
+index e47b769..9ed2fa8 100644
+--- a/bin/tests/system/smartsign/prereq.sh
++++ b/bin/tests/system/smartsign/prereq.sh
+@@ -22,6 +22,7 @@ if $KEYGEN -q -r random.data foo > /dev/null 2>&1
+ then
+     rm -f Kfoo*
+ else
+-    echo "I:This test requires that --with-openssl was used." >&2
++    echo "I:This test requires cryptography" >&2
++    echo "I:--with-openssl, or --with-pkcs11 and --enable-native-pkcs11" >&2
+     exit 1
+ fi
+diff --git a/bin/tests/system/tkey/keycreate.c b/bin/tests/system/tkey/keycreate.c
+index ff2c2ee..af17582 100644
+--- a/bin/tests/system/tkey/keycreate.c
++++ b/bin/tests/system/tkey/keycreate.c
+@@ -228,6 +228,7 @@ main(int argc, char *argv[]) {
+ 	dns_result_register();
+ 
+ 	mctx = NULL;
++	isc_mem_debugging = ISC_MEM_DEBUGRECORD;
+ 	RUNCHECK(isc_mem_create(0, 0, &mctx));
+ 
+ 	ectx = NULL;
+diff --git a/bin/tests/system/tkey/prereq.sh b/bin/tests/system/tkey/prereq.sh
+index fca4a27..66295fe 100644
+--- a/bin/tests/system/tkey/prereq.sh
++++ b/bin/tests/system/tkey/prereq.sh
+@@ -23,6 +23,7 @@ if $KEYGEN -a RSAMD5 -b 512 -n zone -r random.data foo > /dev/null 2>&1
+ then
+     rm -f foo*
+ else
+-    echo "I:This test requires that --with-openssl was used." >&2
++    echo "I:This test requires cryptography" >&2
++    echo "I:--with-openssl, or --with-pkcs11 and --enable-native-pkcs11" >&2
+     exit 1
+ fi
+diff --git a/config.h.in b/config.h.in
+index 4139e1d..f2eb59a 100644
+--- a/config.h.in
++++ b/config.h.in
+@@ -132,14 +132,11 @@ int sigwait(const unsigned int *set, int *sig);
+ /** define if you have strerror in the C library. */
+ #undef HAVE_STRERROR
+ 
+-/** Define if you are running under Compaq TruCluster. */
+-#undef HAVE_TRUCLUSTER
+-
+ /* Define if OpenSSL includes DSA support */
+ #undef HAVE_OPENSSL_DSA
+ 
+-/* Define if OpenSSL includes ECDSA support */
+-#undef HAVE_OPENSSL_ECDSA
++/* Define if you have getpassphrase in the C library. */
++#undef HAVE_GETPASSPHRASE
+ 
+ /* Define to the length type used by the socket API (socklen_t, size_t, int). */
+ #undef ISC_SOCKADDR_LEN_T
+@@ -187,6 +184,9 @@ int sigwait(const unsigned int *set, int *sig);
+ /* Define to 1 if you have the `chroot' function. */
+ #undef HAVE_CHROOT
+ 
++/* Define if clock_gettime is available. */
++#undef HAVE_CLOCK_GETTIME
++
+ /* Define to 1 if you have the <devpoll.h> header file. */
+ #undef HAVE_DEVPOLL_H
+ 
+@@ -292,6 +292,12 @@ int sigwait(const unsigned int *set, int *sig);
+ /* Define if your OpenSSL version supports GOST. */
+ #undef HAVE_OPENSSL_GOST
+ 
++/* Define if your PKCS11 provider supports ECDSA. */
++#undef HAVE_PKCS11_ECDSA
++
++/* Define if your PKCS11 provider supports GOST. */
++#undef HAVE_PKCS11_GOST
++
+ /* Define to 1 if you have the `readline' function. */
+ #undef HAVE_READLINE
+ 
+@@ -418,6 +424,9 @@ int sigwait(const unsigned int *set, int *sig);
+    (O_NDELAY/O_NONBLOCK). */
+ #undef PORT_NONBLOCK
+ 
++/* Define if GOST private keys are encoded in ASN.1. */
++#undef PREFER_GOSTASN1
++
+ /* The size of `void *', as computed by sizeof. */
+ /* #undef SIZEOF_VOID_P */
+ 
+diff --git a/configure.in b/configure.in
+index 8a06905..24eafb7 100644
+--- a/configure.in
++++ b/configure.in
+@@ -640,25 +640,76 @@ AC_ARG_WITH(openssl,
+ 			  (Required for DNSSEC)],
+     use_openssl="$withval", use_openssl="auto")
+ 
++#
++# was --enable-native-pkcs11 specified?
++#  (note it implies both --without-openssl and --with-pkcs11)
++#
++AC_ARG_ENABLE(native-pkcs11,
++	[  --enable-native-pkcs11  use native PKCS11 for all crypto [[default=no]]],
++	want_native_pkcs11="$enableval", want_native_pkcs11="no")
++
++AC_ARG_WITH(pkcs11,
++[  --with-pkcs11[=PATH]      Build with PKCS11 support [yes|no|path]
++                          (PATH is for the PKCS11 provider)],
++   use_pkcs11="$withval", use_pkcs11="auto")
++
+ openssldirs="/usr /usr/local /usr/local/ssl /usr/pkg /usr/sfw"
+ if test "$use_openssl" = "auto"
+ then
+-	for d in $openssldirs
+-	do
+-		if test -f $d/include/openssl/opensslv.h
+-		then
+-			use_openssl=$d
+-			break
+-		fi
+-	done
++    if test "$want_native_pkcs11" = "yes"
++    then
++        use_openssl="native_pkcs11"
++    else
++	    for d in $openssldirs
++    	do
++	    	if test -f $d/include/openssl/opensslv.h
++		    then
++			    use_openssl=$d
++    			break
++		    fi
++    	done
++    fi
+ fi
+ OPENSSL_ECDSA=""
+ OPENSSL_GOST=""
++AC_ARG_WITH(gost,
++[  --with-gost             Crypto GOST [yes|no|raw|asn1].],
++                    with_gost="$withval", with_gost="auto")
++AC_ARG_WITH(ecdsa, [  --with-ecdsa            OpenSSL ECDSA],
++	            with_ecdsa="$withval", with_ecdsa="auto")
++
++gosttype="raw"
++case "$with_gost" in
++	raw)
++		with_gost="yes"
++		;;
++	asn1)
++		AC_DEFINE(PREFER_GOSTASN1, 1,
++			  [Define if GOST private keys are encoded in ASN.1.])
++                gosttype="asn1"
++		with_gost="yes"
++		;;
++	auto|yes|no)
++		;;
++	*)
++		AC_MSG_ERROR(unknown GOST private key encoding)
++		;;
++esac
++
+ case "$use_openssl" in
++    native_pkcs11)
++		AC_MSG_RESULT(disabled because of native PKCS11)
++		DST_OPENSSL_INC=""
++		CRYPTO=""
++		OPENSSLGOSTLINKOBJS=""
++		OPENSSLGOSTLINKSRS=""
++		OPENSSLLINKOBJS=""
++		OPENSSLLINKSRCS=""
++		;;
+ 	no)
+ 		AC_MSG_RESULT(no)
+ 		DST_OPENSSL_INC=""
+-		USE_OPENSSL=""
++		CRYPTO=""
+ 		OPENSSLGOSTLINKOBJS=""
+ 		OPENSSLGOSTLINKSRS=""
+ 		OPENSSLLINKOBJS=""
+@@ -666,7 +717,7 @@ case "$use_openssl" in
+ 		;;
+ 	auto)
+ 		DST_OPENSSL_INC=""
+-		USE_OPENSSL=""
++		CRYPTO=""
+ 		OPENSSLGOSTLINKOBJS=""
+ 		OPENSSLGOSTLINKSRS=""
+ 		OPENSSLLINKOBJS=""
+@@ -676,6 +727,11 @@ case "$use_openssl" in
+ If you don't want OpenSSL, use --without-openssl])
+ 		;;
+ 	*)
++		if test "$want_native_pkcs11" = "yes"
++		then
++                        AC_MSG_RESULT()
++			AC_MSG_ERROR([OpenSSL and native PKCS11 cannot be used together.])
++		fi
+ 		if test "$use_openssl" = "yes"
+ 		then
+ 			# User did not specify a path - guess it
+@@ -697,7 +753,7 @@ If you don't want OpenSSL, use --without-openssl])
+ 		then
+ 			AC_MSG_ERROR(["$use_openssl/include/openssl/opensslv.h" not found])
+ 		fi
+-		USE_OPENSSL='-DOPENSSL'
++		CRYPTO='-DOPENSSL'
+ 		if test "$use_openssl" = "/usr"
+ 		then
+ 			DST_OPENSSL_INC=""
+@@ -733,6 +789,7 @@ If you don't want OpenSSL, use --without-openssl])
+ 		fi
+ 		AC_MSG_RESULT(using OpenSSL from $use_openssl/lib and $use_openssl/include)
+ 
++		saved_cc="$CC"
+ 		saved_cflags="$CFLAGS"
+ 		saved_libs="$LIBS"
+ 		CFLAGS="$CFLAGS $DST_OPENSSL_INC"
+@@ -839,8 +896,7 @@ int main() {
+         [AC_MSG_RESULT(no)
+         have_ecdsa="no"],
+         [AC_MSG_RESULT(using --with-ecdsa)])
+-        AC_ARG_WITH(ecdsa, [  --with-ecdsa            OpenSSL ECDSA],
+-	            with_ecdsa="$withval", with_ecdsa="auto")
++        
+         case "$with_ecdsa" in
+         yes)
+             case "$have_ecdsa" in
+@@ -869,6 +925,15 @@ int main() {
+ 
+         AC_MSG_CHECKING(for OpenSSL GOST support)
+         have_gost=""
++		case "$use_pkcs11" in
++                auto|no)
++                        ;;
++                *)
++                        if $use_threads; then
++                                CC="$CC -pthread"
++                        fi
++                        ;;
++        esac
+         AC_TRY_RUN([
+ #include <openssl/conf.h>
+ #include <openssl/engine.h>
+@@ -896,8 +961,7 @@ int main() {
+         [AC_MSG_RESULT(no)
+         have_gost="no"],
+         [AC_MSG_RESULT(using --with-gost)])
+-        AC_ARG_WITH(gost, [  --with-gost             OpenSSL GOST],
+-                    with_gost="$withval", with_gost="auto")
++        
+         case "$with_gost" in
+         yes)
+             case "$have_gost" in
+@@ -910,7 +974,7 @@ int main() {
+         *)
+             case "$have_gost" in
+             yes|no) ;;
+-            *) AC_MSG_ERROR([need --with-gost=[[yes or no]]]) ;;
++            *) AC_MSG_ERROR([need --with-gost=[[yes, no, raw or asn1]]]) ;;
+             esac
+             ;;
+         esac
+@@ -938,7 +1002,6 @@ esac
+ # it as needed) if it is found.
+ #
+ 
+-AC_SUBST(USE_OPENSSL)
+ AC_SUBST(DST_OPENSSL_INC)
+ AC_SUBST(OPENSSLGOSTLINKOBJS)
+ AC_SUBST(OPENSSLGOSTLINKSRCS)
+@@ -958,7 +1021,7 @@ AC_ARG_ENABLE(openssl-hash,
+ 	want_openssl_hash="$enableval", want_openssl_hash="no")
+ case $want_openssl_hash in
+ 	yes)
+-		if test "$USE_OPENSSL" = ""
++		if test "$CRYPTO" = ""
+ 		then
+ 			AC_MSG_ERROR([No OpenSSL for hash functions])
+ 		fi
+@@ -973,6 +1036,41 @@ esac
+ AC_SUBST(ISC_PLATFORM_OPENSSLHASH)
+ AC_SUBST(ISC_OPENSSL_INC)
+ 
++AC_ARG_WITH(libtool,
++	    [  --with-libtool          use GNU libtool],
++	    use_libtool="$withval", use_libtool="no")
++
++case $use_libtool in
++	yes)
++		AM_PROG_LIBTOOL
++		O=lo
++		A=la
++		LIBTOOL_MKDEP_SED='s;\.o;\.lo;'
++		LIBTOOL_MODE_COMPILE='--mode=compile --tag=CC'
++		LIBTOOL_MODE_INSTALL='--mode=install --tag=CC'
++		LIBTOOL_MODE_LINK='--mode=link --tag=CC'
++		case "$host" in
++		*) LIBTOOL_ALLOW_UNDEFINED= ;;
++		esac
++		case "$host" in
++		*-ibm-aix*) LIBTOOL_IN_MAIN="-Wl,-bI:T_testlist.imp" ;;
++		*) LIBTOOL_IN_MAIN= ;;
++		esac;
++		;;
++	*)
++		O=o
++		A=a
++		LIBTOOL=
++		AC_SUBST(LIBTOOL)
++		LIBTOOL_MKDEP_SED=
++		LIBTOOL_MODE_COMPILE=
++		LIBTOOL_MODE_INSTALL=
++		LIBTOOL_MODE_LINK=
++		LIBTOOL_ALLOW_UNDEFINED=
++		LIBTOOL_IN_MAIN=
++		;;
++esac
++
+ #
+ # PKCS11 (aka crypto hardware) support
+ #
+@@ -980,25 +1078,102 @@ AC_SUBST(ISC_OPENSSL_INC)
+ #
+ 
+ AC_MSG_CHECKING(for PKCS11 support)
+-AC_ARG_WITH(pkcs11,
+-[  --with-pkcs11[=PATH]      Build with PKCS11 support [yes|no|path]
+-                          (PATH is for the PKCS11 provider)],
+-   use_pkcs11="$withval", use_pkcs11="no")
++
++if test "$use_pkcs11" = "auto"
++then
++	if test "$want_native_pkcs11" = "yes"
++	then
++		use_pkcs11="yes"
++	else
++		use_pkcs11="no"
++	fi
++fi
+ 
+ case "$use_pkcs11" in
+ 	no|'')
+-		AC_MSG_RESULT(disabled)
+-		USE_PKCS11=''
+-		PKCS11_TOOLS=''
++		AC_MSG_RESULT(no)
++		USE_PKCS11=""
++		PKCS11_TEST=""
++		PKCS11_TOOLS=""
++		ISC_PK11_C=""
++		ISC_PK11_O=""
++		ISC_PK11_API_C=""
++		ISC_PK11_API_O=""
++		ISC_PK11_RESULT_C=""
++		ISC_PK11_RESULT_O=""
++		ISC_ISCPK11_API_C=""
++		ISC_ISCPK11_API_O=""
+ 		;;
+ 	yes|*)
+-		AC_MSG_RESULT(using OpenSSL with PKCS11 support)
++        AC_MSG_RESULT(yes)
++                if ! $use_threads; then
++			AC_MSG_ERROR([PKCS11 requires thread support])
++                fi
++		if test "$CRYPTO" != ""
++		then
++			AC_MSG_CHECKING(for OpenSSL with PKCS11 support)
++                        saved_cc="$CC"
++			saved_cflags="$CFLAGS"
++			saved_libs="$LIBS"
++                        CC="$CC -pthread"
++			CFLAGS="$CFLAGS $DST_OPENSSL_INC"
++			LIBS="$LIBS $DNS_OPENSSL_LIBS"
++			AC_TRY_RUN([
++#include <openssl/conf.h>
++#include <openssl/engine.h>
++int main() {
++	ENGINE *e;
++
++	OPENSSL_config(NULL);
++	e = ENGINE_by_id("pkcs11");
++	if (e == NULL)
++		return (1);
++	if (ENGINE_init(e) <= 0)
++		return (1);
++	return (0);
++}
++],
++			[AC_MSG_RESULT(yes)
++			PKCS11_TEST=pkcs11ssl
++			PKCS11_ENGINE='-DPKCS11_ENGINE="\"pkcs11\""'],
++			[AC_MSG_RESULT(no)
++			PKCS11_TEST=''
++			PKCS11_ENGINE='-DPKCS11_ENGINE=NULL'],
++			[AC_MSG_RESULT(cross compile, defaulting to no)
++			PKCS11_TEST=''
++			PKCS11_ENGINE='-DPKCS11_ENGINE=NULL'])
++                        CC="$saved_cc"
++			CFLAGS="$saved_cflags"
++			LIBS="$saved_libs"
++		else
++			PKCS11_TEST=''
++			PKCS11_ENGINE='-DPKCS11_ENGINE=NULL'
++
++		fi
+ 		USE_PKCS11='-DUSE_PKCS11'
+ 		PKCS11_TOOLS=pkcs11
+-		;;
++		AC_CHECK_FUNC(getpassphrase, AC_DEFINE(HAVE_GETPASSPHRASE),)
++		ISC_PK11_C="pk11.c"
++		ISC_PK11_O="pk11.$O"
++		ISC_PK11_API_C="pk11_api.c"
++		ISC_PK11_API_O="pk11_api.$O"
++		ISC_PK11_RESULT_C="pk11_result.c"
++		ISC_PK11_RESULT_O="pk11_result.$O"
++		ISC_ISCPK11_API_C="unix/pk11_api.c"
++		ISC_ISCPK11_API_O="unix/pk11_api.$O"
++ 		;;
+ esac
+ AC_SUBST(USE_PKCS11)
+ AC_SUBST(PKCS11_TOOLS)
++AC_SUBST(PKCS11_ENGINE)
++AC_SUBST(ISC_PK11_C)
++AC_SUBST(ISC_PK11_O)
++AC_SUBST(ISC_PK11_API_C)
++AC_SUBST(ISC_PK11_API_O)
++AC_SUBST(ISC_PK11_RESULT_C)
++AC_SUBST(ISC_PK11_RESULT_O)
++AC_SUBST(ISC_ISCPK11_API_C)
++AC_SUBST(ISC_ISCPK11_API_O)
+ 
+ AC_MSG_CHECKING(for PKCS11 tools)
+ case "$use_pkcs11" in
+@@ -1006,13 +1181,77 @@ case "$use_pkcs11" in
+ 		AC_MSG_RESULT(disabled)
+ 		PKCS11_PROVIDER="undefined"
+ 		;;
+-       *)
+-		AC_MSG_RESULT(PKCS11 provider is "$use_pkcs11")
++    yes|'')
++		PKCS11_PROVIDER="undefined"
++		AC_MSG_RESULT(enabled)
++		;;
++ 	*)
+ 		PKCS11_PROVIDER="$use_pkcs11"
++		AC_MSG_RESULT([enabled, PKCS11 provider is $PKCS11_PROVIDER])
+ 		;;
+ esac
+ AC_SUBST(PKCS11_PROVIDER)
+ 
++
++PKCS11_ECDSA=""
++PKCS11_GOST=""
++AC_MSG_CHECKING(for native PKCS11)
++
++case "$want_native_pkcs11" in
++	yes)
++		AC_MSG_RESULT(using native PKCS11 crypto)
++		CRYPTO="-DPKCS11CRYPTO"
++		PKCS11LINKOBJS='${PKCS11LINKOBJS}'
++		PKCS11LINKSRCS='${PKCS11LINKSRCS}'
++                PKCS11_TEST=pkcs11
++		AC_MSG_CHECKING(for PKCS11 ECDSA)
++		case "$with_ecdsa" in
++		no)
++			AC_MSG_RESULT([disabled])
++ 			;;
++		*)
++			AC_MSG_RESULT(enabled)
++			PKCS11_ECDSA="yes"
++			AC_DEFINE(HAVE_PKCS11_ECDSA, 1,
++			          [Define if your PKCS11 provider supports ECDSA.])
++ 			;;
++ 		esac
++		AC_MSG_CHECKING(for PKCS11 GOST)
++		case "$with_gost" in
++		yes)
++			AC_MSG_RESULT(enabled)
++			PKCS11_GOST="yes"
++			AC_DEFINE(HAVE_PKCS11_GOST, 1,
++			          [Define if your PKCS11 provider supports GOST.])
++ 			;;
++		*)
++			AC_MSG_RESULT([disabled])
++ 			;;
++ 		esac
++ 		;;
++	no|'')
++		AC_MSG_RESULT(disabled)
++		;;
++esac
++
++AC_SUBST(PKCS11LINKOBJS)
++AC_SUBST(PKCS11LINKSRCS)
++AC_SUBST(CRYPTO)
++AC_SUBST(PKCS11_ECDSA)
++AC_SUBST(PKCS11_GOST)
++AC_SUBST(PKCS11_TEST)
++
++# for PKCS11 benchmarks
++have_clock_gt=no
++AC_CHECK_FUNC(clock_gettime,have_clock_gt=yes,)
++if test "$have_clock_gt" = "no"; then
++	AC_CHECK_LIB(rt,clock_gettime,have_clock_gt=ye,,)
++ fi
++if test "$have_clock_gt" = "yes"; then
++	AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Define if clock_gettime is available.])
++fi
++
++
+ AC_MSG_CHECKING(for GSSAPI library)
+ AC_ARG_WITH(gssapi,
+ [  --with-gssapi=PATH      Specify path for system-supplied GSSAPI [[default=yes]]],
+@@ -1245,6 +1484,21 @@ case "$use_randomdev" in
+ esac
+ 
+ #
++# Only check dsa signature generation on these platforms when performing
++# system tests.
++#
++CHECK_DSA=0
++if grep "#define PATH_RANDOMDEV " confdefs.h > /dev/null
++then
++	case "$host" in
++	*darwin*|*freebsd*)
++		CHECK_DSA=1
++		;;
++	esac
++fi
++AC_SUBST(CHECK_DSA)
++
++#
+ # Do we have arc4random() ?
+ #
+ AC_CHECK_FUNC(arc4random, AC_DEFINE(HAVE_ARC4RANDOM))
+@@ -1633,41 +1887,6 @@ esac
+ AC_SUBST(PURIFY)
+ 
+ 
+-AC_ARG_WITH(libtool,
+-	    [  --with-libtool          use GNU libtool],
+-	    use_libtool="$withval", use_libtool="no")
+-
+-case $use_libtool in
+-	yes)
+-		AM_PROG_LIBTOOL
+-		O=lo
+-		A=la
+-		LIBTOOL_MKDEP_SED='s;\.o;\.lo;'
+-		LIBTOOL_MODE_COMPILE='--mode=compile --tag=CC'
+-		LIBTOOL_MODE_INSTALL='--mode=install --tag=CC'
+-		LIBTOOL_MODE_LINK='--mode=link --tag=CC'
+-		case "$host" in
+-		*) LIBTOOL_ALLOW_UNDEFINED= ;;
+-		esac
+-		case "$host" in
+-		*-ibm-aix*) LIBTOOL_IN_MAIN="-Wl,-bI:T_testlist.imp" ;;
+-		*) LIBTOOL_IN_MAIN= ;;
+-		esac;
+-		;;
+-	*)
+-		O=o
+-		A=a
+-		LIBTOOL=
+-		AC_SUBST(LIBTOOL)
+-		LIBTOOL_MKDEP_SED=
+-		LIBTOOL_MODE_COMPILE=
+-		LIBTOOL_MODE_INSTALL=
+-		LIBTOOL_MODE_LINK=
+-		LIBTOOL_ALLOW_UNDEFINED=
+-		LIBTOOL_IN_MAIN=
+-		;;
+-esac
+-
+ #
+ # enable/disable dumping stack backtrace.  Also check if the system supports
+ # glibc-compatible backtrace() function.
+@@ -3419,6 +3638,9 @@ BIND9_CONFIGARGS="`echo $BIND9_CONFIGARGS | sed 's/^ //'`"
+ BIND9_CONFIGARGS="CONFIGARGS=${BIND9_CONFIGARGS}"
+ AC_SUBST(BIND9_CONFIGARGS)
+ 
++AC_SUBST_FILE(LIBISCPK11_API)
++LIBISCPK11_API="$srcdir/lib/iscpk11/api"
++
+ AC_SUBST_FILE(LIBISC_API)
+ LIBISC_API="$srcdir/lib/isc/api"
+ 
+@@ -3728,6 +3950,8 @@ AC_CONFIG_FILES([
+ 	bin/tests/mem/Makefile
+ 	bin/tests/names/Makefile
+ 	bin/tests/net/Makefile
++    bin/tests/pkcs11/Makefile
++	bin/tests/pkcs11/benchmarks/Makefile
+ 	bin/tests/rbt/Makefile
+ 	bin/tests/resolver/Makefile
+ 	bin/tests/sockaddr/Makefile
+@@ -3811,11 +4035,14 @@ AC_CONFIG_FILES([
+ 	lib/isc/include/Makefile
+ 	lib/isc/include/isc/Makefile
+ 	lib/isc/include/isc/platform.h
++	lib/isc/include/pk11/Makefile
++	lib/isc/include/pkcs11/Makefile
+ 	lib/isc/tests/Makefile
+ 	lib/isc/nls/Makefile
+ 	lib/isc/unix/Makefile
+ 	lib/isc/unix/include/Makefile
+ 	lib/isc/unix/include/isc/Makefile
++	lib/isc/unix/include/pkcs11/Makefile
+ 	lib/isccc/Makefile
+ 	lib/isccc/include/Makefile
+ 	lib/isccc/include/isccc/Makefile
+@@ -3885,12 +4112,8 @@ test "$use_pkcs11" = "no" || echo "    PKCS#11/Cryptoki support (--with-pkcs11)"
+ if test "$enable_full_report" = "yes"; then
+     test "$enable_ipv6" = "no" -o "$found_ipv6" = "no" || \
+         echo "    IPv6 support (--enable-ipv6)"
+-    test "X$USE_OPENSSL" = "X" || \
++    test "X$CRYPTO" = "X" -o "$want_native_pkcs11" = "yes" || \
+             echo "    OpenSSL cryptography/DNSSEC (--with-openssl)"
+-    test "$OPENSSL_GOST" != "yes" || \
+-            echo "    GOST algorithm support (--with-gost)"
+-    test "$OPENSSL_ECDSA" != "yes" || \
+-            echo "    ECDSA algorithm support (--with-ecdsa)"
+     test "X$PYTHON" = "X" || echo "    Python tools (--with-python)"
+     test "X$libxml2_libs" = "X" || echo "    XML statistics (--with-libxml2)"
+ fi
+@@ -3923,24 +4146,28 @@ test "$enable_filter" = "yes" || \
+ test "$use_gssapi" = "no" && echo "    GSS-API (--with-gssapi)"
+ test "$want_backtrace" = "yes" || \
+     echo "    Print backtrace on crash (--enable-backtrace)"
+-test "$use_pkcs11" = "no" && echo "    PKCS#11/Cryptoki support (--with-pkcs11)"
+ 
+-test "$enable_ipv6" = "no" -o "$found_ipv6" = "no" && \
+-        echo "    IPv6 support (--enable-ipv6)"
+-test "X$USE_OPENSSL" = "X" && \
+-        echo "    OpenSSL cryptography/DNSSEC (--with-openssl)"
+-test "X$USE_OPENSSL" != "X" -a "$OPENSSL_GOST" != "yes" && \
++test "X$CRYPTO" = "X" -o "$want_native_pkcs11" = "yes" && \
++    echo "    OpenSSL cryptography/DNSSEC (--with-openssl)"
++test "$want_native_pkcs11" != "yes" && \
++    echo "    Native PKCS#11 cryptography/DNSSEC (--enable-native-pkcs11)"
++test "X$CRYPTO" = "X" -o "$OPENSSL_GOST" = "yes" -o "$PKCS11_GOST" = "yes" || \
+     echo "    GOST algorithm support (--with-gost)"
+-test "X$USE_OPENSSL" != "X" -a "$OPENSSL_ECDSA" != "yes" && \
++test "X$CRYPTO" = "X" -o "$OPENSSL_ECDSA" = "yes" -o "$PKCS11_ECDSA" = "yes" || \
+     echo "    ECDSA algorithm support (--with-ecdsa)"
++test "$use_pkcs11" = "no" && echo "    PKCS#11/Cryptoki support (--with-pkcs11)"
++test "$enable_ipv6" = "no" -o "$found_ipv6" = "no" && \
++        echo "    IPv6 support (--enable-ipv6)"
+ test "X$PYTHON" = "X" && echo "    Python tools (--with-python)"
+ test "X$libxml2_libs" = "X" && echo "    XML statistics (--with-libxml2)"
+ 
+ echo "========================================================================"
+ 
+-if test "X$USE_OPENSSL" = "X"; then
++if test "X$CRYPTO" = "X"; then
+ cat << \EOF
+-BIND is being built without OpenSSL. This means it will not have DNSSEC support.
++BIND 9 is being built without cryptography support. This means it will
++not have DNSSEC support. Use --with-openssl, or --with-pkcs11 and
++--enable-native-pkcs11 to enable cryptography.
+ EOF
+ fi
+ 
+diff --git a/doc/arm/pkcs11.xml b/doc/arm/pkcs11.xml
+index b4e22bb..5388a29 100644
+--- a/doc/arm/pkcs11.xml
++++ b/doc/arm/pkcs11.xml
+@@ -20,162 +20,259 @@
+ <!-- $Id: pkcs11.xml,v 1.7 2012/01/16 22:50:12 each Exp $ -->
+ 
+ <sect1 id="pkcs11">
+-  <title>PKCS #11 (Cryptoki) support</title>
+-  <para>PKCS #11 (Public Key Cryptography Standard #11) defines a
+-  platform- independent API for the control of hardware security
+-  modules (HSMs) and other cryptographic support devices.</para>
+-  <para>BIND 9 is known to work with two HSMs: The Sun SCA 6000
+-  cryptographic acceleration board, tested under Solaris x86, and
+-  the AEP Keyper network-attached key storage device, tested with
+-  Debian Linux, Solaris x86 and Windows Server 2003.</para>
++  <title>PKCS#11 (Cryptoki) support</title>
++  <para>
++    PKCS#11 (Public Key Cryptography Standard #11) defines a
++    platform-independent API for the control of hardware security
++    modules (HSMs) and other cryptographic support devices.
++  </para>
++  <para>
++    BIND 9 is known to work with three HSMs: The AEP Keyper, which has
++    been tested with Debian Linux, Solaris x86 and Windows Server 2003;
++    the Thales nShield, tested with Debian Linux; and the Sun SCA 6000
++    cryptographic acceleration board, tested with Solaris x86.  In
++    addition, BIND can be used with SoftHSM, a software-based HSM
++    simulator produced by the OpenDNSSEC project.
++  </para>
++  <para>
++    PKCS#11 makes use of a "provider library": a dynamically loadable
++    library which provides a low-level PKCS#11 interface to drive the HSM
++    hardware.  The PKCS#11 provider library comes from the HSM vendor, and
++    it is specific to the HSM to be controlled.
++  </para>
++  <para>
++    There are two available mechanisms for PKCS#11 support in BIND 9:
++    OpenSSL-based PKCS#11 and native PKCS#11.  When using the first
++    mechanism, BIND uses a modified version of OpenSSL, which loads
++    the provider library and operates the HSM indirectly; any
++    cryptographic operations not supported by the HSM can be carried
++    out by OpenSSL instead.  The second mechanism enables BIND to bypass
++    OpenSSL completely; BIND loads the provider library itself, and uses
++    the PKCS#11 API to drive the HSM directly.
++  </para>
+   <sect2>
+     <title>Prerequisites</title>
+-    <para>See the HSM vendor documentation for information about
+-    installing, initializing, testing and troubleshooting the
+-    HSM.</para>
+-    <para>BIND 9 uses OpenSSL for cryptography, but stock OpenSSL
+-    does not yet fully support PKCS #11. However, a PKCS #11 engine
+-    for OpenSSL is available from the OpenSolaris project. It has
+-    been modified by ISC to work with with BIND 9, and to provide
+-    new features such as PIN management and key by
+-    reference.</para>
+-    <para>The patched OpenSSL depends on a "PKCS #11 provider".
+-    This is a shared library object, providing a low-level PKCS #11
+-    interface to the HSM hardware. It is dynamically loaded by
+-    OpenSSL at runtime. The PKCS #11 provider comes from the HSM
+-    vendor, and is specific to the HSM to be controlled.</para>
+-    <para>There are two "flavors" of PKCS #11 support provided by
+-    the patched OpenSSL, one of which must be chosen at
+-    configuration time. The correct choice depends on the HSM
+-    hardware:</para>
++    <para>
++      See the documentation provided by your HSM vendor for
++      information about installing, initializing, testing and
++      troubleshooting the HSM.
++    </para>
++  </sect2>
++  <sect2>
++    <title>Native PKCS#11</title>
++    <para>
++      Native PKCS#11 mode will only work with an HSM capable of carrying
++      out <emphasis>every</emphasis> cryptographic operation BIND 9 may
++      need. The HSM's provider library must have a complete implementation
++      of the PKCS#11 API, so that all these functions are accessible. As of
++      this writing, only the Thales nShield HSM and the latest development
++      version of SoftHSM can be used in this fashion.  For other HSM's,
++      including the AEP Keyper, Sun SCA 6000 and older versions of SoftHSM,
++      use OpenSSL-based PKCS#11. (Note: As more HSMs become capable of
++      supporting native PKCS#11, it is expected that OpenSSL-based
++      PKCS#11 will eventually be deprecated.)
++    </para>
++    <para>
++      To build BIND with native PKCS#11, configure as follows:
++    </para>
++    <screen>
++$ <userinput>cd bind9</userinput>
++$ <userinput>./configure --enable-native-pkcs11 \
++    --with-pkcs11=<replaceable>provider-library-path</replaceable></userinput>
++    </screen>
++    <para>
++      This will cause all BIND tools, including <command>named</command>
++      and the <command>dnssec-*</command> and <command>pkcs11-*</command>
++      tools, to use the PKCS#11 provider library specified in
++      <replaceable>provider-library-path</replaceable> for cryptography.
++      (The provider library path can be overridden using the
++      <option>-E</option> in <command>named</command> and the
++      <command>dnssec-*</command> tools, or the <option>-m</option> in
++      the <command>pkcs11-*</command> tools.)
++    </para>
++  </sect2>
++  <sect2>
++    <title>OpenSSL-based PKCS#11</title>
++    <para>
++      OpenSSL-based PKCS#11 mode uses a modified version of the
++      OpenSSL library; stock OpenSSL does not fully support PKCS#11.
++      ISC provides a patch to OpenSSL to correct this.  This patch is
++      based on work originally done by the OpenSolaris project; it has been
++      modified by ISC to provide new features such as PIN management and
++      key-by-reference.
++    </para>
++    <para>
++      There are two "flavors" of PKCS#11 support provided by
++      the patched OpenSSL, one of which must be chosen at
++      configuration time. The correct choice depends on the HSM
++      hardware:
++    </para>
+     <itemizedlist>
+       <listitem>
+-        <para>Use 'crypto-accelerator' with HSMs that have hardware
+-        cryptographic acceleration features, such as the SCA 6000
+-        board. This causes OpenSSL to run all supported
+-        cryptographic operations in the HSM.</para>
++        <para>
++          Use 'crypto-accelerator' with HSMs that have hardware
++          cryptographic acceleration features, such as the SCA 6000
++          board. This causes OpenSSL to run all supported
++          cryptographic operations in the HSM.
++        </para>
+       </listitem>
+       <listitem>
+-        <para>Use 'sign-only' with HSMs that are designed to
+-        function primarily as secure key storage devices, but lack
+-        hardware acceleration. These devices are highly secure, but
+-        are not necessarily any faster at cryptography than the
+-        system CPU &mdash; often, they are slower. It is therefore
+-        most efficient to use them only for those cryptographic
+-        functions that require access to the secured private key,
+-        such as zone signing, and to use the system CPU for all
+-        other computationally-intensive operations. The AEP Keyper
+-        is an example of such a device.</para>
++        <para>
++          Use 'sign-only' with HSMs that are designed to
++          function primarily as secure key storage devices, but lack
++          hardware acceleration. These devices are highly secure, but
++          are not necessarily any faster at cryptography than the
++          system CPU &mdash; often, they are slower. It is therefore
++          most efficient to use them only for those cryptographic
++          functions that require access to the secured private key,
++          such as zone signing, and to use the system CPU for all
++          other computationally-intensive operations. The AEP Keyper
++          is an example of such a device.
++        </para>
+       </listitem>
+     </itemizedlist>
+-    <para>The modified OpenSSL code is included in the BIND 9 release,
+-        in the form of a context diff against the latest verions of
+-        OpenSSL.  OpenSSL 0.9.8, 1.0.0 and 1.0.1 are supported; there are
+-        separate diffs for each version.  In the examples to follow,
+-        we use OpenSSL 0.9.8, but the same methods work with OpenSSL 1.0.0
+-	and 1.0.1.
++    <para>
++      The modified OpenSSL code is included in the BIND 9 release,
++      in the form of a context diff against the latest verions of
++      OpenSSL.  OpenSSL 0.9.8, 1.0.0, and 1.0.1 are supported; there are
++      separate diffs for each version.  In the examples to follow,
++      we use OpenSSL 0.9.8, but the same methods work with OpenSSL
++      1.0.0 and 1.0.1.
+     </para>
+     <note>
+-      The latest OpenSSL versions at the time of the BIND release
+-      are 0.9.8y, 1.0.0k and 1.0.1e.
+-      ISC will provide an updated patch as new versions of OpenSSL
++      The latest OpenSSL versions as of this writing (January 2014)
++      are 0.9.8y, 1.0.0l, and 1.0.1f.
++      ISC will provide updated patches as new versions of OpenSSL
+       are released. The version number in the following examples
+-      is expected to change.</note>
++      is expected to change.
++    </note>
+     <para>
+-    Before building BIND 9 with PKCS #11 support, it will be
+-    necessary to build OpenSSL with this patch in place and inform
+-    it of the path to the HSM-specific PKCS #11 provider
+-    library.</para>
+-    <para>Obtain OpenSSL 0.9.8s:</para>
+-    <screen>
+-$ <userinput>wget <ulink>http://www.openssl.org/source/openssl-0.9.8s.tar.gz</ulink></userinput>
+-</screen>
+-    <para>Extract the tarball:</para>
+-    <screen>
+-$ <userinput>tar zxf openssl-0.9.8s.tar.gz</userinput>
++      Before building BIND 9 with PKCS#11 support, it will be
++      necessary to build OpenSSL with the patch in place, and configure
++      it with the path to your HSM's PKCS#11 provider library.
++    </para>
++    </sect3>
++      <title>Patching OpenSSL</title>
++      <screen>
++$ <userinput>wget <ulink>http://www.openssl.org/source/openssl-0.9.8y.tar.gz</ulink></userinput>
++  </screen>
++      <para>Extract the tarball:</para>
++      <screen>
++$ <userinput>tar zxf openssl-0.9.8y.tar.gz</userinput>
+ </screen>
+-    <para>Apply the patch from the BIND 9 release:</para>
+-    <screen>
+-$ <userinput>patch -p1 -d openssl-0.9.8s \
+-            &lt; bind9/bin/pkcs11/openssl-0.9.8s-patch</userinput>
++      <para>Apply the patch from the BIND 9 release:</para>
++      <screen>
++$ <userinput>patch -p1 -d openssl-0.9.8y \
++              &lt; bind9/bin/pkcs11/openssl-0.9.8y-patch</userinput>
+ </screen>
+-    <note>(Note that the patch file may not be compatible with the
+-    "patch" utility on all operating systems. You may need to
+-    install GNU patch.)</note>
+-    <para>When building OpenSSL, place it in a non-standard
+-    location so that it does not interfere with OpenSSL libraries
+-    elsewhere on the system. In the following examples, we choose
+-    to install into "/opt/pkcs11/usr". We will use this location
+-    when we configure BIND 9.</para>
++      <note>
++        Note that the patch file may not be compatible with the
++        "patch" utility on all operating systems. You may need to
++        install GNU patch.
++      </note>
++      <para>
++        When building OpenSSL, place it in a non-standard
++        location so that it does not interfere with OpenSSL libraries
++        elsewhere on the system. In the following examples, we choose
++        to install into "/opt/pkcs11/usr". We will use this location
++        when we configure BIND 9.
++      </para>
++      <para>
++        Later, when building BIND 9, the location of the custom-built
++        OpenSSL library will need to be specified via configure.
++      </para>
++    </sect3>
+     <sect3>
+       <!-- Example 1 -->
+       <title>Building OpenSSL for the AEP Keyper on Linux</title>
+-      <para>The AEP Keyper is a highly secure key storage device,
+-      but does not provide hardware cryptographic acceleration. It
+-      can carry out cryptographic operations, but it is probably
+-      slower than your system's CPU. Therefore, we choose the
+-      'sign-only' flavor when building OpenSSL.</para>
+-      <para>The Keyper-specific PKCS #11 provider library is
+-      delivered with the Keyper software. In this example, we place
+-      it /opt/pkcs11/usr/lib:</para>
++      <para>
++        The AEP Keyper is a highly secure key storage device,
++        but does not provide hardware cryptographic acceleration. It
++        can carry out cryptographic operations, but it is probably
++        slower than your system's CPU. Therefore, we choose the
++        'sign-only' flavor when building OpenSSL.
++      </para>
++      <para>
++        The Keyper-specific PKCS#11 provider library is
++        delivered with the Keyper software. In this example, we place
++        it /opt/pkcs11/usr/lib:
++      </para>
+       <screen>
+ $ <userinput>cp pkcs11.GCC4.0.2.so.4.05 /opt/pkcs11/usr/lib/libpkcs11.so</userinput>
+ </screen>
+-      <para>This library is only available for Linux as a 32-bit
+-      binary. If we are compiling on a 64-bit Linux system, it is
+-      necessary to force a 32-bit build, by specifying -m32 in the
+-      build options.</para>
+-      <para>Finally, the Keyper library requires threads, so we
+-      must specify -pthread.</para>
++      <para>
++        This library is only available for Linux as a 32-bit
++        binary. If we are compiling on a 64-bit Linux system, it is
++        necessary to force a 32-bit build, by specifying -m32 in the
++        build options.
++      </para>
++      <para>
++        Finally, the Keyper library requires threads, so we
++        must specify -pthread.
++      </para>
+       <screen>
+-$ <userinput>cd openssl-0.9.8s</userinput>
++$ <userinput>cd openssl-0.9.8y</userinput>
+ $ <userinput>./Configure linux-generic32 -m32 -pthread \
+             --pk11-libname=/opt/pkcs11/usr/lib/libpkcs11.so \
+             --pk11-flavor=sign-only \
+             --prefix=/opt/pkcs11/usr</userinput>
+ </screen>
+-      <para>After configuring, run "<command>make</command>"
+-      and "<command>make test</command>". If "<command>make
+-      test</command>" fails with "pthread_atfork() not found", you forgot to
+-      add the -pthread above.</para>
++      <para>
++        After configuring, run "<command>make</command>"
++        and "<command>make test</command>". If "<command>make
++        test</command>" fails with "pthread_atfork() not found", you forgot to
++        add the -pthread above.
++      </para>
+     </sect3>
+     <sect3>
+       <!-- Example 2 -->
+       <title>Building OpenSSL for the SCA 6000 on Solaris</title>
+-      <para>The SCA-6000 PKCS #11 provider is installed as a system
+-      library, libpkcs11. It is a true crypto accelerator, up to 4
+-      times faster than any CPU, so the flavor shall be
+-      'crypto-accelerator'.</para>
+-      <para>In this example, we are building on Solaris x86 on an
+-      AMD64 system.</para>
++      <para>
++        The SCA-6000 PKCS#11 provider is installed as a system
++        library, libpkcs11. It is a true crypto accelerator, up to 4
++        times faster than any CPU, so the flavor shall be
++        'crypto-accelerator'.
++      </para>
++      <para>
++        In this example, we are building on Solaris x86 on an
++        AMD64 system.
++      </para>
+       <screen>
+-$ <userinput>cd openssl-0.9.8s</userinput>
++$ <userinput>cd openssl-0.9.8y</userinput>
+ $ <userinput>./Configure solaris64-x86_64-cc \
+             --pk11-libname=/usr/lib/64/libpkcs11.so \
+             --pk11-flavor=crypto-accelerator \
+             --prefix=/opt/pkcs11/usr</userinput>
+ </screen>
+-      <para>(For a 32-bit build, use "solaris-x86-cc" and
+-      /usr/lib/libpkcs11.so.)</para>
+-      <para>After configuring, run 
+-      <command>make</command> and 
+-      <command>make test</command>.</para>
++      <para>
++        (For a 32-bit build, use "solaris-x86-cc" and /usr/lib/libpkcs11.so.)
++      </para>
++      <para>
++        After configuring, run 
++        <command>make</command> and 
++        <command>make test</command>.
++      </para>
+     </sect3>
+     <sect3>
+       <!-- Example 3 -->
+       <title>Building OpenSSL for SoftHSM</title>
+-      <para>SoftHSM is a software library provided by the OpenDNSSEC
+-      project (http://www.opendnssec.org) which provides a PKCS#11
+-      interface to a virtual HSM, implemented in the form of encrypted
+-      data on the local filesystem.  It uses the Botan library for
+-      encryption and SQLite3 for data storage.  Though less secure
+-      than a true HSM, it can provide more secure key storage than
+-      traditional key files, and can allow you to experiment with
+-      PKCS#11 when an HSM is not available.</para>
+-      <para>The SoftHSM cryptographic store must be installed and
+-      initialized before using it with OpenSSL, and the SOFTHSM_CONF
+-      environment variable must always point to the SoftHSM configuration
+-      file:</para>
++      <para>
++        SoftHSM is a software library provided by the OpenDNSSEC
++        project (http://www.opendnssec.org) which provides a PKCS#11
++        interface to a virtual HSM, implemented in the form of encrypted
++        data on the local filesystem.  SoftHSM can be configured to use
++        either OpenSSL or the Botan library for encryption, and SQLite3
++        for data storage.  Though less secure than a true HSM, it can
++        provide more secure key storage than traditional key files,
++        and can allow you to experiment with PKCS#11 when an HSM is
++        not available.
++      </para>
++      <para>
++        The SoftHSM cryptographic store must be installed and
++        initialized before using it with OpenSSL, and the SOFTHSM_CONF
++        environment variable must always point to the SoftHSM configuration
++        file:
++      </para>
+       <screen>
+ $ <userinput> cd softhsm-1.3.0 </userinput>
+ $ <userinput> configure --prefix=/opt/pkcs11/usr </userinput>
+@@ -185,25 +282,31 @@ $ <userinput> export SOFTHSM_CONF=/opt/pkcs11/softhsm.conf </userinput>
+ $ <userinput> echo "0:/opt/pkcs11/softhsm.db" > $SOFTHSM_CONF </userinput>
+ $ <userinput> /opt/pkcs11/usr/bin/softhsm --init-token 0 --slot 0 --label softhsm </userinput>
+ </screen>
+-      <para>SoftHSM can perform all cryptographic operations, but
+-      since it only uses your system CPU, there is no need to use it
+-      for anything but signing.  Therefore, we choose the 'sign-only'
+-      flavor when building OpenSSL.</para>
++      <para>
++        SoftHSM can perform all cryptographic operations, but
++        since it only uses your system CPU, there is no advantage to using
++        it for anything but signing.  Therefore, we choose the 'sign-only'
++        flavor when building OpenSSL.
++      </para>
+       <screen>
+-$ <userinput>cd openssl-0.9.8s</userinput>
++$ <userinput>cd openssl-0.9.8y</userinput>
+ $ <userinput>./Configure linux-x86_64 -pthread \
+-            --pk11-libname=/opt/pkcs11/usr/lib/libpkcs11.so \
++            --pk11-libname=/opt/pkcs11/usr/lib/libsofthsm.so \
+             --pk11-flavor=sign-only \
+             --prefix=/opt/pkcs11/usr</userinput>
+ </screen>
+-      <para>After configuring, run "<command>make</command>"
+-      and "<command>make test</command>".</para>
++     <para>
++       After configuring, run "<command>make</command>"
++       and "<command>make test</command>".
++     </para>
+     </sect3>
+-    <para>Once you have built OpenSSL, run
+-    "<command>apps/openssl engine pkcs11</command>" to confirm
+-    that PKCS #11 support was compiled in correctly. The output
+-    should be one of the following lines, depending on the flavor
+-    selected:</para>
++    <para>
++      Once you have built OpenSSL, run
++      "<command>apps/openssl engine pkcs11</command>" to confirm
++      that PKCS#11 support was compiled in correctly. The output
++      should be one of the following lines, depending on the flavor
++      selected:
++    </para>
+     <screen>
+         (pkcs11) PKCS #11 engine support (sign only)
+ </screen>
+@@ -211,29 +314,31 @@ $ <userinput>./Configure linux-x86_64 -pthread \
+     <screen>
+         (pkcs11) PKCS #11 engine support (crypto accelerator)
+ </screen>
+-    <para>Next, run
+-    "<command>apps/openssl engine pkcs11 -t</command>". This will
+-    attempt to initialize the PKCS #11 engine. If it is able to
+-    do so successfully, it will report
+-    <quote><literal>[ available ]</literal></quote>.</para>
+-    <para>If the output is correct, run
+-    "<command>make install</command>" which will install the
+-    modified OpenSSL suite to 
+-    <filename>/opt/pkcs11/usr</filename>.</para>
+-  </sect2>
+-  <sect2>
+-    <title>Building BIND 9 with PKCS#11</title>
+-    <para>When building BIND 9, the location of the custom-built
+-    OpenSSL library must be specified via configure.</para>
++    <para>
++      Next, run
++      "<command>apps/openssl engine pkcs11 -t</command>". This will
++      attempt to initialize the PKCS#11 engine. If it is able to
++      do so successfully, it will report
++      <quote><literal>[ available ]</literal></quote>.
++    </para>
++    <para>
++      If the output is correct, run
++      "<command>make install</command>" which will install the
++      modified OpenSSL suite to <filename>/opt/pkcs11/usr</filename>.
++    </para>
+     <sect3>
+       <!-- Example 4 -->
+       <title>Configuring BIND 9 for Linux with the AEP Keyper</title>
+-      <para>To link with the PKCS #11 provider, threads must be
+-      enabled in the BIND 9 build.</para>
+-      <para>The PKCS #11 library for the AEP Keyper is currently
+-      only available as a 32-bit binary. If we are building on a
+-      64-bit host, we must force a 32-bit build by adding "-m32" to
+-      the CC options on the "configure" command line.</para>
++      <para>
++        To link with the PKCS#11 provider, threads must be
++        enabled in the BIND 9 build.
++      </para>
++      <para>
++        The PKCS#11 library for the AEP Keyper is currently
++        only available as a 32-bit binary. If we are building on a
++        64-bit host, we must force a 32-bit build by adding "-m32" to
++        the CC options on the "configure" command line.
++      </para>
+       <screen>
+ $ <userinput>cd ../bind9</userinput>
+ $ <userinput>./configure CC="gcc -m32" --enable-threads \
+@@ -244,8 +349,10 @@ $ <userinput>./configure CC="gcc -m32" --enable-threads \
+     <sect3>
+       <!-- Example 5 -->
+       <title>Configuring BIND 9 for Solaris with the SCA 6000</title>
+-      <para>To link with the PKCS #11 provider, threads must be
+-      enabled in the BIND 9 build.</para>
++      <para>
++        To link with the PKCS#11 provider, threads must be
++        enabled in the BIND 9 build.
++      </para>
+       <screen>
+ $ <userinput>cd ../bind9</userinput>
+ $ <userinput>./configure CC="cc -xarch=amd64" --enable-threads \
+@@ -253,11 +360,13 @@ $ <userinput>./configure CC="cc -xarch=amd64" --enable-threads \
+             --with-pkcs11=/usr/lib/64/libpkcs11.so</userinput>
+ </screen>
+       <para>(For a 32-bit build, omit CC="cc -xarch=amd64".)</para>
+-      <para>If configure complains about OpenSSL not working, you
+-      may have a 32/64-bit architecture mismatch. Or, you may have
+-      incorrectly specified the path to OpenSSL (it should be the
+-      same as the --prefix argument to the OpenSSL
+-      Configure).</para>
++      <para>
++        If configure complains about OpenSSL not working, you
++        may have a 32/64-bit architecture mismatch. Or, you may have
++        incorrectly specified the path to OpenSSL (it should be the
++        same as the --prefix argument to the OpenSSL
++        Configure).
++      </para>
+     </sect3>
+     <sect3>
+       <!-- Example 6 -->
+@@ -266,63 +375,85 @@ $ <userinput>./configure CC="cc -xarch=amd64" --enable-threads \
+ $ <userinput>cd ../bind9</userinput>
+ $ <userinput>./configure --enable-threads \
+            --with-openssl=/opt/pkcs11/usr \
+-           --with-pkcs11=/opt/pkcs11/usr/lib/libpkcs11.so</userinput>
++           --with-pkcs11=/opt/pkcs11/usr/lib/libsofthsm.so</userinput>
+ </screen>
+     </sect3>
+-    <para>After configuring, run
+-    "<command>make</command>",
+-    "<command>make test</command>" and
+-    "<command>make install</command>".</para>
+-    <para>(Note: If "make test" fails in the "pkcs11" system test, you may
+-    have forgotten to set the SOFTHSM_CONF environment variable.)</para>
++    <para>
++      After configuring, run
++      "<command>make</command>",
++      "<command>make test</command>" and
++      "<command>make install</command>".
++    </para>
++    <para>
++      (Note: If "make test" fails in the "pkcs11" system test, you may
++      have forgotten to set the SOFTHSM_CONF environment variable.)
++    </para>
+   </sect2>
+   <sect2>
+-    <title>PKCS #11 Tools</title>
+-    <para>BIND 9 includes a minimal set of tools to operate the
+-    HSM, including 
+-    <command>pkcs11-keygen</command> to generate a new key pair
+-    within the HSM, 
+-    <command>pkcs11-list</command> to list objects currently
+-    available, and 
+-    <command>pkcs11-destroy</command> to remove objects.</para>
+-    <para>In UNIX/Linux builds, these tools are built only if BIND
+-    9 is configured with the --with-pkcs11 option. (NOTE: If
+-    --with-pkcs11 is set to "yes", rather than to the path of the
+-    PKCS #11 provider, then the tools will be built but the
+-    provider will be left undefined. Use the -m option or the
+-    PKCS11_PROVIDER environment variable to specify the path to the
+-    provider.)</para>
++    <title>PKCS#11 Tools</title>
++    <para>
++      BIND 9 includes a minimal set of tools to operate the
++      HSM, including 
++      <command>pkcs11-keygen</command> to generate a new key pair
++      within the HSM, 
++      <command>pkcs11-list</command> to list objects currently
++      available,
++      <command>pkcs11-destroy</command> to remove objects, and
++      <command>pkcs11-tokens</command> to list available tokens.
++    </para>
++    <para>
++      In UNIX/Linux builds, these tools are built only if BIND
++      9 is configured with the --with-pkcs11 option. (Note: If
++      --with-pkcs11 is set to "yes", rather than to the path of the
++      PKCS#11 provider, then the tools will be built but the
++      provider will be left undefined. Use the -m option or the
++      PKCS11_PROVIDER environment variable to specify the path to the
++      provider.)
++    </para>
+   </sect2>
+   <sect2>
+     <title>Using the HSM</title>
+-    <para>First, we must set up the runtime environment so the
+-    OpenSSL and PKCS #11 libraries can be loaded:</para>
++    <para>
++      For OpenSSL-based PKCS#11, we must first set up the runtime
++      environment so the OpenSSL and PKCS#11 libraries can be loaded:
++    </para>
+     <screen>
+ $ <userinput>export LD_LIBRARY_PATH=/opt/pkcs11/usr/lib:${LD_LIBRARY_PATH}</userinput>
+ </screen>
+-    <para>When operating an AEP Keyper, it is also necessary to
+-    specify the location of the "machine" file, which stores
+-    information about the Keyper for use by PKCS #11 provider
+-    library. If the machine file is in 
+-    <filename>/opt/Keyper/PKCS11Provider/machine</filename>,
+-    use:</para>
++    <para>
++      This causes <command>named</command> and other binaries to load
++      the OpenSSL library from <filename>/opt/pkcs11/usr/lib</filename>
++      rather than from the default location.  This step is not necessary
++      when using native PKCS#11.
++    </para>
++    <para>
++      Some HSMs require other environment variables to be set.
++      For example, when operating an AEP Keyper, it is necessary to
++      specify the location of the "machine" file, which stores
++      information about the Keyper for use by the provider
++      library. If the machine file is in 
++      <filename>/opt/Keyper/PKCS11Provider/machine</filename>,
++      use:
++    </para>
+     <screen>
+ $ <userinput>export KEYPER_LIBRARY_PATH=/opt/Keyper/PKCS11Provider</userinput>
+ </screen>
+-    <!-- TODO: why not defined at compile time? -->
+-    <para>These environment variables must be set whenever running
+-    any tool that uses the HSM, including 
+-    <command>pkcs11-keygen</command>, 
+-    <command>pkcs11-list</command>, 
+-    <command>pkcs11-destroy</command>, 
+-    <command>dnssec-keyfromlabel</command>, 
+-    <command>dnssec-signzone</command>, 
+-    <command>dnssec-keygen</command>(which will use the HSM for
+-    random number generation), and 
+-    <command>named</command>.</para>
+-    <para>We can now create and use keys in the HSM. In this case,
+-    we will create a 2048 bit key and give it the label
+-    "sample-ksk":</para>
++    <para>
++      Such environment variables must be set whenever running
++      any tool that uses the HSM, including 
++      <command>pkcs11-keygen</command>, 
++      <command>pkcs11-list</command>, 
++      <command>pkcs11-destroy</command>, 
++      <command>dnssec-keyfromlabel</command>, 
++      <command>dnssec-signzone</command>, 
++      <command>dnssec-keygen</command>, and
++      <command>named</command>.
++    </para>
++    <para>
++      We can now create and use keys in the HSM. In this case,
++      we will create a 2048 bit key and give it the label
++      "sample-ksk":
++    </para>
+     <screen>
+ $ <userinput>pkcs11-keygen -b 2048 -l sample-ksk</userinput>
+ </screen>
+@@ -333,44 +464,56 @@ Enter PIN:
+ object[0]: handle 2147483658 class 3 label[8] 'sample-ksk' id[0]
+ object[1]: handle 2147483657 class 2 label[8] 'sample-ksk' id[0]
+ </screen>
+-    <para>Before using this key to sign a zone, we must create a
+-    pair of BIND 9 key files. The "dnssec-keyfromlabel" utility
+-    does this. In this case, we will be using the HSM key
+-    "sample-ksk" as the key-signing key for "example.net":</para>
++    <para>
++      Before using this key to sign a zone, we must create a
++      pair of BIND 9 key files. The "dnssec-keyfromlabel" utility
++      does this. In this case, we will be using the HSM key
++      "sample-ksk" as the key-signing key for "example.net":
++    </para>
+     <screen>
+ $ <userinput>dnssec-keyfromlabel -l sample-ksk -f KSK example.net</userinput>
+ </screen>
+-    <para>The resulting K*.key and K*.private files can now be used
+-    to sign the zone. Unlike normal K* files, which contain both
+-    public and private key data, these files will contain only the
+-    public key data, plus an identifier for the private key which
+-    remains stored within the HSM. The HSM handles signing with the
+-    private key.</para>
+-    <para>If you wish to generate a second key in the HSM for use
+-    as a zone-signing key, follow the same procedure above, using a
+-    different keylabel, a smaller key size, and omitting "-f KSK"
+-    from the dnssec-keyfromlabel arguments:</para>
++    <para>
++      The resulting K*.key and K*.private files can now be used
++      to sign the zone. Unlike normal K* files, which contain both
++      public and private key data, these files will contain only the
++      public key data, plus an identifier for the private key which
++      remains stored within the HSM. Signing with the private key takes
++      place inside the HSM.
++    </para>
++    <para>
++      If you wish to generate a second key in the HSM for use
++      as a zone-signing key, follow the same procedure above, using a
++      different keylabel, a smaller key size, and omitting "-f KSK"
++      from the dnssec-keyfromlabel arguments:
++    </para>
+     <screen>
+ $ <userinput>pkcs11-keygen -b 1024 -l sample-zsk</userinput>
+ $ <userinput>dnssec-keyfromlabel -l sample-zsk example.net</userinput>
+ </screen>
+-    <para>Alternatively, you may prefer to generate a conventional
+-    on-disk key, using dnssec-keygen:</para>
++    <para>
++      Alternatively, you may prefer to generate a conventional
++      on-disk key, using dnssec-keygen:
++    </para>
+     <screen>
+ $ <userinput>dnssec-keygen example.net</userinput>
+ </screen>
+-    <para>This provides less security than an HSM key, but since
+-    HSMs can be slow or cumbersome to use for security reasons, it
+-    may be more efficient to reserve HSM keys for use in the less
+-    frequent key-signing operation. The zone-signing key can be
+-    rolled more frequently, if you wish, to compensate for a
+-    reduction in key security.</para>
+-    <para>Now you can sign the zone. (Note: If not using the -S
+-    option to 
+-    <command>dnssec-signzone</command>, it will be necessary to add
+-    the contents of both 
+-    <filename>K*.key</filename> files to the zone master file before
+-    signing it.)</para>
++    <para>
++      This provides less security than an HSM key, but since
++      HSMs can be slow or cumbersome to use for security reasons, it
++      may be more efficient to reserve HSM keys for use in the less
++      frequent key-signing operation. The zone-signing key can be
++      rolled more frequently, if you wish, to compensate for a
++      reduction in key security.  (Note: When using native PKCS#11,
++      there is no speed advantage to using on-disk keys, as cryptographic
++      operations will be done by the HSM regardless.)
++    </para>
++    <para>
++      Now you can sign the zone. (Note: If not using the -S
++      option to <command>dnssec-signzone</command>, it will be
++      necessary to add the contents of both <filename>K*.key</filename>
++      files to the zone master file before signing it.)
++    </para>
+     <screen>
+ $ <userinput>dnssec-signzone -S example.net</userinput>
+ Enter PIN:
+@@ -383,36 +526,50 @@ example.net.signed
+   </sect2>
+   <sect2>
+     <title>Specifying the engine on the command line</title>
+-    <para>The OpenSSL engine can be specified in 
+-    <command>named</command> and all of the BIND 
+-    <command>dnssec-*</command> tools by using the "-E
+-    &lt;engine&gt;" command line option. If BIND 9 is built with
+-    the --with-pkcs11 option, this option defaults to "pkcs11".
+-    Specifying the engine will generally not be necessary unless
+-    for some reason you wish to use a different OpenSSL
+-    engine.</para>
+-    <para>If you wish to disable use of the "pkcs11" engine &mdash;
+-    for troubleshooting purposes, or because the HSM is unavailable
+-    &mdash; set the engine to the empty string. For example:</para>
++    <para>
++      When using OpenSSL-based PKCS#11, the "engine" to be used by
++      OpenSSL can be specified in <command>named</command> and all of
++      the BIND <command>dnssec-*</command> tools by using the "-E
++      &lt;engine&gt;" command line option. If BIND 9 is built with
++      the --with-pkcs11 option, this option defaults to "pkcs11".
++      Specifying the engine will generally not be necessary unless
++      for some reason you wish to use a different OpenSSL
++      engine.
++    </para>
++    <para>
++      If you wish to disable use of the "pkcs11" engine &mdash;
++      for troubleshooting purposes, or because the HSM is unavailable
++      &mdash; set the engine to the empty string. For example:
++    </para>
+     <screen>
+ $ <userinput>dnssec-signzone -E '' -S example.net</userinput>
+ </screen>
+-    <para>This causes 
+-    <command>dnssec-signzone</command> to run as if it were compiled
+-    without the --with-pkcs11 option.</para>
++    <para>
++      This causes 
++      <command>dnssec-signzone</command> to run as if it were compiled
++      without the --with-pkcs11 option.
++    </para>
++    <para>
++      When built with native PKCS#11 mode, the "engine" option has a
++      different meaning: it specifies the path to the PKCS#11 provider
++      library.  This may be useful when testing a new provider library.
++    </para>
+   </sect2>
+   <sect2>
+     <title>Running named with automatic zone re-signing</title>
+-    <para>If you want 
+-    <command>named</command> to dynamically re-sign zones using HSM
+-    keys, and/or to to sign new records inserted via nsupdate, then
+-    named must have access to the HSM PIN. This can be accomplished
+-    by placing the PIN into the openssl.cnf file (in the above
+-    examples, 
+-    <filename>/opt/pkcs11/usr/ssl/openssl.cnf</filename>).</para>
+-    <para>The location of the openssl.cnf file can be overridden by
+-    setting the OPENSSL_CONF environment variable before running
+-    named.</para>
++    <para>
++      If you want <command>named</command> to dynamically re-sign zones
++      using HSM keys, and/or to to sign new records inserted via nsupdate,
++      then named must have access to the HSM PIN. In OpenSSL-based PKCS#11,
++      this is accomplished by placing the PIN into the openssl.cnf file
++      (in the above examples, 
++      <filename>/opt/pkcs11/usr/ssl/openssl.cnf</filename>).
++    </para>
++    <para>
++      The location of the openssl.cnf file can be overridden by
++      setting the OPENSSL_CONF environment variable before running
++      named.
++    </para>
+     <para>Sample openssl.cnf:</para>
+     <programlisting>
+         openssl_conf = openssl_def
+@@ -423,22 +580,25 @@ $ <userinput>dnssec-signzone -E '' -S example.net</userinput>
+         [ pkcs11_section ]
+         PIN = <replaceable>&lt;PLACE PIN HERE&gt;</replaceable>
+ </programlisting>
+-    <para>This will also allow the dnssec-* tools to access the HSM
+-    without PIN entry. (The pkcs11-* tools access the HSM directly,
+-    not via OpenSSL, so a PIN will still be required to use
+-    them.)</para>
+-<!-- 
+-If the PIN is not known, I believe the first time named needs the
+-PIN to open a key, it'll ask you to type in the PIN, which will be
+-a problem because it probably won't be running on a terminal
+--->
++    <para>
++      This will also allow the dnssec-* tools to access the HSM
++      without PIN entry. (The pkcs11-* tools access the HSM directly,
++      not via OpenSSL, so a PIN will still be required to use
++      them.)
++    </para>
++    <para>
++      In native PKCS#11 mode, the PIN can be provided in a file specified
++      as an attribute of the key's label.  For example, if a key had the label
++      <userinput>pkcs11:object=local-zsk;pin-source=/etc/hsmpin"</userinput>,
++      then the PIN would be read from the file
++      <filename>/etc/hsmpin</filename>.
++    </para>
+     <warning>
+-      <para>Placing the HSM's PIN in a text file in
+-      this manner may reduce the security advantage of using an
+-      HSM. Be sure this is what you want to do before configuring
+-      OpenSSL in this way.</para>
++      <para>
++        Placing the HSM's PIN in a text file in this manner may reduce the
++        security advantage of using an HSM. Be sure this is what you want to
++        do before configuring OpenSSL in this way.
++      </para>
+     </warning>
+   </sect2>
+-  <!-- TODO: what is alternative then for named dynamic re-signing? -->
+-  <!-- TODO: what happens if PIN is not known? named will log about it? -->
+ </sect1>
+diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in
+index 0c5e93b..41fac95 100644
+--- a/lib/dns/Makefile.in
++++ b/lib/dns/Makefile.in
+@@ -27,10 +27,10 @@ top_srcdir =	@top_srcdir@
+ 
+ USE_ISC_SPNEGO = @USE_ISC_SPNEGO@
+ 
+-CINCLUDES =	-I. -Iinclude ${DNS_INCLUDES} \
+-		${ISC_INCLUDES} @DST_OPENSSL_INC@ @DST_GSSAPI_INC@
++CINCLUDES =	-I. -I${top_srcdir}/lib/dns -Iinclude ${DNS_INCLUDES} ${ISC_INCLUDES} \
++		@DST_OPENSSL_INC@ @DST_GSSAPI_INC@
+ 
+-CDEFINES =	-DUSE_MD5 @USE_OPENSSL@ @USE_GSSAPI@ ${USE_ISC_SPNEGO}
++CDEFINES =	-DUSE_MD5 @CRYPTO@ @USE_GSSAPI@ ${USE_ISC_SPNEGO}
+ 
+ CWARNINGS =
+ 
+@@ -47,7 +47,10 @@ OPENSSLLINKOBJS = openssl_link.@O@ openssldh_link.@O@ openssldsa_link.@O@ \
+ 		  opensslecdsa_link.@O@ @OPENSSLGOSTLINKOBJS@ \
+ 		  opensslrsa_link.@O@
+ 
+-DSTOBJS =	@DST_EXTRA_OBJS@ @OPENSSLLINKOBJS@ \
++PKCS11LINKOBJS	= pkcs11dh_link.@O@ pkcs11dsa_link.@O@ pkcs11rsa_link.@O@ \
++		pkcs11ecdsa_link.@O@ pkcs11gost_link.@O@ pkcs11.@O@
++
++DSTOBJS =	@DST_EXTRA_OBJS@ @OPENSSLLINKOBJS@ @PKCS11LINKOBJS@ \
+ 		dst_api.@O@ dst_lib.@O@ dst_parse.@O@ dst_result.@O@ \
+ 		gssapi_link.@O@ gssapictx.@O@ hmac_link.@O@ key.@O@ 
+ 
+@@ -79,7 +82,10 @@ OPENSSLGOSTLINKSRCS = opensslgost_link.c
+ OPENSSLLINKSRCS = openssl_link.c openssldh_link.c openssldsa_link.c \
+ 		  opensslecdsa_link.c @OPENSSLGOSTLINKSRCS@ opensslrsa_link.c
+ 
+-DSTSRCS =	@DST_EXTRA_SRCS@ @OPENSSLLINKSRCS@ \
++PKCS11LINKSRCS	= pkcs11dh_link.c pkcs11dsa_link.c pkcs11rsa_link.c \
++		pkcs11ecdsa_link.c pkcs11gost_link.c pkcs11.c
++
++DSTSRCS =	@DST_EXTRA_SRCS@ @OPENSSLLINKSRCS@ @PKCS11LINKSRCS@ \
+ 		dst_api.c dst_lib.c dst_parse.c \
+ 		dst_result.c gssapi_link.c gssapictx.c \
+ 		hmac_link.c key.c
+diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c
+index cf97404..00a0080 100644
+--- a/lib/dns/dnssec.c
++++ b/lib/dns/dnssec.c
+@@ -275,7 +275,8 @@ dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
+ 	if (ret != ISC_R_SUCCESS)
+ 		goto cleanup_databuf;
+ 
+-	ret = dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx);
++	ret = dst_context_create3(key, mctx,
++				  DNS_LOGCATEGORY_DNSSEC, ISC_TRUE, &ctx);
+ 	if (ret != ISC_R_SUCCESS)
+ 		goto cleanup_databuf;
+ 
+@@ -470,7 +471,8 @@ dns_dnssec_verify3(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
+ 	}
+ 
+  again:
+-	ret = dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx);
++	ret = dst_context_create4(key, mctx, DNS_LOGCATEGORY_DNSSEC,
++				  ISC_FALSE, maxbits, &ctx);
+ 	if (ret != ISC_R_SUCCESS)
+ 		goto cleanup_struct;
+ 
+@@ -872,7 +874,8 @@ dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
+ 
+ 	isc_buffer_init(&databuf, data, sizeof(data));
+ 
+-	RETERR(dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx));
++	RETERR(dst_context_create3(key, mctx,
++				   DNS_LOGCATEGORY_DNSSEC, ISC_TRUE, &ctx));
+ 
+ 	/*
+ 	 * Digest the fields of the SIG - we can cheat and use
+@@ -1022,7 +1025,8 @@ dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
+ 		goto failure;
+ 	}
+ 
+-	RETERR(dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx));
++	RETERR(dst_context_create3(key, mctx,
++				   DNS_LOGCATEGORY_DNSSEC, ISC_FALSE, &ctx));
+ 
+ 	/*
+ 	 * Digest the SIG(0) record, except for the signature.
+diff --git a/lib/dns/ds.c b/lib/dns/ds.c
+index e72ecbb..b51476b 100644
+--- a/lib/dns/ds.c
++++ b/lib/dns/ds.c
+@@ -38,11 +38,8 @@
+ 
+ #include <dst/dst.h>
+ 
+-#ifdef HAVE_OPENSSL_GOST
+-#include <dst/result.h>
+-#include <openssl/evp.h>
+-
+-extern const EVP_MD * EVP_gost(void);
++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
++#include "dst_gost.h"
+ #endif
+ 
+ isc_result_t
+@@ -59,9 +56,8 @@ dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key,
+ 	isc_sha1_t sha1;
+ 	isc_sha256_t sha256;
+ 	isc_sha384_t sha384;
+-#ifdef HAVE_OPENSSL_GOST
+-	EVP_MD_CTX ctx;
+-	const EVP_MD *md;
++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
++	isc_gost_t gost;
+ #endif
+ 
+ 	REQUIRE(key != NULL);
+@@ -88,29 +84,23 @@ dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key,
+ 		isc_sha1_final(&sha1, digest);
+ 		break;
+ 
+-#ifdef HAVE_OPENSSL_GOST
+-#define CHECK(x)					\
+-	if ((x) != 1) {					\
+-		EVP_MD_CTX_cleanup(&ctx);		\
+-		return (DST_R_CRYPTOFAILURE);		\
+-	}
++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
++#define RETERR(x) do {					\
++	isc_result_t ret = (x);				\
++	if (ret != ISC_R_SUCCESS) {			\
++		isc_gost_invalidate(&gost);		\
++		return (ret);				\
++	}						\
++} while (0)
+ 
+ 	case DNS_DSDIGEST_GOST:
+-		md = EVP_gost();
+-		if (md == NULL)
+-			return (DST_R_CRYPTOFAILURE);
+-		EVP_MD_CTX_init(&ctx);
+-		CHECK(EVP_DigestInit(&ctx, md));
++		RETERR(isc_gost_init(&gost));
+ 		dns_name_toregion(name, &r);
+-		CHECK(EVP_DigestUpdate(&ctx,
+-				       (const void *) r.base,
+-				       (size_t) r.length));
++		RETERR(isc_gost_update(&gost, r.base, r.length));
+ 		dns_rdata_toregion(key, &r);
+ 		INSIST(r.length >= 4);
+-		CHECK(EVP_DigestUpdate(&ctx,
+-				       (const void *) r.base,
+-				       (size_t) r.length));
+-		CHECK(EVP_DigestFinal(&ctx, digest, NULL));
++		RETERR(isc_gost_update(&gost, r.base, r.length));
++		RETERR(isc_gost_final(&gost, digest));
+ 		break;
+ #endif
+ 
+@@ -147,7 +137,7 @@ dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key,
+ 		ds.length = ISC_SHA1_DIGESTLENGTH;
+ 		break;
+ 
+-#ifdef HAVE_OPENSSL_GOST
++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
+ 	case DNS_DSDIGEST_GOST:
+ 		ds.length = ISC_GOST_DIGESTLENGTH;
+ 		break;
+diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c
+index 6416273..d96473f 100644
+--- a/lib/dns/dst_api.c
++++ b/lib/dns/dst_api.c
+@@ -75,9 +75,7 @@
+ #define DST_AS_STR(t) ((t).value.as_textregion.base)
+ 
+ static dst_func_t *dst_t_func[DST_MAX_ALGS];
+-#ifdef BIND9
+ static isc_entropy_t *dst_entropy_pool = NULL;
+-#endif
+ static unsigned int dst_entropy_flags = 0;
+ static isc_boolean_t dst_initialized = ISC_FALSE;
+ 
+@@ -169,7 +167,7 @@ dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx,
+ #endif
+ 	REQUIRE(dst_initialized == ISC_FALSE);
+ 
+-#ifndef OPENSSL
++#if !defined(OPENSSL) && !defined(PKCS11CRYPTO)
+ 	UNUSED(engine);
+ #endif
+ 
+@@ -234,7 +232,24 @@ dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx,
+ 	RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA256]));
+ 	RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA384]));
+ #endif
+-#endif /* OPENSSL */
++#elif PKCS11CRYPTO
++	RETERR(dst__pkcs11_init(mctx, engine));
++	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSAMD5]));
++	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA1]));
++	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1]));
++	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA256]));
++	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA512]));
++	RETERR(dst__pkcs11dsa_init(&dst_t_func[DST_ALG_DSA]));
++	RETERR(dst__pkcs11dsa_init(&dst_t_func[DST_ALG_NSEC3DSA]));
++	RETERR(dst__pkcs11dh_init(&dst_t_func[DST_ALG_DH]));
++#ifdef HAVE_PKCS11_ECDSA
++	RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA256]));
++	RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA384]));
++#endif
++#ifdef HAVE_PKCS11_GOST
++	RETERR(dst__pkcs11gost_init(&dst_t_func[DST_ALG_ECCGOST]));
++#endif
++#endif /* if OPENSSL, elif PKCS11CRYPTO */
+ #ifdef GSSAPI
+ 	RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI]));
+ #endif
+@@ -259,7 +274,9 @@ dst_lib_destroy(void) {
+ 			dst_t_func[i]->cleanup();
+ #ifdef OPENSSL
+ 	dst__openssl_destroy();
+-#endif
++#elif PKCS11CRYPTO
++	(void) dst__pkcs11_destroy();
++#endif /* if OPENSSL, elif PKCS11CRYPTO */
+ 	if (dst__memory_pool != NULL)
+ 		isc_mem_detach(&dst__memory_pool);
+ #ifdef BIND9
+@@ -279,13 +296,31 @@ dst_algorithm_supported(unsigned int alg) {
+ 
+ isc_result_t
+ dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) {
+-	return (dst_context_create2(key, mctx,
+-				    DNS_LOGCATEGORY_GENERAL, dctxp));
++	return (dst_context_create4(key, mctx, DNS_LOGCATEGORY_GENERAL,
++				    ISC_TRUE, 0, dctxp));
+ }
+ 
+ isc_result_t
+ dst_context_create2(dst_key_t *key, isc_mem_t *mctx,
+-		    isc_logcategory_t *category, dst_context_t **dctxp) {
++		    isc_logcategory_t *category, dst_context_t **dctxp)
++{
++	return (dst_context_create4(key, mctx, category, ISC_TRUE, 0, dctxp));
++}
++
++isc_result_t
++dst_context_create3(dst_key_t *key, isc_mem_t *mctx,
++		    isc_logcategory_t *category, isc_boolean_t useforsigning,
++		    dst_context_t **dctxp)
++{
++	return (dst_context_create4(key, mctx, category,
++				    useforsigning, 0, dctxp));
++}
++
++isc_result_t
++dst_context_create4(dst_key_t *key, isc_mem_t *mctx,
++		    isc_logcategory_t *category, isc_boolean_t useforsigning,
++		    int maxbits, dst_context_t **dctxp)
++{
+ 	dst_context_t *dctx;
+ 	isc_result_t result;
+ 
+@@ -294,7 +329,7 @@ dst_context_create2(dst_key_t *key, isc_mem_t *mctx,
+ 	REQUIRE(mctx != NULL);
+ 	REQUIRE(dctxp != NULL && *dctxp == NULL);
+ 
+-	if (key->func->createctx == NULL)
++	if (key->func->createctx == NULL && key->func->createctx2 == NULL)
+ 		return (DST_R_UNSUPPORTEDALG);
+ 	if (key->keydata.generic == NULL)
+ 		return (DST_R_NULLKEY);
+@@ -305,7 +340,14 @@ dst_context_create2(dst_key_t *key, isc_mem_t *mctx,
+ 	dctx->key = key;
+ 	dctx->mctx = mctx;
+ 	dctx->category = category;
+-	result = key->func->createctx(key, dctx);
++	if (useforsigning)
++		dctx->use = DO_SIGN;
++	else
++		dctx->use = DO_VERIFY;
++	if (key->func->createctx2 != NULL)
++		result = key->func->createctx2(key, maxbits, dctx);
++	else
++		result = key->func->createctx(key, dctx);
+ 	if (result != ISC_R_SUCCESS) {
+ 		isc_mem_put(mctx, dctx, sizeof(dst_context_t));
+ 		return (result);
+@@ -1796,7 +1838,7 @@ algorithm_status(unsigned int alg) {
+ 
+ 	if (dst_algorithm_supported(alg))
+ 		return (ISC_R_SUCCESS);
+-#ifndef OPENSSL
++#if !defined(OPENSSL) && !defined(PKCS11CRYPTO)
+ 	if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 ||
+ 	    alg == DST_ALG_DSA || alg == DST_ALG_DH ||
+ 	    alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA ||
+@@ -1842,11 +1884,18 @@ dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) {
+ 
+ 	if (len == 0)
+ 		return (ISC_R_SUCCESS);
++
++#ifdef PKCS11CRYPTO
++	UNUSED(pseudo);
++	UNUSED(flags);
++	return (pk11_rand_bytes(buf, len));
++#else /* PKCS11CRYPTO */
+ 	if (pseudo)
+ 		flags &= ~ISC_ENTROPY_GOODONLY;
+ 	else
+ 		flags |= ISC_ENTROPY_BLOCKING;
+ 	return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags));
++#endif /* PKCS11CRYPTO */
+ #else
+ 	UNUSED(buf);
+ 	UNUSED(len);
+@@ -1858,7 +1907,7 @@ dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) {
+ 
+ unsigned int
+ dst__entropy_status(void) {
+-#ifdef BIND9
++#ifndef PKCS11CRYPTO
+ #ifdef GSSAPI
+ 	unsigned int flags = dst_entropy_flags;
+ 	isc_result_t ret;
+diff --git a/lib/dns/dst_gost.h b/lib/dns/dst_gost.h
+new file mode 100644
+index 0000000..37a4200
+--- /dev/null
++++ b/lib/dns/dst_gost.h
+@@ -0,0 +1,57 @@
++/*
++ * Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#ifndef DST_GOST_H
++#define DST_GOST_H 1
++
++#include <isc/lang.h>
++#include <isc/log.h>
++#include <dst/result.h>
++
++#define ISC_GOST_DIGESTLENGTH 32U
++
++#ifdef HAVE_OPENSSL_GOST
++#include <openssl/evp.h>
++
++typedef EVP_MD_CTX isc_gost_t;
++#endif
++#ifdef HAVE_PKCS11_GOST
++#include <pk11/pk11.h>
++
++typedef pk11_context_t isc_gost_t;
++#endif
++
++ISC_LANG_BEGINDECLS
++
++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
++
++isc_result_t
++isc_gost_init(isc_gost_t *ctx);
++
++void
++isc_gost_invalidate(isc_gost_t *ctx);
++
++isc_result_t
++isc_gost_update(isc_gost_t *ctx, const unsigned char *data, unsigned int len);
++
++isc_result_t
++isc_gost_final(isc_gost_t *ctx, unsigned char *digest);
++
++ISC_LANG_ENDDECLS
++
++#endif /* HAVE_OPENSSL_GOST || HAVE_PKCS11_GOST */
++
++#endif /* DST_GOST_H */
+diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h
+index 49ca424..b15135e 100644
+--- a/lib/dns/dst_internal.h
++++ b/lib/dns/dst_internal.h
+@@ -84,6 +84,12 @@ typedef struct dst_hmacsha256_key dst_hmacsha256_key_t;
+ typedef struct dst_hmacsha384_key dst_hmacsha384_key_t;
+ typedef struct dst_hmacsha512_key dst_hmacsha512_key_t;
+ 
++/*%
++ * Indicate whether a DST context will be used for signing
++ * or for verification
++ */
++typedef enum { DO_SIGN, DO_VERIFY } dst_use_t;
++
+ /*% DST Key Structure */
+ struct dst_key {
+ 	unsigned int	magic;
+@@ -112,6 +118,8 @@ struct dst_key {
+ 		DSA *dsa;
+ 		DH *dh;
+ 		EVP_PKEY *pkey;
++#elif PKCS11CRYPTO
++		pk11_object_t *pkey;
+ #endif
+ 		dst_hmacmd5_key_t *hmacmd5;
+ 		dst_hmacsha1_key_t *hmacsha1;
+@@ -139,6 +147,7 @@ struct dst_key {
+ 
+ struct dst_context {
+ 	unsigned int magic;
++	dst_use_t use;
+ 	dst_key_t *key;
+ 	isc_mem_t *mctx;
+ 	isc_logcategory_t *category;
+@@ -157,6 +166,8 @@ struct dst_context {
+ 		isc_hmacsha512_t *hmacsha512ctx;
+ #ifdef OPENSSL
+ 		EVP_MD_CTX *evp_md_ctx;
++#elif PKCS11CRYPTO
++		pk11_context_t *pk11_ctx;
+ #endif
+ 	} ctxdata;
+ };
+@@ -166,6 +177,8 @@ struct dst_func {
+ 	 * Context functions
+ 	 */
+ 	isc_result_t (*createctx)(dst_key_t *key, dst_context_t *dctx);
++	isc_result_t (*createctx2)(dst_key_t *key, int maxbits,
++				   dst_context_t *dctx);
+ 	void (*destroyctx)(dst_context_t *dctx);
+ 	isc_result_t (*adddata)(dst_context_t *dctx, const isc_region_t *data);
+ 
+@@ -209,6 +222,7 @@ struct dst_func {
+  * Initializers
+  */
+ isc_result_t dst__openssl_init(const char *engine);
++#define dst__pkcs11_init pk11_initialize
+ 
+ isc_result_t dst__hmacmd5_init(struct dst_func **funcp);
+ isc_result_t dst__hmacsha1_init(struct dst_func **funcp);
+@@ -218,20 +232,30 @@ isc_result_t dst__hmacsha384_init(struct dst_func **funcp);
+ isc_result_t dst__hmacsha512_init(struct dst_func **funcp);
+ isc_result_t dst__opensslrsa_init(struct dst_func **funcp,
+ 				  unsigned char algorithm);
++isc_result_t dst__pkcs11rsa_init(struct dst_func **funcp);
+ isc_result_t dst__openssldsa_init(struct dst_func **funcp);
++isc_result_t dst__pkcs11dsa_init(struct dst_func **funcp);
+ isc_result_t dst__openssldh_init(struct dst_func **funcp);
++isc_result_t dst__pkcs11dh_init(struct dst_func **funcp);
+ isc_result_t dst__gssapi_init(struct dst_func **funcp);
++#ifdef HAVE_OPENSSL_ECDSA
++isc_result_t dst__opensslecdsa_init(struct dst_func **funcp);
++#endif
++#ifdef HAVE_PKCS11_ECDSA
++isc_result_t dst__pkcs11ecdsa_init(struct dst_func **funcp);
++#endif
+ #ifdef HAVE_OPENSSL_GOST
+ isc_result_t dst__opensslgost_init(struct dst_func **funcp);
+ #endif
+-#ifdef HAVE_OPENSSL_ECDSA
+-isc_result_t dst__opensslecdsa_init(struct dst_func **funcp);
++#ifdef HAVE_PKCS11_GOST
++isc_result_t dst__pkcs11gost_init(struct dst_func **funcp);
+ #endif
+ 
+ /*%
+  * Destructors
+  */
+ void dst__openssl_destroy(void);
++#define dst__pkcs11_destroy pk11_finalize
+ 
+ /*%
+  * Memory allocators using the DST memory pool.
+diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c
+index 6348cc1..ec622d9 100644
+--- a/lib/dns/dst_parse.c
++++ b/lib/dns/dst_parse.c
+@@ -93,7 +93,6 @@ static struct parse_map map[] = {
+ 	{TAG_RSA_COEFFICIENT, "Coefficient:"},
+ 	{TAG_RSA_ENGINE, "Engine:" },
+ 	{TAG_RSA_LABEL, "Label:" },
+-	{TAG_RSA_PIN, "PIN:" },
+ 
+ 	{TAG_DH_PRIME, "Prime(p):"},
+ 	{TAG_DH_GENERATOR, "Generator(g):"},
+@@ -107,8 +106,11 @@ static struct parse_map map[] = {
+ 	{TAG_DSA_PUBLIC, "Public_value(y):"},
+ 
+ 	{TAG_GOST_PRIVASN1, "GostAsn1:"},
++	{TAG_GOST_PRIVRAW, "PrivateKey:"},
+ 
+ 	{TAG_ECDSA_PRIVATEKEY, "PrivateKey:"},
++	{TAG_ECDSA_ENGINE, "Engine:" },
++	{TAG_ECDSA_LABEL, "Label:" },
+ 
+ 	{TAG_HMACMD5_KEY, "Key:"},
+ 	{TAG_HMACMD5_BITS, "Bits:"},
+@@ -262,22 +264,42 @@ check_gost(const dst_private_t *priv, isc_boolean_t external) {
+ 
+ 	if (priv->nelements != GOST_NTAGS)
+ 		return (-1);
+-	if (priv->elements[0].tag != TAG(DST_ALG_ECCGOST, 0))
++	if ((priv->elements[0].tag != TAG(DST_ALG_ECCGOST, 0)) &&
++	    (priv->elements[0].tag != TAG(DST_ALG_ECCGOST, 1)))
+ 		return (-1);
+ 	return (0);
+ }
+ 
+ static int
+ check_ecdsa(const dst_private_t *priv, isc_boolean_t external) {
++	int i, j;
++	isc_boolean_t have[ECDSA_NTAGS];
++	isc_boolean_t ok;
++	unsigned int mask;
+ 
+ 	if (external)
+ 		return ((priv->nelements == 0) ? 0 : -1);
+ 
+-	if (priv->nelements != ECDSA_NTAGS)
+-		return (-1);
+-	if (priv->elements[0].tag != TAG(DST_ALG_ECDSA256, 0))
+-		return (-1);
+-	return (0);
++	for (i = 0; i < ECDSA_NTAGS; i++)
++		have[i] = ISC_FALSE;
++	for (j = 0; j < priv->nelements; j++) {
++		for (i = 0; i < ECDSA_NTAGS; i++)
++			if (priv->elements[j].tag == TAG(DST_ALG_ECDSA256, i))
++				break;
++		if (i == ECDSA_NTAGS)
++			return (-1);
++		have[i] = ISC_TRUE;
++	}
++
++	mask = ~0;
++	mask <<= sizeof(mask) * 8 - TAG_SHIFT;
++	mask >>= sizeof(mask) * 8 - TAG_SHIFT;
++
++	if (have[TAG_ECDSA_ENGINE & mask])
++		ok = have[TAG_ECDSA_LABEL & mask];
++	else
++		ok = have[TAG_ECDSA_PRIVATEKEY & mask];
++	return (ok ? 0 : -1 );
+ }
+ 
+ static int
+diff --git a/lib/dns/dst_parse.h b/lib/dns/dst_parse.h
+index f048bf0..a8a5641 100644
+--- a/lib/dns/dst_parse.h
++++ b/lib/dns/dst_parse.h
+@@ -63,7 +63,6 @@
+ #define TAG_RSA_COEFFICIENT	((DST_ALG_RSAMD5 << TAG_SHIFT) + 7)
+ #define TAG_RSA_ENGINE		((DST_ALG_RSAMD5 << TAG_SHIFT) + 8)
+ #define TAG_RSA_LABEL		((DST_ALG_RSAMD5 << TAG_SHIFT) + 9)
+-#define TAG_RSA_PIN		((DST_ALG_RSAMD5 << TAG_SHIFT) + 10)
+ 
+ #define DH_NTAGS		4
+ #define TAG_DH_PRIME		((DST_ALG_DH << TAG_SHIFT) + 0)
+@@ -80,9 +79,12 @@
+ 
+ #define GOST_NTAGS		1
+ #define TAG_GOST_PRIVASN1	((DST_ALG_ECCGOST << TAG_SHIFT) + 0)
++#define TAG_GOST_PRIVRAW	((DST_ALG_ECCGOST << TAG_SHIFT) + 1)
+ 
+-#define ECDSA_NTAGS		1
++#define ECDSA_NTAGS		4
+ #define TAG_ECDSA_PRIVATEKEY	((DST_ALG_ECDSA256 << TAG_SHIFT) + 0)
++#define TAG_ECDSA_ENGINE	((DST_ALG_ECDSA256 << TAG_SHIFT) + 1)
++#define TAG_ECDSA_LABEL		((DST_ALG_ECDSA256 << TAG_SHIFT) + 2)
+ 
+ #define OLD_HMACMD5_NTAGS	1
+ #define HMACMD5_NTAGS		2
+diff --git a/lib/dns/dst_pkcs11.h b/lib/dns/dst_pkcs11.h
+new file mode 100644
+index 0000000..1c35b6b
+--- /dev/null
++++ b/lib/dns/dst_pkcs11.h
+@@ -0,0 +1,43 @@
++/*
++ * Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#ifndef DST_PKCS11_H
++#define DST_PKCS11_H 1
++
++#include <isc/lang.h>
++#include <isc/log.h>
++#include <isc/result.h>
++
++ISC_LANG_BEGINDECLS
++
++isc_result_t
++dst__pkcs11_toresult(const char *funcname, const char *file, int line,
++		     isc_result_t fallback, CK_RV rv);
++
++#define PK11_CALL(func, args, fallback) \
++	((void) (((rv = (func) args) == CKR_OK) || \
++		 ((ret = dst__pkcs11_toresult(#func, __FILE__, __LINE__, \
++					      fallback, rv)), 0)))
++
++#define PK11_RET(func, args, fallback) \
++	((void) (((rv = (func) args) == CKR_OK) || \
++		 ((ret = dst__pkcs11_toresult(#func, __FILE__, __LINE__, \
++					      fallback, rv)), 0)));	\
++	if (rv != CKR_OK) goto err;
++
++ISC_LANG_ENDDECLS
++
++#endif /* DST_PKCS11_H */
+diff --git a/lib/dns/dst_result.c b/lib/dns/dst_result.c
+index 30aa1fa..79fa7d3 100644
+--- a/lib/dns/dst_result.c
++++ b/lib/dns/dst_result.c
+@@ -50,7 +50,8 @@ static const char *text[DST_R_NRESULTS] = {
+ 	"failure computing a shared secret",	/*%< 18 */
+ 	"no randomness available",		/*%< 19 */
+ 	"bad key type",				/*%< 20 */
+-	"no engine"				/*%< 21 */
++	"no engine",				/*%< 21 */
++	"illegal operation for an external key",/*%< 22 */
+ };
+ 
+ #define DST_RESULT_RESULTSET			2
+diff --git a/lib/dns/gssapi_link.c b/lib/dns/gssapi_link.c
+index 5ad81cd..1c35959 100644
+--- a/lib/dns/gssapi_link.c
++++ b/lib/dns/gssapi_link.c
+@@ -358,6 +358,7 @@ gssapi_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) {
+ 
+ static dst_func_t gssapi_functions = {
+ 	gssapi_create_signverify_ctx,
++	NULL, /*%< createctx2 */
+ 	gssapi_destroy_signverify_ctx,
+ 	gssapi_adddata,
+ 	gssapi_sign,
+diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c
+index 1f1a0ca..7a56c79 100644
+--- a/lib/dns/hmac_link.c
++++ b/lib/dns/hmac_link.c
+@@ -282,6 +282,9 @@ hmacmd5_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	if (result != ISC_R_SUCCESS)
+ 		return (result);
+ 
++	if (key->external)
++		result = DST_R_EXTERNALKEY;
++
+ 	key->key_bits = 0;
+ 	for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) {
+ 		switch (priv.elements[i].tag) {
+@@ -310,6 +313,7 @@ hmacmd5_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 
+ static dst_func_t hmacmd5_functions = {
+ 	hmacmd5_createctx,
++	NULL, /*%< createctx2 */
+ 	hmacmd5_destroyctx,
+ 	hmacmd5_adddata,
+ 	hmacmd5_sign,
+@@ -528,6 +532,9 @@ hmacsha1_tofile(const dst_key_t *key, const char *directory) {
+ 	if (key->keydata.hmacsha1 == NULL)
+ 		return (DST_R_NULLKEY);
+ 
++	if (key->external)
++		return (DST_R_EXTERNALKEY);
++
+ 	hkey = key->keydata.hmacsha1;
+ 
+ 	priv.elements[cnt].tag = TAG_HMACSHA1_KEY;
+@@ -559,8 +566,11 @@ hmacsha1_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	if (result != ISC_R_SUCCESS)
+ 		return (result);
+ 
++	if (key->external)
++		result = DST_R_EXTERNALKEY;
++
+ 	key->key_bits = 0;
+-	for (i = 0; i < priv.nelements; i++) {
++	for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) {
+ 		switch (priv.elements[i].tag) {
+ 		case TAG_HMACSHA1_KEY:
+ 			isc_buffer_init(&b, priv.elements[i].data,
+@@ -587,6 +597,7 @@ hmacsha1_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 
+ static dst_func_t hmacsha1_functions = {
+ 	hmacsha1_createctx,
++	NULL, /*%< createctx2 */
+ 	hmacsha1_destroyctx,
+ 	hmacsha1_adddata,
+ 	hmacsha1_sign,
+@@ -807,6 +818,9 @@ hmacsha224_tofile(const dst_key_t *key, const char *directory) {
+ 	if (key->keydata.hmacsha224 == NULL)
+ 		return (DST_R_NULLKEY);
+ 
++	if (key->external)
++		return (DST_R_EXTERNALKEY);
++
+ 	hkey = key->keydata.hmacsha224;
+ 
+ 	priv.elements[cnt].tag = TAG_HMACSHA224_KEY;
+@@ -838,6 +852,9 @@ hmacsha224_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	if (result != ISC_R_SUCCESS)
+ 		return (result);
+ 
++	if (key->external)
++		result = DST_R_EXTERNALKEY;
++
+ 	key->key_bits = 0;
+ 	for (i = 0; i < priv.nelements; i++) {
+ 		switch (priv.elements[i].tag) {
+@@ -866,6 +883,7 @@ hmacsha224_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 
+ static dst_func_t hmacsha224_functions = {
+ 	hmacsha224_createctx,
++	NULL, /*%< createctx2 */
+ 	hmacsha224_destroyctx,
+ 	hmacsha224_adddata,
+ 	hmacsha224_sign,
+@@ -1086,6 +1104,9 @@ hmacsha256_tofile(const dst_key_t *key, const char *directory) {
+ 	if (key->keydata.hmacsha256 == NULL)
+ 		return (DST_R_NULLKEY);
+ 
++	if (key->external)
++		return (DST_R_EXTERNALKEY);
++
+ 	hkey = key->keydata.hmacsha256;
+ 
+ 	priv.elements[cnt].tag = TAG_HMACSHA256_KEY;
+@@ -1117,8 +1138,11 @@ hmacsha256_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	if (result != ISC_R_SUCCESS)
+ 		return (result);
+ 
++	if (key->external)
++		result = DST_R_EXTERNALKEY;
++
+ 	key->key_bits = 0;
+-	for (i = 0; i < priv.nelements; i++) {
++	for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) {
+ 		switch (priv.elements[i].tag) {
+ 		case TAG_HMACSHA256_KEY:
+ 			isc_buffer_init(&b, priv.elements[i].data,
+@@ -1145,6 +1169,7 @@ hmacsha256_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 
+ static dst_func_t hmacsha256_functions = {
+ 	hmacsha256_createctx,
++	NULL, /*%< createctx2 */
+ 	hmacsha256_destroyctx,
+ 	hmacsha256_adddata,
+ 	hmacsha256_sign,
+@@ -1365,6 +1390,9 @@ hmacsha384_tofile(const dst_key_t *key, const char *directory) {
+ 	if (key->keydata.hmacsha384 == NULL)
+ 		return (DST_R_NULLKEY);
+ 
++	if (key->external)
++		return (DST_R_EXTERNALKEY);
++
+ 	hkey = key->keydata.hmacsha384;
+ 
+ 	priv.elements[cnt].tag = TAG_HMACSHA384_KEY;
+@@ -1396,8 +1424,11 @@ hmacsha384_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	if (result != ISC_R_SUCCESS)
+ 		return (result);
+ 
++	if (key->external)
++		result = DST_R_EXTERNALKEY;
++
+ 	key->key_bits = 0;
+-	for (i = 0; i < priv.nelements; i++) {
++	for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) {
+ 		switch (priv.elements[i].tag) {
+ 		case TAG_HMACSHA384_KEY:
+ 			isc_buffer_init(&b, priv.elements[i].data,
+@@ -1424,6 +1455,7 @@ hmacsha384_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 
+ static dst_func_t hmacsha384_functions = {
+ 	hmacsha384_createctx,
++	NULL, /*%< createctx2 */
+ 	hmacsha384_destroyctx,
+ 	hmacsha384_adddata,
+ 	hmacsha384_sign,
+@@ -1644,6 +1676,9 @@ hmacsha512_tofile(const dst_key_t *key, const char *directory) {
+ 	if (key->keydata.hmacsha512 == NULL)
+ 		return (DST_R_NULLKEY);
+ 
++	if (key->external)
++		return (DST_R_EXTERNALKEY);
++
+ 	hkey = key->keydata.hmacsha512;
+ 
+ 	priv.elements[cnt].tag = TAG_HMACSHA512_KEY;
+@@ -1675,8 +1710,11 @@ hmacsha512_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	if (result != ISC_R_SUCCESS)
+ 		return (result);
+ 
++	if (key->external)
++		result = DST_R_EXTERNALKEY;
++
+ 	key->key_bits = 0;
+-	for (i = 0; i < priv.nelements; i++) {
++	for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) {
+ 		switch (priv.elements[i].tag) {
+ 		case TAG_HMACSHA512_KEY:
+ 			isc_buffer_init(&b, priv.elements[i].data,
+@@ -1703,6 +1741,7 @@ hmacsha512_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 
+ static dst_func_t hmacsha512_functions = {
+ 	hmacsha512_createctx,
++	NULL, /*%< createctx2 */
+ 	hmacsha512_destroyctx,
+ 	hmacsha512_adddata,
+ 	hmacsha512_sign,
+diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h
+index 1fdce4c..bdbd269 100644
+--- a/lib/dns/include/dst/dst.h
++++ b/lib/dns/include/dst/dst.h
+@@ -175,6 +175,16 @@ isc_result_t
+ dst_context_create2(dst_key_t *key, isc_mem_t *mctx,
+ 		    isc_logcategory_t *category, dst_context_t **dctxp);
+ 
++isc_result_t
++dst_context_create3(dst_key_t *key, isc_mem_t *mctx,
++		    isc_logcategory_t *category, isc_boolean_t useforsigning,
++		    dst_context_t **dctxp);
++
++isc_result_t
++dst_context_create4(dst_key_t *key, isc_mem_t *mctx,
++		    isc_logcategory_t *category, isc_boolean_t useforsigning,
++		    int maxbits, dst_context_t **dctxp);
++
+ /*%<
+  * Creates a context to be used for a sign or verify operation.
+  *
+diff --git a/lib/dns/include/dst/result.h b/lib/dns/include/dst/result.h
+index 00640a1..cf9428f 100644
+--- a/lib/dns/include/dst/result.h
++++ b/lib/dns/include/dst/result.h
+@@ -57,8 +57,9 @@
+ #define DST_R_NORANDOMNESS		(ISC_RESULTCLASS_DST + 19)
+ #define DST_R_BADKEYTYPE		(ISC_RESULTCLASS_DST + 20)
+ #define DST_R_NOENGINE			(ISC_RESULTCLASS_DST + 21)
++#define DST_R_EXTERNALKEY		(ISC_RESULTCLASS_DST + 22)
+ 
+-#define DST_R_NRESULTS			22	/* Number of results */
++#define DST_R_NRESULTS			23	/* Number of results */
+ 
+ ISC_LANG_BEGINDECLS
+ 
+diff --git a/lib/dns/openssldh_link.c b/lib/dns/openssldh_link.c
+index 36b8a41..55752da 100644
+--- a/lib/dns/openssldh_link.c
++++ b/lib/dns/openssldh_link.c
+@@ -463,6 +463,9 @@ openssldh_tofile(const dst_key_t *key, const char *directory) {
+ 	if (key->keydata.dh == NULL)
+ 		return (DST_R_NULLKEY);
+ 
++	if (key->external)
++		return (DST_R_EXTERNALKEY);
++
+ 	dh = key->keydata.dh;
+ 
+ 	memset(bufs, 0, sizeof(bufs));
+@@ -528,6 +531,9 @@ openssldh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	if (ret != ISC_R_SUCCESS)
+ 		return (ret);
+ 
++	if (key->external)
++		DST_RET(DST_R_EXTERNALKEY);
++
+ 	dh = DH_new();
+ 	if (dh == NULL)
+ 		DST_RET(ISC_R_NOMEMORY);
+@@ -630,6 +636,7 @@ openssldh_cleanup(void) {
+ 
+ static dst_func_t openssldh_functions = {
+ 	NULL, /*%< createctx */
++	NULL, /*%< createctx2 */
+ 	NULL, /*%< destroyctx */
+ 	NULL, /*%< adddata */
+ 	NULL, /*%< openssldh_sign */
+diff --git a/lib/dns/openssldsa_link.c b/lib/dns/openssldsa_link.c
+index a24baae..fd6e91e 100644
+--- a/lib/dns/openssldsa_link.c
++++ b/lib/dns/openssldsa_link.c
+@@ -522,7 +522,7 @@ openssldsa_tofile(const dst_key_t *key, const char *directory) {
+ 
+ 	if (key->keydata.dsa == NULL)
+ 		return (DST_R_NULLKEY);
+-	
++
+ 	if (key->external) {
+ 		priv.nelements = 0;
+ 		return (dst__privstruct_writefile(key, &priv, directory));
+@@ -573,20 +573,31 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	isc_mem_t *mctx = key->mctx;
+ #define DST_RET(a) {ret = a; goto err;}
+ 
+-	UNUSED(pub);
+-
+ 	/* read private key file */
+ 	ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv);
+ 	if (ret != ISC_R_SUCCESS)
+ 		return (ret);
+ 
++	if (key->external) {
++		if (priv.nelements != 0)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		if (pub == NULL)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		key->keydata.pkey = pub->keydata.pkey;
++		pub->keydata.pkey = NULL;
++		key->key_size = pub->key_size;
++		dst__privstruct_free(&priv, mctx);
++		memset(&priv, 0, sizeof(priv));
++		return (ISC_R_SUCCESS);
++	}
++
+ 	dsa = DSA_new();
+ 	if (dsa == NULL)
+ 		DST_RET(ISC_R_NOMEMORY);
+ 	dsa->flags &= ~DSA_FLAG_CACHE_MONT_P;
+ 	key->keydata.dsa = dsa;
+ 
+-	for (i=0; i < priv.nelements; i++) {
++	for (i = 0; i < priv.nelements; i++) {
+ 		BIGNUM *bn;
+ 		bn = BN_bin2bn(priv.elements[i].data,
+ 			       priv.elements[i].length, NULL);
+@@ -612,22 +623,8 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 		}
+ 	}
+ 	dst__privstruct_free(&priv, mctx);
+-
+-	if (key->external) {
+-		if (pub == NULL)
+-			DST_RET(DST_R_INVALIDPRIVATEKEY);
+-		dsa->q = pub->keydata.dsa->q;
+-		pub->keydata.dsa->q = NULL;
+-		dsa->p = pub->keydata.dsa->p;
+-		pub->keydata.dsa->p = NULL;
+-		dsa->g = pub->keydata.dsa->g;
+-		pub->keydata.dsa->g =  NULL;
+-		dsa->pub_key = pub->keydata.dsa->pub_key;
+-		pub->keydata.dsa->pub_key = NULL;
+-	}
+-
++	memset(&priv, 0, sizeof(priv));
+ 	key->key_size = BN_num_bits(dsa->p);
+-
+ 	return (ISC_R_SUCCESS);
+ 
+  err:
+@@ -639,6 +636,7 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 
+ static dst_func_t openssldsa_functions = {
+ 	openssldsa_createctx,
++	NULL, /*%< createctx2 */
+ 	openssldsa_destroyctx,
+ 	openssldsa_adddata,
+ 	openssldsa_sign,
+diff --git a/lib/dns/opensslecdsa_link.c b/lib/dns/opensslecdsa_link.c
+index 7eff9a0..c64cc55 100644
+--- a/lib/dns/opensslecdsa_link.c
++++ b/lib/dns/opensslecdsa_link.c
+@@ -18,7 +18,7 @@
+ 
+ #include <config.h>
+ 
+-#ifdef HAVE_OPENSSL_ECDSA
++#if defined(OPENSSL) && defined(HAVE_OPENSSL_ECDSA)
+ 
+ #if !defined(HAVE_EVP_SHA256) || !defined(HAVE_EVP_SHA384)
+ #error "ECDSA without EVP for SHA2?"
+@@ -474,7 +474,7 @@ opensslecdsa_tofile(const dst_key_t *key, const char *directory) {
+ 	priv.elements[0].length = BN_num_bytes(privkey);
+ 	BN_bn2bin(privkey, buf);
+ 	priv.elements[0].data = buf;
+-	priv.nelements = ECDSA_NTAGS;
++	priv.nelements = 1;
+ 	ret = dst__privstruct_writefile(key, &priv, directory);
+ 
+  err:
+@@ -519,60 +519,50 @@ static isc_result_t
+ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	dst_private_t priv;
+ 	isc_result_t ret;
+-	EVP_PKEY *pkey, *pubpkey;
+-	EC_KEY *eckey = NULL, *pubeckey = NULL;
+-	const EC_POINT *pubkey;
+-	BIGNUM *privkey;
++	EVP_PKEY *pkey;
++	EC_KEY *eckey = NULL;
++	BIGNUM *privkey = NULL;
+ 	int group_nid;
+ 	isc_mem_t *mctx = key->mctx;
+ 
+ 	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
+ 		key->key_alg == DST_ALG_ECDSA384);
+ 
+-	if (key->key_alg == DST_ALG_ECDSA256)
+-		group_nid = NID_X9_62_prime256v1;
+-	else
+-		group_nid = NID_secp384r1;
+-
+-	eckey = EC_KEY_new_by_curve_name(group_nid);
+-	if (eckey == NULL)
+-		return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
+-
+ 	/* read private key file */
+ 	ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv);
+ 	if (ret != ISC_R_SUCCESS)
+ 		goto err;
+ 
+ 	if (key->external) {
+-		/*
+-		 * Copy the public key to this new key.
+-		 */
+-		if (pub == NULL)
+-			DST_RET(DST_R_INVALIDPRIVATEKEY);
+-		pubpkey = pub->keydata.pkey;
+-		pubeckey = EVP_PKEY_get1_EC_KEY(pubpkey);
+-		if (pubeckey == NULL)
+-			DST_RET(DST_R_INVALIDPRIVATEKEY);
+-		pubkey = EC_KEY_get0_public_key(pubeckey);
+-		if (pubkey == NULL)
+-			DST_RET(DST_R_INVALIDPRIVATEKEY);
+-		if (EC_KEY_set_public_key(eckey, pubkey) != 1)
+-			DST_RET(DST_R_INVALIDPRIVATEKEY);
+-		if (EC_KEY_check_key(eckey) != 1)
++		if (priv.nelements != 0)
+ 			DST_RET(DST_R_INVALIDPRIVATEKEY);
+-	} else {
+-		privkey = BN_bin2bn(priv.elements[0].data,
+-				    priv.elements[0].length, NULL);
+-		if (privkey == NULL)
+-			DST_RET(ISC_R_NOMEMORY);
+-		if (!EC_KEY_set_private_key(eckey, privkey))
+-			DST_RET(ISC_R_NOMEMORY);
+-		if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS)
++		if (pub == NULL)
+ 			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		key->keydata.pkey = pub->keydata.pkey;
++		pub->keydata.pkey = NULL;
+ 		dst__privstruct_free(&priv, mctx);
+ 		memset(&priv, 0, sizeof(priv));
++		return (ISC_R_SUCCESS);
+ 	}
+- 
++
++	if (key->key_alg == DST_ALG_ECDSA256)
++		group_nid = NID_X9_62_prime256v1;
++	else
++		group_nid = NID_secp384r1;
++
++	eckey = EC_KEY_new_by_curve_name(group_nid);
++	if (eckey == NULL)
++		return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
++
++	privkey = BN_bin2bn(priv.elements[0].data,
++			    priv.elements[0].length, NULL);
++	if (privkey == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	if (!EC_KEY_set_private_key(eckey, privkey))
++		DST_RET(ISC_R_NOMEMORY);
++	if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS)
++		DST_RET(DST_R_INVALIDPRIVATEKEY);
++
+ 	pkey = EVP_PKEY_new();
+ 	if (pkey == NULL)
+ 		DST_RET (ISC_R_NOMEMORY);
+@@ -584,10 +574,10 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	ret = ISC_R_SUCCESS;
+ 
+  err:
++	if (privkey != NULL)
++		BN_clear_free(privkey);
+ 	if (eckey != NULL)
+ 		EC_KEY_free(eckey);
+-	if (pubeckey != NULL)
+-		EC_KEY_free(pubeckey);
+ 	dst__privstruct_free(&priv, mctx);
+ 	memset(&priv, 0, sizeof(priv));
+ 	return (ret);
+@@ -595,6 +585,7 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 
+ static dst_func_t opensslecdsa_functions = {
+ 	opensslecdsa_createctx,
++	NULL, /*%< createctx2 */
+ 	opensslecdsa_destroyctx,
+ 	opensslecdsa_adddata,
+ 	opensslecdsa_sign,
+diff --git a/lib/dns/opensslgost_link.c b/lib/dns/opensslgost_link.c
+index 325a7c0..9b4ff55 100644
+--- a/lib/dns/opensslgost_link.c
++++ b/lib/dns/opensslgost_link.c
+@@ -30,6 +30,7 @@
+ #include "dst_internal.h"
+ #include "dst_openssl.h"
+ #include "dst_parse.h"
++#include "dst_gost.h"
+ 
+ #include <openssl/err.h>
+ #include <openssl/objects.h>
+@@ -44,6 +45,60 @@ const EVP_MD *EVP_gost(void) {
+ 	return (opensslgost_digest);
+ }
+ 
++/* ISC methods */
++
++isc_result_t
++isc_gost_init(isc_gost_t *ctx) {
++	const EVP_MD *md;
++	int ret;
++
++	INSIST(ctx != NULL);
++
++	md = EVP_gost();
++	if (md == NULL)
++		return (DST_R_CRYPTOFAILURE);
++	EVP_MD_CTX_init(ctx);
++	ret = EVP_DigestInit(ctx, md);
++	if (ret != 1)
++		return (DST_R_CRYPTOFAILURE);
++	return (ISC_R_SUCCESS);
++}
++
++void
++isc_gost_invalidate(isc_gost_t *ctx) {
++	EVP_MD_CTX_cleanup(ctx);
++}
++
++isc_result_t
++isc_gost_update(isc_gost_t *ctx, const unsigned char *data,
++		unsigned int len)
++{
++	int ret;
++
++	INSIST(ctx != NULL);
++	INSIST(data != NULL);
++
++	ret = EVP_DigestUpdate(ctx, (const void *) data, (size_t) len);
++	if (ret != 1)
++		return (DST_R_CRYPTOFAILURE);
++	return (ISC_R_SUCCESS);
++}
++
++isc_result_t
++isc_gost_final(isc_gost_t *ctx, unsigned char *digest) {
++	int ret;
++
++	INSIST(ctx != NULL);
++	INSIST(digest != NULL);
++
++	ret = EVP_DigestFinal(ctx, digest, NULL);
++	if (ret != 1)
++		return (DST_R_CRYPTOFAILURE);
++	return (ISC_R_SUCCESS);
++}
++
++/* DST methods */
++
+ #define DST_RET(a) {ret = a; goto err;}
+ 
+ static isc_result_t opensslgost_todns(const dst_key_t *key,
+@@ -285,6 +340,8 @@ opensslgost_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 	return (ISC_R_SUCCESS);
+ }
+ 
++#ifdef PREFER_GOSTASN1
++
+ static isc_result_t
+ opensslgost_tofile(const dst_key_t *key, const char *directory) {
+ 	EVP_PKEY *pkey;
+@@ -318,7 +375,7 @@ opensslgost_tofile(const dst_key_t *key, const char *directory) {
+ 	priv.elements[0].tag = TAG_GOST_PRIVASN1;
+ 	priv.elements[0].length = len;
+ 	priv.elements[0].data = der;
+-	priv.nelements = GOST_NTAGS;
++	priv.nelements = 1;
+ 
+ 	result = dst__privstruct_writefile(key, &priv, directory);
+  fail:
+@@ -327,42 +384,146 @@ opensslgost_tofile(const dst_key_t *key, const char *directory) {
+ 	return (result);
+ }
+ 
++#else
++
++static isc_result_t
++opensslgost_tofile(const dst_key_t *key, const char *directory) {
++	EVP_PKEY *pkey;
++	EC_KEY *eckey;
++	const BIGNUM *privkey;
++	dst_private_t priv;
++	isc_result_t ret;
++	unsigned char *buf = NULL;
++
++	if (key->keydata.pkey == NULL)
++		return (DST_R_NULLKEY);
++
++	if (key->external) {
++		priv.nelements = 0;
++		return (dst__privstruct_writefile(key, &priv, directory));
++	}
++
++	pkey = key->keydata.pkey;
++	eckey = EVP_PKEY_get0(pkey);
++	if (eckey == NULL)
++		return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
++	privkey = EC_KEY_get0_private_key(eckey);
++	if (privkey == NULL)
++		return (ISC_R_FAILURE);
++
++	buf = isc_mem_get(key->mctx, BN_num_bytes(privkey));
++	if (buf == NULL)
++		return (ISC_R_NOMEMORY);
++
++	priv.elements[0].tag = TAG_GOST_PRIVRAW;
++	priv.elements[0].length = BN_num_bytes(privkey);
++	BN_bn2bin(privkey, buf);
++	priv.elements[0].data = buf;
++	priv.nelements = 1;
++
++	ret = dst__privstruct_writefile(key, &priv, directory);
++
++	if (buf != NULL)
++		isc_mem_put(key->mctx, buf, BN_num_bytes(privkey));
++	return (ret);
++}
++#endif
++
++static unsigned char gost_dummy_key[71] = {
++	0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06,
++	0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30,
++	0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02,
++	0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02,
++	0x02, 0x1e, 0x01, 0x04, 0x22, 0x02, 0x20, 0x1b,
++	0x3f, 0x94, 0xf7, 0x1a, 0x5f, 0x2f, 0xe7, 0xe5,
++	0x74, 0x0b, 0x8c, 0xd4, 0xb7, 0x18, 0xdd, 0x65,
++	0x68, 0x26, 0xd1, 0x54, 0xfb, 0x77, 0xba, 0x63,
++	0x72, 0xd9, 0xf0, 0x63, 0x87, 0xe0, 0xd6
++};
++
+ static isc_result_t
+ opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	dst_private_t priv;
+ 	isc_result_t ret;
+ 	isc_mem_t *mctx = key->mctx;
+ 	EVP_PKEY *pkey = NULL;
++	EC_KEY *eckey;
++	const EC_POINT *pubkey = NULL;
++	BIGNUM *privkey = NULL;
+ 	const unsigned char *p;
+ 
+-	UNUSED(pub);
+-
+ 	/* read private key file */
+ 	ret = dst__privstruct_parse(key, DST_ALG_ECCGOST, lexer, mctx, &priv);
+ 	if (ret != ISC_R_SUCCESS)
+ 		return (ret);
+ 
+ 	if (key->external) {
+-		INSIST(priv.nelements == 0);
++		if (priv.nelements != 0)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
+ 		if (pub == NULL)
+ 			DST_RET(DST_R_INVALIDPRIVATEKEY);
+ 		key->keydata.pkey = pub->keydata.pkey;
+ 		pub->keydata.pkey = NULL;
+-	} else {
+-		INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1);
++		key->key_size = pub->key_size;
++		dst__privstruct_free(&priv, mctx);
++		memset(&priv, 0, sizeof(priv));
++		return (ISC_R_SUCCESS);
++	}
++
++	INSIST((priv.elements[0].tag == TAG_GOST_PRIVASN1) ||
++	       (priv.elements[0].tag == TAG_GOST_PRIVRAW));
++
++	if (priv.elements[0].tag == TAG_GOST_PRIVASN1) {
+ 		p = priv.elements[0].data;
+ 		if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
+ 				   (long) priv.elements[0].length) == NULL)
+-			DST_RET(dst__openssl_toresult2("d2i_PrivateKey",
+-						     DST_R_INVALIDPRIVATEKEY));
+-		key->keydata.pkey = pkey;
++			DST_RET(dst__openssl_toresult2(
++					    "d2i_PrivateKey",
++					    DST_R_INVALIDPRIVATEKEY));
++	} else {
++		if ((pub != NULL) && (pub->keydata.pkey != NULL)) {
++			eckey = EVP_PKEY_get0(pub->keydata.pkey);
++			pubkey = EC_KEY_get0_public_key(eckey);
++		}
++
++		privkey = BN_bin2bn(priv.elements[0].data,
++				    priv.elements[0].length, NULL);
++		if (privkey == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++
++		/* can't create directly the whole key */
++		p = gost_dummy_key;
++		if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p,
++				   (long) sizeof(gost_dummy_key)) == NULL)
++			DST_RET(dst__openssl_toresult2(
++					    "d2i_PrivateKey",
++					    DST_R_INVALIDPRIVATEKEY));
++
++		eckey = EVP_PKEY_get0(pkey);
++		if (eckey == NULL)
++			return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
++		if (!EC_KEY_set_private_key(eckey, privkey))
++			DST_RET(ISC_R_NOMEMORY);
++
++		/* have to (re)set the public key */
++#ifdef notyet
++		(void) gost2001_compute_public(eckey);
++#else
++		if ((pubkey != NULL) && !EC_KEY_set_public_key(eckey, pubkey))
++			DST_RET(ISC_R_NOMEMORY);
++#endif
++		BN_clear_free(privkey);
++		privkey = NULL;
+ 	}
++	key->keydata.pkey = pkey;
+ 	key->key_size = EVP_PKEY_bits(pkey);
+ 	dst__privstruct_free(&priv, mctx);
+ 	memset(&priv, 0, sizeof(priv));
+ 	return (ISC_R_SUCCESS);
+ 
+  err:
++	if (privkey != NULL)
++		BN_clear_free(privkey);
+ 	if (pkey != NULL)
+ 		EVP_PKEY_free(pkey);
+ 	opensslgost_destroy(key);
+@@ -382,6 +543,7 @@ opensslgost_cleanup(void) {
+ 
+ static dst_func_t opensslgost_functions = {
+ 	opensslgost_createctx,
++	NULL, /*%< createctx2 */
+ 	opensslgost_destroyctx,
+ 	opensslgost_adddata,
+ 	opensslgost_sign,
+diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c
+index 894c7ae..1edeb8d 100644
+--- a/lib/dns/opensslrsa_link.c
++++ b/lib/dns/opensslrsa_link.c
+@@ -1196,6 +1196,24 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	EVP_PKEY *pkey = NULL;
+ #endif
+ 
++	/* read private key file */
++	ret = dst__privstruct_parse(key, DST_ALG_RSA, lexer, mctx, &priv);
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	if (key->external) {
++		if (priv.nelements != 0)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		if (pub == NULL)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		key->keydata.pkey = pub->keydata.pkey;
++		pub->keydata.pkey = NULL;
++		key->key_size = pub->key_size;
++		dst__privstruct_free(&priv, mctx);
++		memset(&priv, 0, sizeof(priv));
++		return (ISC_R_SUCCESS);
++	}
++
+ #if USE_EVP
+ 	if (pub != NULL && pub->keydata.pkey != NULL)
+ 		pubrsa = EVP_PKEY_get1_RSA(pub->keydata.pkey);
+@@ -1206,14 +1224,6 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 	}
+ #endif
+ 
+-	/* read private key file */
+-	ret = dst__privstruct_parse(key, DST_ALG_RSA, lexer, mctx, &priv);
+-	if (ret != ISC_R_SUCCESS)
+-		goto err;
+-
+-	if (key->external && priv.nelements != 0)
+-		DST_RET(DST_R_INVALIDPRIVATEKEY);
+-
+ 	for (i = 0; i < priv.nelements; i++) {
+ 		switch (priv.elements[i].tag) {
+ 		case TAG_RSA_ENGINE:
+@@ -1297,8 +1307,6 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 			continue;
+ 		case TAG_RSA_LABEL:
+ 			continue;
+-		case TAG_RSA_PIN:
+-			continue;
+ 		default:
+ 			bn = BN_bin2bn(priv.elements[i].data,
+ 				       priv.elements[i].length, NULL);
+@@ -1338,10 +1346,8 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
+ 
+ 	if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS)
+ 		DST_RET(DST_R_INVALIDPRIVATEKEY);
+-	if (!key->external) {
+-		if (BN_num_bits(rsa->e) > RSA_MAX_PUBEXP_BITS)
+-			DST_RET(ISC_R_RANGE);
+-	}
++	if (BN_num_bits(rsa->e) > RSA_MAX_PUBEXP_BITS)
++		DST_RET(ISC_R_RANGE);
+ 	key->key_size = BN_num_bits(rsa->n);
+ 	if (pubrsa != NULL)
+ 		RSA_free(pubrsa);
+@@ -1448,6 +1454,7 @@ opensslrsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
+ 
+ static dst_func_t opensslrsa_functions = {
+ 	opensslrsa_createctx,
++	NULL, /*%< createctx2 */
+ 	opensslrsa_destroyctx,
+ 	opensslrsa_adddata,
+ 	opensslrsa_sign,
+diff --git a/lib/dns/pkcs11.c b/lib/dns/pkcs11.c
+new file mode 100644
+index 0000000..7aa15fa
+--- /dev/null
++++ b/lib/dns/pkcs11.c
+@@ -0,0 +1,50 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#ifdef PKCS11CRYPTO
++
++#include <config.h>
++
++#include <dns/log.h>
++#include <dns/result.h>
++
++#include <pk11/pk11.h>
++#include <pk11/internal.h>
++
++#include "dst_pkcs11.h"
++
++isc_result_t
++dst__pkcs11_toresult(const char *funcname, const char *file, int line,
++		     isc_result_t fallback, CK_RV rv)
++{
++	isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
++		      DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING,
++		      "%s:%d: %s: Error = 0x%.8lX\n",
++		      file, line, funcname, rv);
++	if (rv == CKR_HOST_MEMORY)
++		return (ISC_R_NOMEMORY);
++	return (fallback);
++}
++
++
++#else /* PKCS11CRYPTO */
++
++#include <isc/util.h>
++
++EMPTY_TRANSLATION_UNIT
++
++#endif /* PKCS11CRYPTO */
++/*! \file */
+diff --git a/lib/dns/pkcs11dh_link.c b/lib/dns/pkcs11dh_link.c
+new file mode 100644
+index 0000000..87afc02
+--- /dev/null
++++ b/lib/dns/pkcs11dh_link.c
+@@ -0,0 +1,1140 @@
++/*
++ * Portions Copyright (C) 20012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ *
++ * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* $Id$ */
++
++#ifdef PKCS11CRYPTO
++
++#include <config.h>
++
++#include <ctype.h>
++
++#include <isc/mem.h>
++#include <isc/string.h>
++#include <isc/util.h>
++
++#include <dst/result.h>
++
++#include "dst_internal.h"
++#include "dst_parse.h"
++#include "dst_pkcs11.h"
++
++#include <pk11/pk11.h>
++#include <pk11/internal.h>
++#define WANT_DH_PRIMES
++#include <pk11/constants.h>
++
++#include <pkcs11/pkcs11.h>
++
++/*
++ * PKCS#3 DH keys:
++ *  mechanisms:
++ *    CKM_DH_PKCS_PARAMETER_GEN,
++ *    CKM_DH_PKCS_KEY_PAIR_GEN,
++ *    CKM_DH_PKCS_DERIVE
++ *  domain parameters:
++ *    object class CKO_DOMAIN_PARAMETERS
++ *    key type CKK_DH
++ *    attribute CKA_PRIME (prime p)
++ *    attribute CKA_BASE (base g)
++ *    optional attribute CKA_PRIME_BITS (p length in bits)
++ *  public key:
++ *    object class CKO_PUBLIC_KEY
++ *    key type CKK_DH
++ *    attribute CKA_PRIME (prime p)
++ *    attribute CKA_BASE (base g)
++ *    attribute CKA_VALUE (public value y)
++ *  private key:
++ *    object class CKO_PRIVATE_KEY
++ *    key type CKK_DH
++ *    attribute CKA_PRIME (prime p)
++ *    attribute CKA_BASE (base g)
++ *    attribute CKA_VALUE (private value x)
++ *    optional attribute CKA_VALUE_BITS (x length in bits)
++ *  reuse CKA_PRIVATE_EXPONENT for key pair private value
++ */
++
++#define CKA_VALUE2	CKA_PRIVATE_EXPONENT
++
++static CK_BBOOL truevalue = TRUE;
++static CK_BBOOL falsevalue = FALSE;
++
++#define DST_RET(a) {ret = a; goto err;}
++
++static void pkcs11dh_destroy(dst_key_t *key);
++static isc_result_t pkcs11dh_todns(const dst_key_t *key, isc_buffer_t *data);
++
++static isc_result_t
++pkcs11dh_loadpriv(const dst_key_t *key,
++		  CK_SESSION_HANDLE session,
++		  CK_OBJECT_HANDLE *hKey)
++{
++	CK_RV rv;
++	CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
++	CK_KEY_TYPE keyType = CKK_DH;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_DERIVE, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_PRIME, NULL, 0 },
++		{ CKA_BASE, NULL, 0 },
++		{ CKA_VALUE, NULL, 0 }
++	};
++	CK_ATTRIBUTE *attr;
++	const pk11_object_t *priv;
++	isc_result_t ret;
++	unsigned int i;
++
++	priv = key->keydata.pkey;
++	if ((priv->object != CK_INVALID_HANDLE) && priv->ontoken) {
++		*hKey = priv->object;
++		return (ISC_R_SUCCESS);
++	}
++
++	attr = pk11_attribute_bytype(priv, CKA_PRIME);
++	if (attr == NULL)
++		return (DST_R_INVALIDPRIVATEKEY);
++	keyTemplate[6].pValue = isc_mem_get(key->mctx, attr->ulValueLen);
++	if (keyTemplate[6].pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memcpy(keyTemplate[6].pValue, attr->pValue, attr->ulValueLen);
++	keyTemplate[6].ulValueLen = attr->ulValueLen;
++
++	attr = pk11_attribute_bytype(priv, CKA_BASE);
++	if (attr == NULL)
++		DST_RET(DST_R_INVALIDPRIVATEKEY);
++	keyTemplate[7].pValue = isc_mem_get(key->mctx, attr->ulValueLen);
++	if (keyTemplate[7].pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memcpy(keyTemplate[7].pValue, attr->pValue, attr->ulValueLen);
++	keyTemplate[7].ulValueLen = attr->ulValueLen;
++
++	attr = pk11_attribute_bytype(priv, CKA_VALUE2);
++	if (attr == NULL)
++		DST_RET(DST_R_INVALIDPRIVATEKEY);
++	keyTemplate[8].pValue = isc_mem_get(key->mctx, attr->ulValueLen);
++	if (keyTemplate[8].pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memcpy(keyTemplate[8].pValue, attr->pValue, attr->ulValueLen);
++	keyTemplate[8].ulValueLen = attr->ulValueLen;
++
++	PK11_CALL(pkcs_C_CreateObject,
++		  (session, keyTemplate, (CK_ULONG) 9, hKey),
++		  DST_R_COMPUTESECRETFAILURE);
++	if (rv == CKR_OK)
++		ret = ISC_R_SUCCESS;
++
++    err:
++	for (i = 6; i <= 8; i++)
++		if (keyTemplate[i].pValue != NULL) {
++			memset(keyTemplate[i].pValue, 0,
++			       keyTemplate[i].ulValueLen);
++			isc_mem_put(key->mctx,
++				    keyTemplate[i].pValue,
++				    keyTemplate[i].ulValueLen);
++		}
++	return (ret);
++}
++
++static isc_result_t
++pkcs11dh_computesecret(const dst_key_t *pub, const dst_key_t *priv,
++		       isc_buffer_t *secret)
++{
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_DH_PKCS_DERIVE, NULL, 0 };
++	CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
++	CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
++	CK_OBJECT_HANDLE hDerived = CK_INVALID_HANDLE;
++	CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
++	CK_ATTRIBUTE *attr;
++	CK_ULONG secLen;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_VALUE_LEN, &secLen, (CK_ULONG) sizeof(secLen) }
++	};
++	CK_ATTRIBUTE valTemplate[] =
++	{
++		{ CKA_VALUE, NULL, 0 }
++	};
++	CK_BYTE *secValue;
++	pk11_context_t ctx;
++	isc_result_t ret;
++	unsigned int i;
++	isc_region_t r;
++
++	REQUIRE(pub->keydata.pkey != NULL);
++	REQUIRE(priv->keydata.pkey != NULL);
++	REQUIRE(priv->keydata.pkey->repr != NULL);
++	attr = pk11_attribute_bytype(pub->keydata.pkey, CKA_PRIME);
++	if (attr == NULL)
++		return (DST_R_INVALIDPUBLICKEY);
++	REQUIRE(attr != NULL);
++	secLen = attr->ulValueLen;
++	attr = pk11_attribute_bytype(pub->keydata.pkey, CKA_VALUE);
++	if (attr == NULL)
++		return (DST_R_INVALIDPUBLICKEY);
++
++	ret = pk11_get_session(&ctx, OP_DH, ISC_TRUE, ISC_FALSE, ISC_FALSE,
++			       NULL, pk11_get_best_token(OP_DH));
++	if (ret != ISC_R_SUCCESS)
++		return (ret);
++
++	mech.ulParameterLen = attr->ulValueLen;
++	mech.pParameter = isc_mem_get(pub->mctx, mech.ulParameterLen);
++	if (mech.pParameter == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memcpy(mech.pParameter, attr->pValue, mech.ulParameterLen);
++
++	ret = pkcs11dh_loadpriv(priv, ctx.session, &hKey);
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	PK11_RET(pkcs_C_DeriveKey,
++		 (ctx.session, &mech, hKey,
++		  keyTemplate, (CK_ULONG) 6, &hDerived),
++		 DST_R_COMPUTESECRETFAILURE);
++
++	attr = valTemplate;
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (ctx.session, hDerived, attr, (CK_ULONG) 1),
++		 DST_R_CRYPTOFAILURE);
++	attr->pValue = isc_mem_get(pub->mctx, attr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(attr->pValue, 0, attr->ulValueLen);
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (ctx.session, hDerived, attr, (CK_ULONG) 1),
++		 DST_R_CRYPTOFAILURE);
++
++	/* strip leading zeros */
++	secValue = (CK_BYTE_PTR) attr->pValue;
++	for (i = 0; i < attr->ulValueLen; i++)
++		if (secValue[i] != 0)
++			break;
++	isc_buffer_availableregion(secret, &r);
++	if (r.length < attr->ulValueLen - i)
++		DST_RET(ISC_R_NOSPACE);
++	memcpy(r.base, secValue + i, attr->ulValueLen - i);
++	isc_buffer_add(secret, attr->ulValueLen - i);
++	ret = ISC_R_SUCCESS;
++
++    err:
++	if (hDerived != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(ctx.session, hDerived);
++	if (valTemplate[0].pValue != NULL) {
++		memset(valTemplate[0].pValue, 0, valTemplate[0].ulValueLen);
++		isc_mem_put(pub->mctx,
++			    valTemplate[0].pValue,
++			    valTemplate[0].ulValueLen);
++	}
++	if ((hKey != CK_INVALID_HANDLE) && !priv->keydata.pkey->ontoken)
++		(void) pkcs_C_DestroyObject(ctx.session, hKey);
++	if (mech.pParameter != NULL) {
++		memset(mech.pParameter, 0, mech.ulParameterLen);
++		isc_mem_put(pub->mctx, mech.pParameter, mech.ulParameterLen);
++	}
++	pk11_return_session(&ctx);
++	return (ret);
++}
++
++static isc_boolean_t
++pkcs11dh_compare(const dst_key_t *key1, const dst_key_t *key2) {
++	pk11_object_t *dh1, *dh2;
++	CK_ATTRIBUTE *attr1, *attr2;
++
++	dh1 = key1->keydata.pkey;
++	dh2 = key2->keydata.pkey;
++
++	if ((dh1 == NULL) && (dh2 == NULL))
++		return (ISC_TRUE);
++	else if ((dh1 == NULL) || (dh2 == NULL))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(dh1, CKA_PRIME);
++	attr2 = pk11_attribute_bytype(dh2, CKA_PRIME);
++	if ((attr1 == NULL) && (attr2 == NULL))
++		return (ISC_TRUE);
++	else if ((attr1 == NULL) || (attr2 == NULL) ||
++		 (attr1->ulValueLen != attr2->ulValueLen) ||
++		 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(dh1, CKA_BASE);
++	attr2 = pk11_attribute_bytype(dh2, CKA_BASE);
++	if ((attr1 == NULL) && (attr2 == NULL))
++		return (ISC_TRUE);
++	else if ((attr1 == NULL) || (attr2 == NULL) ||
++		 (attr1->ulValueLen != attr2->ulValueLen) ||
++		 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(dh1, CKA_VALUE);
++	attr2 = pk11_attribute_bytype(dh2, CKA_VALUE);
++	if ((attr1 == NULL) && (attr2 == NULL))
++		return (ISC_TRUE);
++	else if ((attr1 == NULL) || (attr2 == NULL) ||
++		 (attr1->ulValueLen != attr2->ulValueLen) ||
++		 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(dh1, CKA_VALUE2);
++	attr2 = pk11_attribute_bytype(dh2, CKA_VALUE2);
++	if (((attr1 != NULL) || (attr2 != NULL)) &&
++	    ((attr1 == NULL) || (attr2 == NULL) ||
++	     (attr1->ulValueLen != attr2->ulValueLen) ||
++	     memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)))
++		return (ISC_FALSE);
++
++	if (!dh1->ontoken && !dh2->ontoken)
++		return (ISC_TRUE);
++	else if (dh1->ontoken || dh2->ontoken ||
++		 (dh1->object != dh2->object))
++		return (ISC_FALSE);
++
++	return (ISC_TRUE);
++}
++
++static isc_boolean_t
++pkcs11dh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
++	pk11_object_t *dh1, *dh2;
++	CK_ATTRIBUTE *attr1, *attr2;
++
++	dh1 = key1->keydata.pkey;
++	dh2 = key2->keydata.pkey;
++
++	if ((dh1 == NULL) && (dh2 == NULL))
++		return (ISC_TRUE);
++	else if ((dh1 == NULL) || (dh2 == NULL))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(dh1, CKA_PRIME);
++	attr2 = pk11_attribute_bytype(dh2, CKA_PRIME);
++	if ((attr1 == NULL) && (attr2 == NULL))
++		return (ISC_TRUE);
++	else if ((attr1 == NULL) || (attr2 == NULL) ||
++		 (attr1->ulValueLen != attr2->ulValueLen) ||
++		 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(dh1, CKA_BASE);
++	attr2 = pk11_attribute_bytype(dh2, CKA_BASE);
++	if ((attr1 == NULL) && (attr2 == NULL))
++		return (ISC_TRUE);
++	else if ((attr1 == NULL) || (attr2 == NULL) ||
++		 (attr1->ulValueLen != attr2->ulValueLen) ||
++		 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))
++		return (ISC_FALSE);
++
++	return (ISC_TRUE);
++}
++
++static isc_result_t
++pkcs11dh_generate(dst_key_t *key, int generator, void (*callback)(int)) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_DH_PKCS_PARAMETER_GEN, NULL, 0 };
++	CK_OBJECT_HANDLE domainparams = CK_INVALID_HANDLE;
++	CK_OBJECT_CLASS dClass = CKO_DOMAIN_PARAMETERS;
++	CK_KEY_TYPE keyType = CKK_DH;
++	CK_ULONG bits = 0;
++	CK_ATTRIBUTE dTemplate[] =
++	{
++		{ CKA_CLASS, &dClass, (CK_ULONG) sizeof(dClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIME_BITS, &bits, (CK_ULONG) sizeof(bits) }
++	};
++	CK_ATTRIBUTE pTemplate[] =
++	{
++		{ CKA_PRIME, NULL, 0 },
++		{ CKA_BASE, NULL, 0 }
++	};
++	CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE;
++	CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY;
++	CK_ATTRIBUTE pubTemplate[] =
++	{
++		{ CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) },
++		{ CKA_KEY_TYPE,&keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIME, NULL, 0 },
++		{ CKA_BASE, NULL, 0 },
++	};
++	CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE;
++	CK_OBJECT_HANDLE privClass = CKO_PRIVATE_KEY;
++	CK_ATTRIBUTE privTemplate[] =
++	{
++		{ CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_DERIVE, &truevalue, (CK_ULONG) sizeof(truevalue) },
++	};
++	CK_ATTRIBUTE *attr;
++	pk11_object_t *dh = NULL;
++	pk11_context_t *pk11_ctx;
++	isc_result_t ret;
++
++	UNUSED(callback);
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		return (ISC_R_NOMEMORY);
++	ret = pk11_get_session(pk11_ctx, OP_DH, ISC_TRUE, ISC_FALSE,
++			       ISC_FALSE, NULL, pk11_get_best_token(OP_DH));
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	bits = key->key_size;
++	if ((generator == 0) &&
++	    ((bits == 768) || (bits == 1024) || (bits == 1536))) {
++		if (bits == 768) {
++			pubTemplate[4].pValue =
++				isc_mem_get(key->mctx, sizeof(pk11_dh_bn768));
++			if (pubTemplate[4].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(pubTemplate[4].pValue,
++			       pk11_dh_bn768, sizeof(pk11_dh_bn768));
++			pubTemplate[4].ulValueLen = sizeof(pk11_dh_bn768);
++		} else if (bits == 1024) {
++			pubTemplate[4].pValue =
++				isc_mem_get(key->mctx, sizeof(pk11_dh_bn1024));
++			if (pubTemplate[4].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(pubTemplate[4].pValue,
++			       pk11_dh_bn1024, sizeof(pk11_dh_bn1024));
++			pubTemplate[4].ulValueLen = sizeof(pk11_dh_bn1024);
++		} else {
++			pubTemplate[4].pValue =
++				isc_mem_get(key->mctx, sizeof(pk11_dh_bn1536));
++			if (pubTemplate[4].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(pubTemplate[4].pValue,
++			       pk11_dh_bn1536, sizeof(pk11_dh_bn1536));
++			pubTemplate[4].ulValueLen = sizeof(pk11_dh_bn1536);
++		}
++		pubTemplate[5].pValue = isc_mem_get(key->mctx,
++						    sizeof(pk11_dh_bn2));
++		if (pubTemplate[5].pValue == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++		memcpy(pubTemplate[5].pValue, pk11_dh_bn2, sizeof(pk11_dh_bn2));
++		pubTemplate[5].ulValueLen = sizeof(pk11_dh_bn2);
++	} else {
++		PK11_RET(pkcs_C_GenerateKey,
++			 (pk11_ctx->session, &mech,
++			  dTemplate, (CK_ULONG) 5, &domainparams),
++			 DST_R_CRYPTOFAILURE);
++		PK11_RET(pkcs_C_GetAttributeValue,
++			 (pk11_ctx->session, domainparams,
++			  pTemplate, (CK_ULONG) 2),
++			 DST_R_CRYPTOFAILURE);
++		pTemplate[0].pValue = isc_mem_get(key->mctx,
++						  pTemplate[0].ulValueLen);
++		if (pTemplate[0].pValue == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++		memset(pTemplate[0].pValue, 0, pTemplate[0].ulValueLen);
++		pTemplate[1].pValue = isc_mem_get(key->mctx,
++						  pTemplate[1].ulValueLen);
++		if (pTemplate[1].pValue == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++		memset(pTemplate[1].pValue, 0, pTemplate[1].ulValueLen);
++		PK11_RET(pkcs_C_GetAttributeValue,
++			 (pk11_ctx->session, domainparams,
++			  pTemplate, (CK_ULONG) 2),
++			 DST_R_CRYPTOFAILURE);
++
++		pubTemplate[4].pValue = pTemplate[0].pValue;
++		pubTemplate[4].ulValueLen = pTemplate[0].ulValueLen;
++		pTemplate[0].pValue = NULL;
++		pubTemplate[5].pValue = pTemplate[1].pValue;
++		pubTemplate[5].ulValueLen = pTemplate[1].ulValueLen;
++		pTemplate[1].pValue = NULL;
++	}
++
++	mech.mechanism = CKM_DH_PKCS_KEY_PAIR_GEN;
++	PK11_RET(pkcs_C_GenerateKeyPair,
++		 (pk11_ctx->session, &mech,
++		  pubTemplate, (CK_ULONG) 6,
++		  privTemplate, (CK_ULONG) 7,
++		  &pub, &priv),
++		 DST_R_CRYPTOFAILURE);
++
++	dh = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*dh));
++	if (dh == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(dh, 0,  sizeof(*dh));
++	key->keydata.pkey = dh;
++	dh->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 4);
++	if (dh->repr == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(dh->repr, 0, sizeof(*attr) * 4);
++	dh->attrcnt = 4;
++
++	attr = dh->repr;
++	attr[0].type = CKA_PRIME;
++	attr[0].pValue = pubTemplate[4].pValue;
++	attr[0].ulValueLen = pubTemplate[4].ulValueLen;
++	pubTemplate[4].pValue = NULL;
++
++	attr[1].type = CKA_BASE;
++	attr[1].pValue = pubTemplate[5].pValue;
++	attr[1].ulValueLen = pubTemplate[5].ulValueLen;
++	pubTemplate[5].pValue =NULL;
++
++	attr += 2;
++	attr->type = CKA_VALUE;
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, pub, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++	attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(attr->pValue, 0, attr->ulValueLen);
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, pub, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++
++	attr++;
++	attr->type = CKA_VALUE;
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, priv, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++	attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(attr->pValue, 0, attr->ulValueLen);
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, priv, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++	attr->type = CKA_VALUE2;
++
++	(void) pkcs_C_DestroyObject(pk11_ctx->session, priv);
++	(void) pkcs_C_DestroyObject(pk11_ctx->session, pub);
++	(void) pkcs_C_DestroyObject(pk11_ctx->session, domainparams);
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ISC_R_SUCCESS);
++
++    err:
++	pkcs11dh_destroy(key);
++	if (priv != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, priv);
++	if (pub != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, pub);
++	if (domainparams != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, domainparams);
++
++	if (pubTemplate[4].pValue != NULL) {
++		memset(pubTemplate[4].pValue, 0, pubTemplate[4].ulValueLen);
++		isc_mem_put(key->mctx,
++			    pubTemplate[4].pValue,
++			    pubTemplate[4].ulValueLen);
++	}
++	if (pubTemplate[5].pValue != NULL) {
++		memset(pubTemplate[5].pValue, 0, pubTemplate[5].ulValueLen);
++		isc_mem_put(key->mctx,
++			    pubTemplate[5].pValue,
++			    pubTemplate[5].ulValueLen);
++	}
++	if (pTemplate[0].pValue != NULL) {
++		memset(pTemplate[0].pValue, 0, pTemplate[0].ulValueLen);
++		isc_mem_put(key->mctx,
++			    pTemplate[0].pValue,
++			    pTemplate[0].ulValueLen);
++	}
++	if (pTemplate[1].pValue != NULL) {
++		memset(pTemplate[1].pValue, 0, pTemplate[1].ulValueLen);
++		isc_mem_put(key->mctx,
++			    pTemplate[1].pValue,
++			    pTemplate[1].ulValueLen);
++	}
++
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ret);
++}
++
++static isc_boolean_t
++pkcs11dh_isprivate(const dst_key_t *key) {
++	pk11_object_t *dh = key->keydata.pkey;
++	CK_ATTRIBUTE *attr;
++
++	if (dh == NULL)
++		return (ISC_FALSE);
++	attr = pk11_attribute_bytype(dh, CKA_VALUE2);
++	return (ISC_TF((attr != NULL) || dh->ontoken));
++}
++
++static void
++pkcs11dh_destroy(dst_key_t *key) {
++	pk11_object_t *dh = key->keydata.pkey;
++	CK_ATTRIBUTE *attr;
++
++	if (dh == NULL)
++		return;
++
++	INSIST((dh->object == CK_INVALID_HANDLE) || dh->ontoken);
++
++	for (attr = pk11_attribute_first(dh);
++	     attr != NULL;
++	     attr = pk11_attribute_next(dh, attr))
++		switch (attr->type) {
++		case CKA_VALUE:
++		case CKA_VALUE2:
++		case CKA_PRIME:
++		case CKA_BASE:
++			if (attr->pValue != NULL) {
++				memset(attr->pValue, 0, attr->ulValueLen);
++				isc_mem_put(key->mctx,
++					    attr->pValue,
++					    attr->ulValueLen);
++			}
++			break;
++		}
++	if (dh->repr != NULL) {
++		memset(dh->repr, 0, dh->attrcnt * sizeof(*attr));
++		isc_mem_put(key->mctx, dh->repr, dh->attrcnt * sizeof(*attr));
++	}
++	memset(dh, 0, sizeof(*dh));
++	isc_mem_put(key->mctx, dh, sizeof(*dh));
++	key->keydata.pkey = NULL;
++}
++
++static void
++uint16_toregion(isc_uint16_t val, isc_region_t *region) {
++	*region->base++ = (val & 0xff00) >> 8;
++	*region->base++ = (val & 0x00ff);
++}
++
++static isc_uint16_t
++uint16_fromregion(isc_region_t *region) {
++	isc_uint16_t val;
++	unsigned char *cp = region->base;
++
++	val = ((unsigned int)(cp[0])) << 8;
++	val |= ((unsigned int)(cp[1]));
++
++	region->base += 2;
++	return (val);
++}
++
++static isc_result_t
++pkcs11dh_todns(const dst_key_t *key, isc_buffer_t *data) {
++	pk11_object_t *dh;
++	CK_ATTRIBUTE *attr;
++	isc_region_t r;
++	isc_uint16_t dnslen, plen = 0, glen = 0, publen = 0;
++	CK_BYTE *prime = NULL, *base = NULL, *pub = NULL;
++
++	REQUIRE(key->keydata.pkey != NULL);
++
++	dh = key->keydata.pkey;
++
++	for (attr = pk11_attribute_first(dh);
++	     attr != NULL;
++	     attr = pk11_attribute_next(dh, attr))
++		switch (attr->type) {
++		case CKA_VALUE:
++			pub = (CK_BYTE *) attr->pValue;
++			publen = (isc_uint16_t) attr->ulValueLen;
++			break;
++		case CKA_PRIME:
++			prime = (CK_BYTE *) attr->pValue;
++			plen = (isc_uint16_t) attr->ulValueLen;
++			break;
++		case CKA_BASE:
++			base = (CK_BYTE *) attr->pValue;
++			glen = (isc_uint16_t) attr->ulValueLen;
++			break;
++		}
++	REQUIRE((prime != NULL) && (base != NULL) && (pub != NULL));
++
++	isc_buffer_availableregion(data, &r);
++
++	if ((glen == 1) && (memcmp(pk11_dh_bn2, base, glen) == 0) &&
++	    (((plen == sizeof(pk11_dh_bn768)) &&
++	      (memcmp(pk11_dh_bn768, prime, plen) == 0)) ||
++	     ((plen == sizeof(pk11_dh_bn1024)) &&
++	      (memcmp(pk11_dh_bn1024, prime, plen) == 0)) ||
++	     ((plen == sizeof(pk11_dh_bn1536)) &&
++	      (memcmp(pk11_dh_bn1536, prime, plen) == 0)))) {
++		plen = 1;
++		glen = 0;
++	}
++
++	dnslen = plen + glen + publen + 6;
++	if (r.length < (unsigned int) dnslen)
++		return (ISC_R_NOSPACE);
++
++	uint16_toregion(plen, &r);
++	if (plen == 1) {
++		if (memcmp(pk11_dh_bn768, prime, sizeof(pk11_dh_bn768)) == 0)
++			*r.base = 1;
++		else if (memcmp(pk11_dh_bn1024, prime,
++				sizeof(pk11_dh_bn1024)) == 0)
++			*r.base = 2;
++		else
++			*r.base = 3;
++	}
++	else
++		memcpy(r.base, prime, plen);
++	r.base += plen;
++
++	uint16_toregion(glen, &r);
++	if (glen > 0)
++		memcpy(r.base, base, glen);
++	r.base += glen;
++
++	uint16_toregion(publen, &r);
++	memcpy(r.base, pub, publen);
++	r.base += publen;
++
++	isc_buffer_add(data, dnslen);
++
++	return (ISC_R_SUCCESS);
++}
++
++static isc_result_t
++pkcs11dh_fromdns(dst_key_t *key, isc_buffer_t *data) {
++	pk11_object_t *dh;
++	isc_region_t r;
++	isc_uint16_t plen, glen, plen_, glen_, publen;
++	CK_BYTE *prime = NULL, *base = NULL, *pub = NULL;
++	CK_ATTRIBUTE *attr;
++	int special = 0;
++
++	isc_buffer_remainingregion(data, &r);
++	if (r.length == 0)
++		return (ISC_R_SUCCESS);
++
++	dh = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*dh));
++	if (dh == NULL)
++		return (ISC_R_NOMEMORY);
++	memset(dh, 0, sizeof(*dh));
++
++	/*
++	 * Read the prime length.  1 & 2 are table entries, > 16 means a
++	 * prime follows, otherwise an error.
++	 */
++	if (r.length < 2) {
++		memset(dh, 0, sizeof(*dh));
++		isc_mem_put(key->mctx, dh, sizeof(*dh));
++		return (DST_R_INVALIDPUBLICKEY);
++	}
++	plen = uint16_fromregion(&r);
++	if (plen < 16 && plen != 1 && plen != 2) {
++		memset(dh, 0, sizeof(*dh));
++		isc_mem_put(key->mctx, dh, sizeof(*dh));
++		return (DST_R_INVALIDPUBLICKEY);
++	}
++	if (r.length < plen) {
++		memset(dh, 0, sizeof(*dh));
++		isc_mem_put(key->mctx, dh, sizeof(*dh));
++		return (DST_R_INVALIDPUBLICKEY);
++	}
++	plen_ = plen;
++	if (plen == 1 || plen == 2) {
++		if (plen == 1)
++			special = *r.base++;
++		else
++			special = uint16_fromregion(&r);
++		switch (special) {
++			case 1:
++				prime = pk11_dh_bn768;
++				plen_ = sizeof(pk11_dh_bn768);
++				break;
++			case 2:
++				prime = pk11_dh_bn1024;
++				plen_ = sizeof(pk11_dh_bn1024);
++				break;
++			case 3:
++				prime = pk11_dh_bn1536;
++				plen_ = sizeof(pk11_dh_bn1536);
++				break;
++			default:
++				memset(dh, 0, sizeof(*dh));
++				isc_mem_put(key->mctx, dh, sizeof(*dh));
++				return (DST_R_INVALIDPUBLICKEY);
++		}
++	}
++	else {
++		prime = r.base;
++		r.base += plen;
++	}
++
++	/*
++	 * Read the generator length.  This should be 0 if the prime was
++	 * special, but it might not be.  If it's 0 and the prime is not
++	 * special, we have a problem.
++	 */
++	if (r.length < 2) {
++		memset(dh, 0, sizeof(*dh));
++		isc_mem_put(key->mctx, dh, sizeof(*dh));
++		return (DST_R_INVALIDPUBLICKEY);
++	}
++	glen = uint16_fromregion(&r);
++	if (r.length < glen) {
++		memset(dh, 0, sizeof(*dh));
++		isc_mem_put(key->mctx, dh, sizeof(*dh));
++		return (DST_R_INVALIDPUBLICKEY);
++	}
++	glen_ = glen;
++	if (special != 0) {
++		if (glen == 0) {
++			base = pk11_dh_bn2;
++			glen_ = sizeof(pk11_dh_bn2);
++		}
++		else {
++			base = r.base;
++			if (memcmp(base, pk11_dh_bn2, glen) == 0) {
++				base = pk11_dh_bn2;
++				glen_ = sizeof(pk11_dh_bn2);
++			}
++			else {
++				memset(dh, 0, sizeof(*dh));
++				isc_mem_put(key->mctx, dh, sizeof(*dh));
++				return (DST_R_INVALIDPUBLICKEY);
++			}
++		}
++	}
++	else {
++		if (glen == 0) {
++			memset(dh, 0, sizeof(*dh));
++			isc_mem_put(key->mctx, dh, sizeof(*dh));
++			return (DST_R_INVALIDPUBLICKEY);
++		}
++		base = r.base;
++	}
++	r.base += glen;
++
++	if (r.length < 2) {
++		memset(dh, 0, sizeof(*dh));
++		isc_mem_put(key->mctx, dh, sizeof(*dh));
++		return (DST_R_INVALIDPUBLICKEY);
++	}
++	publen = uint16_fromregion(&r);
++	if (r.length < publen) {
++		memset(dh, 0, sizeof(*dh));
++		isc_mem_put(key->mctx, dh, sizeof(*dh));
++		return (DST_R_INVALIDPUBLICKEY);
++	}
++	pub = r.base;
++	r.base += publen;
++
++	key->key_size = pk11_numbits(prime, plen_);
++
++	dh->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 3);
++	if (dh->repr == NULL)
++		goto nomemory;
++	memset(dh->repr, 0, sizeof(*attr) * 3);
++	dh->attrcnt = 3;
++
++	attr = dh->repr;
++	attr[0].type = CKA_PRIME;
++	attr[0].pValue = isc_mem_get(key->mctx, plen_);
++	if (attr[0].pValue == NULL)
++		goto nomemory;
++	memcpy(attr[0].pValue, prime, plen_);
++	attr[0].ulValueLen = (CK_ULONG) plen_;
++
++	attr[1].type = CKA_BASE;
++	attr[1].pValue = isc_mem_get(key->mctx, glen_);
++	if (attr[1].pValue == NULL)
++		goto nomemory;
++	memcpy(attr[1].pValue, base, glen_);
++	attr[1].ulValueLen = (CK_ULONG) glen_;
++
++	attr[2].type = CKA_VALUE;
++	attr[2].pValue = isc_mem_get(key->mctx, publen);
++	if (attr[2].pValue == NULL)
++		goto nomemory;
++	memcpy(attr[2].pValue, pub, publen);
++	attr[2].ulValueLen = (CK_ULONG) publen;
++
++	isc_buffer_forward(data, plen + glen + publen + 6);
++
++	key->keydata.pkey = dh;
++
++	return (ISC_R_SUCCESS);
++
++    nomemory:
++	for (attr = pk11_attribute_first(dh);
++	     attr != NULL;
++	     attr = pk11_attribute_next(dh, attr))
++		switch (attr->type) {
++		case CKA_VALUE:
++		case CKA_PRIME:
++		case CKA_BASE:
++			if (attr->pValue != NULL) {
++				memset(attr->pValue, 0, attr->ulValueLen);
++				isc_mem_put(key->mctx,
++					    attr->pValue,
++					    attr->ulValueLen);
++			}
++			break;
++		}
++	if (dh->repr != NULL) {
++		memset(dh->repr, 0, dh->attrcnt * sizeof(*attr));
++		isc_mem_put(key->mctx, dh->repr, dh->attrcnt * sizeof(*attr));
++	}
++	memset(dh, 0, sizeof(*dh));
++	isc_mem_put(key->mctx, dh, sizeof(*dh));
++	return (ISC_R_NOMEMORY);
++}
++
++static isc_result_t
++pkcs11dh_tofile(const dst_key_t *key, const char *directory) {
++	int i;
++	pk11_object_t *dh;
++	CK_ATTRIBUTE *attr;
++	CK_ATTRIBUTE *prime = NULL, *base = NULL, *pub = NULL, *prv = NULL;
++	dst_private_t priv;
++	unsigned char *bufs[4];
++	isc_result_t result;
++
++	if (key->keydata.pkey == NULL)
++		return (DST_R_NULLKEY);
++
++	if (key->external)
++		return (DST_R_EXTERNALKEY);
++
++	dh = key->keydata.pkey;
++
++	for (attr = pk11_attribute_first(dh);
++	     attr != NULL;
++	     attr = pk11_attribute_next(dh, attr))
++		switch (attr->type) {
++		case CKA_VALUE:
++			pub = attr;
++			break;
++		case CKA_VALUE2:
++			prv = attr;
++			break;
++		case CKA_PRIME:
++			prime = attr;
++			break;
++		case CKA_BASE:
++			base = attr;
++			break;
++		}
++	if ((prime == NULL) || (base == NULL) ||
++	    (pub == NULL) || (prv == NULL))
++		return (DST_R_NULLKEY);
++
++	memset(bufs, 0, sizeof(bufs));
++	for (i = 0; i < 4; i++) {
++		bufs[i] = isc_mem_get(key->mctx, prime->ulValueLen);
++		if (bufs[i] == NULL) {
++			result = ISC_R_NOMEMORY;
++			goto fail;
++		}
++		memset(bufs[i], 0, prime->ulValueLen);
++	}
++
++	i = 0;
++
++	priv.elements[i].tag = TAG_DH_PRIME;
++	priv.elements[i].length = (unsigned short) prime->ulValueLen;
++	memcpy(bufs[i], prime->pValue, prime->ulValueLen);
++	priv.elements[i].data = bufs[i];
++	i++;
++
++	priv.elements[i].tag = TAG_DH_GENERATOR;
++	priv.elements[i].length = (unsigned short) base->ulValueLen;
++	memcpy(bufs[i], base->pValue, base->ulValueLen);
++	priv.elements[i].data = bufs[i];
++	i++;
++
++	priv.elements[i].tag = TAG_DH_PRIVATE;
++	priv.elements[i].length = (unsigned short) prv->ulValueLen;
++	memcpy(bufs[i], prv->pValue, prv->ulValueLen);
++	priv.elements[i].data = bufs[i];
++	i++;
++
++	priv.elements[i].tag = TAG_DH_PUBLIC;
++	priv.elements[i].length = (unsigned short) pub->ulValueLen;
++	memcpy(bufs[i], pub->pValue, pub->ulValueLen);
++	priv.elements[i].data = bufs[i];
++	i++;
++
++	priv.nelements = i;
++	result = dst__privstruct_writefile(key, &priv, directory);
++ fail:
++	for (i = 0; i < 4; i++) {
++		if (bufs[i] == NULL)
++			break;
++		memset(bufs[i], 0, prime->ulValueLen);
++		isc_mem_put(key->mctx, bufs[i], prime->ulValueLen);
++	}
++	return (result);
++}
++
++static isc_result_t
++pkcs11dh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
++	dst_private_t priv;
++	isc_result_t ret;
++	int i;
++	pk11_object_t *dh = NULL;
++	CK_ATTRIBUTE *attr;
++	isc_mem_t *mctx;
++
++	UNUSED(pub);
++	mctx = key->mctx;
++
++	/* read private key file */
++	ret = dst__privstruct_parse(key, DST_ALG_DH, lexer, mctx, &priv);
++	if (ret != ISC_R_SUCCESS)
++		return (ret);
++
++	if (key->external)
++		DST_RET(DST_R_EXTERNALKEY);
++
++	dh = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*dh));
++	if (dh == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(dh, 0, sizeof(*dh));
++	key->keydata.pkey = dh;
++	dh->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 4);
++	if (dh->repr == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(dh->repr, 0, sizeof(*attr) * 4);
++	dh->attrcnt = 4;
++	attr = dh->repr;
++	attr[0].type = CKA_PRIME;
++	attr[1].type = CKA_BASE;
++	attr[2].type = CKA_VALUE;
++	attr[3].type = CKA_VALUE2;
++
++	for (i = 0; i < priv.nelements; i++) {
++		CK_BYTE *bn;
++
++		bn = isc_mem_get(key->mctx, priv.elements[i].length);
++		if (bn == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++		memcpy(bn, priv.elements[i].data, priv.elements[i].length);
++
++		switch (priv.elements[i].tag) {
++			case TAG_DH_PRIME:
++				attr = pk11_attribute_bytype(dh, CKA_PRIME);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++			case TAG_DH_GENERATOR:
++				attr = pk11_attribute_bytype(dh, CKA_BASE);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++			case TAG_DH_PRIVATE:
++				attr = pk11_attribute_bytype(dh, CKA_VALUE2);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++			case TAG_DH_PUBLIC:
++				attr = pk11_attribute_bytype(dh, CKA_VALUE);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++		}
++	}
++	dst__privstruct_free(&priv, mctx);
++
++	attr = pk11_attribute_bytype(dh, CKA_PRIME);
++	INSIST(attr != NULL);
++	key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen);
++
++	return (ISC_R_SUCCESS);
++
++ err:
++	pkcs11dh_destroy(key);
++	dst__privstruct_free(&priv, mctx);
++	memset(&priv, 0, sizeof(priv));
++	return (ret);
++}
++
++static dst_func_t pkcs11dh_functions = {
++	NULL, /*%< createctx */
++	NULL, /*%< createctx2 */
++	NULL, /*%< destroyctx */
++	NULL, /*%< adddata */
++	NULL, /*%< sign */
++	NULL, /*%< verify */
++	NULL, /*%< verify2 */
++	pkcs11dh_computesecret,
++	pkcs11dh_compare,
++	pkcs11dh_paramcompare,
++	pkcs11dh_generate,
++	pkcs11dh_isprivate,
++	pkcs11dh_destroy,
++	pkcs11dh_todns,
++	pkcs11dh_fromdns,
++	pkcs11dh_tofile,
++	pkcs11dh_parse,
++	NULL, /*%< cleanup */
++	NULL, /*%< fromlabel */
++	NULL, /*%< dump */
++	NULL, /*%< restore */
++};
++
++isc_result_t
++dst__pkcs11dh_init(dst_func_t **funcp) {
++	REQUIRE(funcp != NULL);
++	if (*funcp == NULL)
++		*funcp = &pkcs11dh_functions;
++	return (ISC_R_SUCCESS);
++}
++
++#else /* PKCS11CRYPTO */
++
++#include <isc/util.h>
++
++EMPTY_TRANSLATION_UNIT
++
++#endif /* PKCS11CRYPTO */
++/*! \file */
+diff --git a/lib/dns/pkcs11dsa_link.c b/lib/dns/pkcs11dsa_link.c
+new file mode 100644
+index 0000000..6c8e46c
+--- /dev/null
++++ b/lib/dns/pkcs11dsa_link.c
+@@ -0,0 +1,1130 @@
++/*
++ * Portions Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ *
++ * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* $Id$ */
++
++#ifdef PKCS11CRYPTO
++
++#include <config.h>
++
++#include <string.h>
++
++#include <isc/entropy.h>
++#include <isc/mem.h>
++#include <isc/sha1.h>
++#include <isc/util.h>
++
++#include <dst/result.h>
++
++#include "dst_internal.h"
++#include "dst_parse.h"
++#include "dst_pkcs11.h"
++
++#include <pk11/internal.h>
++
++/*
++ * FIPS 186-2 DSA keys:
++ *  mechanisms:
++ *    CKM_DSA_SHA1,
++ *    CKM_DSA_KEY_PAIR_GEN,
++ *    CKM_DSA_PARAMETER_GEN
++ *  domain parameters:
++ *    object class CKO_DOMAIN_PARAMETERS
++ *    key type CKK_DSA
++ *    attribute CKA_PRIME (prime p)
++ *    attribute CKA_SUBPRIME (subprime q)
++ *    attribute CKA_BASE (base g)
++ *    optional attribute CKA_PRIME_BITS (p length in bits)
++ *  public keys:
++ *    object class CKO_PUBLIC_KEY
++ *    key type CKK_DSA
++ *    attribute CKA_PRIME (prime p)
++ *    attribute CKA_SUBPRIME (subprime q)
++ *    attribute CKA_BASE (base g)
++ *    attribute CKA_VALUE (public value y)
++ *  private keys:
++ *    object class CKO_PRIVATE_KEY
++ *    key type CKK_DSA
++ *    attribute CKA_PRIME (prime p)
++ *    attribute CKA_SUBPRIME (subprime q)
++ *    attribute CKA_BASE (base g)
++ *    attribute CKA_VALUE (private value x)
++ *  reuse CKA_PRIVATE_EXPONENT for key pair private value
++ */
++
++#define CKA_VALUE2	CKA_PRIVATE_EXPONENT
++
++#define DST_RET(a) {ret = a; goto err;}
++
++static CK_BBOOL truevalue = TRUE;
++static CK_BBOOL falsevalue = FALSE;
++
++static isc_result_t pkcs11dsa_todns(const dst_key_t *key, isc_buffer_t *data);
++static void pkcs11dsa_destroy(dst_key_t *key);
++
++static isc_result_t
++pkcs11dsa_createctx_sign(dst_key_t *key, dst_context_t *dctx) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_DSA_SHA1, NULL, 0 };
++	CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
++	CK_KEY_TYPE keyType = CKK_DSA;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_PRIME, NULL, 0 },
++		{ CKA_SUBPRIME, NULL, 0 },
++		{ CKA_BASE, NULL, 0 },
++		{ CKA_VALUE, NULL, 0 }
++	};
++	CK_ATTRIBUTE *attr;
++	pk11_object_t *dsa;
++	pk11_context_t *pk11_ctx;
++	isc_result_t ret;
++	unsigned int i;
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		return (ISC_R_NOMEMORY);
++	ret = pk11_get_session(pk11_ctx, OP_DSA, ISC_TRUE, ISC_FALSE,
++			       ISC_FALSE, NULL, pk11_get_best_token(OP_DSA));
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	dsa = key->keydata.pkey;
++	if (dsa->ontoken && (dsa->object != CK_INVALID_HANDLE)) {
++		pk11_ctx->ontoken = dsa->ontoken;
++		pk11_ctx->object = dsa->object;
++		goto token_key;
++	}
++
++	for (attr = pk11_attribute_first(dsa);
++	     attr != NULL;
++	     attr = pk11_attribute_next(dsa, attr))
++		switch (attr->type) {
++		case CKA_PRIME:
++			INSIST(keyTemplate[6].type == attr->type);
++			keyTemplate[6].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[6].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[6].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[6].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_SUBPRIME:
++			INSIST(keyTemplate[7].type == attr->type);
++			keyTemplate[7].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[7].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[7].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[7].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_BASE:
++			INSIST(keyTemplate[8].type == attr->type);
++			keyTemplate[8].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[8].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[8].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[8].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_VALUE2:
++			INSIST(keyTemplate[9].type == CKA_VALUE);
++			keyTemplate[9].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[9].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[9].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[9].ulValueLen = attr->ulValueLen;
++			break;
++		}
++	pk11_ctx->object = CK_INVALID_HANDLE;
++	pk11_ctx->ontoken = ISC_FALSE;
++	PK11_RET(pkcs_C_CreateObject,
++		 (pk11_ctx->session,
++		  keyTemplate, (CK_ULONG) 10,
++		  &pk11_ctx->object),
++		 ISC_R_FAILURE);
++
++    token_key:
++
++	PK11_RET(pkcs_C_SignInit,
++		 (pk11_ctx->session, &mech, pk11_ctx->object),
++		 ISC_R_FAILURE);
++
++	dctx->ctxdata.pk11_ctx = pk11_ctx;
++
++	for (i = 6; i <= 9; i++)
++		if (keyTemplate[i].pValue != NULL) {
++			memset(keyTemplate[i].pValue, 0,
++			       keyTemplate[i].ulValueLen);
++			isc_mem_put(dctx->mctx,
++				    keyTemplate[i].pValue,
++				    keyTemplate[i].ulValueLen);
++		}
++
++	return (ISC_R_SUCCESS);
++
++    err:
++	if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE))
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, pk11_ctx->object);
++	for (i = 6; i <= 9; i++)
++		if (keyTemplate[i].pValue != NULL) {
++			memset(keyTemplate[i].pValue, 0,
++			       keyTemplate[i].ulValueLen);
++			isc_mem_put(dctx->mctx,
++				    keyTemplate[i].pValue,
++				    keyTemplate[i].ulValueLen);
++		}
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ret);
++}
++
++static isc_result_t
++pkcs11dsa_createctx_verify(dst_key_t *key, dst_context_t *dctx) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_DSA_SHA1, NULL, 0 };
++	CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
++	CK_KEY_TYPE keyType = CKK_DSA;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_PRIME, NULL, 0 },
++		{ CKA_SUBPRIME, NULL, 0 },
++		{ CKA_BASE, NULL, 0 },
++		{ CKA_VALUE, NULL, 0 }
++	};
++	CK_ATTRIBUTE *attr;
++	pk11_object_t *dsa;
++	pk11_context_t *pk11_ctx;
++	isc_result_t ret;
++	unsigned int i;
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		return (ISC_R_NOMEMORY);
++	ret = pk11_get_session(pk11_ctx, OP_DSA, ISC_TRUE, ISC_FALSE,
++			       ISC_FALSE, NULL, pk11_get_best_token(OP_DSA));
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	dsa = key->keydata.pkey;
++	if (dsa->ontoken && (dsa->object != CK_INVALID_HANDLE)) {
++		pk11_ctx->ontoken = dsa->ontoken;
++		pk11_ctx->object = dsa->object;
++		goto token_key;
++	}
++
++	for (attr = pk11_attribute_first(dsa);
++	     attr != NULL;
++	     attr = pk11_attribute_next(dsa, attr))
++		switch (attr->type) {
++		case CKA_PRIME:
++			INSIST(keyTemplate[5].type == attr->type);
++			keyTemplate[5].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[5].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[5].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[5].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_SUBPRIME:
++			INSIST(keyTemplate[6].type == attr->type);
++			keyTemplate[6].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[6].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[6].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[6].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_BASE:
++			INSIST(keyTemplate[7].type == attr->type);
++			keyTemplate[7].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[7].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[7].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[7].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_VALUE:
++			INSIST(keyTemplate[8].type == attr->type);
++			keyTemplate[8].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[8].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[8].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[8].ulValueLen = attr->ulValueLen;
++			break;
++		}
++	pk11_ctx->object = CK_INVALID_HANDLE;
++	pk11_ctx->ontoken = ISC_FALSE;
++	PK11_RET(pkcs_C_CreateObject,
++		 (pk11_ctx->session,
++		  keyTemplate, (CK_ULONG) 9,
++		  &pk11_ctx->object),
++		 ISC_R_FAILURE);
++
++    token_key:
++
++	PK11_RET(pkcs_C_VerifyInit,
++		 (pk11_ctx->session, &mech, pk11_ctx->object),
++		 ISC_R_FAILURE);
++
++	dctx->ctxdata.pk11_ctx = pk11_ctx;
++
++	for (i = 5; i <= 8; i++)
++		if (keyTemplate[i].pValue != NULL) {
++			memset(keyTemplate[i].pValue, 0,
++			       keyTemplate[i].ulValueLen);
++			isc_mem_put(dctx->mctx,
++				    keyTemplate[i].pValue,
++				    keyTemplate[i].ulValueLen);
++		}
++
++	return (ISC_R_SUCCESS);
++
++    err:
++	if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE))
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, pk11_ctx->object);
++	for (i = 5; i <= 8; i++)
++		if (keyTemplate[i].pValue != NULL) {
++			memset(keyTemplate[i].pValue, 0,
++			       keyTemplate[i].ulValueLen);
++			isc_mem_put(dctx->mctx,
++				    keyTemplate[i].pValue,
++				    keyTemplate[i].ulValueLen);
++		}
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ret);
++}
++
++static isc_result_t
++pkcs11dsa_createctx(dst_key_t *key, dst_context_t *dctx) {
++	if (dctx->use == DO_SIGN)
++		return (pkcs11dsa_createctx_sign(key, dctx));
++	else
++		return (pkcs11dsa_createctx_verify(key, dctx));
++}
++
++static void
++pkcs11dsa_destroyctx(dst_context_t *dctx) {
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++
++	if (pk11_ctx != NULL) {
++		if (!pk11_ctx->ontoken &&
++		    (pk11_ctx->object != CK_INVALID_HANDLE))
++			(void) pkcs_C_DestroyObject(pk11_ctx->session,
++					       pk11_ctx->object);
++		pk11_return_session(pk11_ctx);
++		memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++		isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
++		dctx->ctxdata.pk11_ctx = NULL;
++	}
++}
++
++static isc_result_t
++pkcs11dsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
++	CK_RV rv;
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++	isc_result_t ret = ISC_R_SUCCESS;
++
++	if (dctx->use == DO_SIGN)
++		PK11_CALL(pkcs_C_SignUpdate,
++			  (pk11_ctx->session,
++			   (CK_BYTE_PTR) data->base,
++			   (CK_ULONG) data->length),
++			  ISC_R_FAILURE);
++	else
++		PK11_CALL(pkcs_C_VerifyUpdate,
++			  (pk11_ctx->session,
++			   (CK_BYTE_PTR) data->base,
++			   (CK_ULONG) data->length),
++			  ISC_R_FAILURE);
++	return (ret);
++}
++
++static isc_result_t
++pkcs11dsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
++	CK_RV rv;
++	CK_ULONG siglen = ISC_SHA1_DIGESTLENGTH * 2;
++	isc_region_t r;
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++	isc_result_t ret = ISC_R_SUCCESS;
++
++	isc_buffer_availableregion(sig, &r);
++	if (r.length < ISC_SHA1_DIGESTLENGTH * 2 + 1)
++		return (ISC_R_NOSPACE);
++
++	PK11_RET(pkcs_C_SignFinal,
++		 (pk11_ctx->session, (CK_BYTE_PTR) r.base + 1, &siglen),
++		 DST_R_SIGNFAILURE);
++	if (siglen != ISC_SHA1_DIGESTLENGTH * 2)
++		return (DST_R_SIGNFAILURE);
++
++	*r.base = (dctx->key->key_size - 512)/64;
++	isc_buffer_add(sig, ISC_SHA1_DIGESTLENGTH * 2 + 1);
++
++    err:
++	return (ret);
++}
++
++static isc_result_t
++pkcs11dsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
++	CK_RV rv;
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++	isc_result_t ret = ISC_R_SUCCESS;
++
++	PK11_CALL(pkcs_C_VerifyFinal,
++		  (pk11_ctx->session,
++		   (CK_BYTE_PTR) sig->base + 1,
++		   (CK_ULONG) sig->length - 1),
++		  DST_R_VERIFYFAILURE);
++	return (ret);
++}
++
++static isc_boolean_t
++pkcs11dsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
++	pk11_object_t *dsa1, *dsa2;
++	CK_ATTRIBUTE *attr1, *attr2;
++
++	dsa1 = key1->keydata.pkey;
++	dsa2 = key2->keydata.pkey;
++
++	if ((dsa1 == NULL) && (dsa2 == NULL))
++		return (ISC_TRUE);
++	else if ((dsa1 == NULL) || (dsa2 == NULL))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(dsa1, CKA_PRIME);
++	attr2 = pk11_attribute_bytype(dsa2, CKA_PRIME);
++	if ((attr1 == NULL) && (attr2 == NULL))
++		return (ISC_TRUE);
++	else if ((attr1 == NULL) || (attr2 == NULL) ||
++		 (attr1->ulValueLen != attr2->ulValueLen) ||
++		 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(dsa1, CKA_SUBPRIME);
++	attr2 = pk11_attribute_bytype(dsa2, CKA_SUBPRIME);
++	if ((attr1 == NULL) && (attr2 == NULL))
++		return (ISC_TRUE);
++	else if ((attr1 == NULL) || (attr2 == NULL) ||
++		 (attr1->ulValueLen != attr2->ulValueLen) ||
++		 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(dsa1, CKA_BASE);
++	attr2 = pk11_attribute_bytype(dsa2, CKA_BASE);
++	if ((attr1 == NULL) && (attr2 == NULL))
++		return (ISC_TRUE);
++	else if ((attr1 == NULL) || (attr2 == NULL) ||
++		 (attr1->ulValueLen != attr2->ulValueLen) ||
++		 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(dsa1, CKA_VALUE);
++	attr2 = pk11_attribute_bytype(dsa2, CKA_VALUE);
++	if ((attr1 == NULL) && (attr2 == NULL))
++		return (ISC_TRUE);
++	else if ((attr1 == NULL) || (attr2 == NULL) ||
++		 (attr1->ulValueLen != attr2->ulValueLen) ||
++		 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(dsa1, CKA_VALUE2);
++	attr2 = pk11_attribute_bytype(dsa2, CKA_VALUE2);
++	if (((attr1 != NULL) || (attr2 != NULL)) &&
++	    ((attr1 == NULL) || (attr2 == NULL) ||
++	     (attr1->ulValueLen != attr2->ulValueLen) ||
++	     memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)))
++		return (ISC_FALSE);
++
++	if (!dsa1->ontoken && !dsa2->ontoken)
++		return (ISC_TRUE);
++	else if (dsa1->ontoken || dsa2->ontoken ||
++		 (dsa1->object != dsa2->object))
++		return (ISC_FALSE);
++
++	return (ISC_TRUE);
++}
++
++static isc_result_t
++pkcs11dsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_DSA_PARAMETER_GEN, NULL, 0 };
++	CK_OBJECT_HANDLE dp = CK_INVALID_HANDLE;
++	CK_OBJECT_CLASS dpClass = CKO_DOMAIN_PARAMETERS;
++	CK_KEY_TYPE  keyType = CKK_DSA;
++	CK_ULONG bits = 0;
++	CK_ATTRIBUTE dpTemplate[] =
++	{
++		{ CKA_CLASS, &dpClass, (CK_ULONG) sizeof(dpClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIME_BITS, &bits, (CK_ULONG) sizeof(bits) },
++	};
++	CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE;
++	CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY;
++	CK_ATTRIBUTE pubTemplate[] =
++	{
++		{ CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_PRIME, NULL, 0 },
++		{ CKA_SUBPRIME, NULL, 0 },
++		{ CKA_BASE, NULL, 0 }
++	};
++	CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE;
++	CK_OBJECT_HANDLE privClass = CKO_PRIVATE_KEY;
++	CK_ATTRIBUTE privTemplate[] =
++	{
++		{ CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++	};
++	CK_ATTRIBUTE *attr;
++	pk11_object_t *dsa;
++	pk11_context_t *pk11_ctx;
++	isc_result_t ret;
++	unsigned int i;
++
++	UNUSED(unused);
++	UNUSED(callback);
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		return (ISC_R_NOMEMORY);
++	ret = pk11_get_session(pk11_ctx, OP_DSA, ISC_TRUE, ISC_FALSE,
++			       ISC_FALSE, NULL, pk11_get_best_token(OP_DSA));
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	bits = key->key_size;
++	PK11_RET(pkcs_C_GenerateKey,
++		 (pk11_ctx->session, &mech, dpTemplate, (CK_ULONG) 5, &dp),
++		 DST_R_CRYPTOFAILURE);
++
++	dsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*dsa));
++	if (dsa == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(dsa, 0, sizeof(*dsa));
++	key->keydata.pkey = dsa;
++	dsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 5);
++	if (dsa->repr == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(dsa->repr, 0, sizeof(*attr) * 5);
++	dsa->attrcnt = 5;
++
++	attr = dsa->repr;
++	attr[0].type = CKA_PRIME;
++	attr[1].type = CKA_SUBPRIME;
++	attr[2].type = CKA_BASE;
++	attr[3].type = CKA_VALUE;
++	attr[4].type = CKA_VALUE2;
++
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, dp, attr, 3),
++		 DST_R_CRYPTOFAILURE);
++
++	for (i = 0; i <= 2; i++) {
++		attr[i].pValue = isc_mem_get(key->mctx, attr[i].ulValueLen);
++		if (attr[i].pValue == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++		memset(attr[i].pValue, 0, attr[i].ulValueLen);
++	}
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, dp, attr, 3),
++		 DST_R_CRYPTOFAILURE);
++	pubTemplate[5].pValue = attr[0].pValue;
++	pubTemplate[5].ulValueLen = attr[0].ulValueLen;
++	pubTemplate[6].pValue = attr[1].pValue;
++	pubTemplate[6].ulValueLen = attr[1].ulValueLen;
++	pubTemplate[7].pValue = attr[2].pValue;
++	pubTemplate[7].ulValueLen = attr[2].ulValueLen;
++
++	mech.mechanism = CKM_DSA_KEY_PAIR_GEN;
++	PK11_RET(pkcs_C_GenerateKeyPair,
++		 (pk11_ctx->session, &mech,
++		  pubTemplate, (CK_ULONG) 8,
++		  privTemplate, (CK_ULONG) 7,
++		  &pub, &priv),
++		 DST_R_CRYPTOFAILURE);
++
++	attr = dsa->repr;
++	attr += 3;
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, pub, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++	attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(attr->pValue, 0, attr->ulValueLen);
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, pub, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++
++	attr++;
++	attr->type = CKA_VALUE;
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, priv, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++	attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(attr->pValue, 0, attr->ulValueLen);
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, priv, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++	attr->type = CKA_VALUE2;
++
++	(void) pkcs_C_DestroyObject(pk11_ctx->session, priv);
++	(void) pkcs_C_DestroyObject(pk11_ctx->session, pub);
++	(void) pkcs_C_DestroyObject(pk11_ctx->session, dp);
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ISC_R_SUCCESS);
++
++    err:
++	pkcs11dsa_destroy(key);
++	if (priv != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, priv);
++	if (pub != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, pub);
++	if (dp != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, dp);
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ret);
++}
++
++static isc_boolean_t
++pkcs11dsa_isprivate(const dst_key_t *key) {
++	pk11_object_t *dsa = key->keydata.pkey;
++	CK_ATTRIBUTE *attr;
++
++	if (dsa == NULL)
++		return (ISC_FALSE);
++	attr = pk11_attribute_bytype(dsa, CKA_VALUE2);
++	return (ISC_TF((attr != NULL) || dsa->ontoken));
++}
++
++static void
++pkcs11dsa_destroy(dst_key_t *key) {
++	pk11_object_t *dsa = key->keydata.pkey;
++	CK_ATTRIBUTE *attr;
++
++	if (dsa == NULL)
++		return;
++
++	INSIST((dsa->object == CK_INVALID_HANDLE) || dsa->ontoken);
++
++	for (attr = pk11_attribute_first(dsa);
++	     attr != NULL;
++	     attr = pk11_attribute_next(dsa, attr))
++		switch (attr->type) {
++		case CKA_PRIME:
++		case CKA_SUBPRIME:
++		case CKA_BASE:
++		case CKA_VALUE:
++		case CKA_VALUE2:
++			if (attr->pValue != NULL) {
++				memset(attr->pValue, 0, attr->ulValueLen);
++				isc_mem_put(key->mctx,
++					    attr->pValue,
++					    attr->ulValueLen);
++			}
++			break;
++		}
++	if (dsa->repr != NULL) {
++		memset(dsa->repr, 0, dsa->attrcnt * sizeof(*attr));
++		isc_mem_put(key->mctx,
++			    dsa->repr,
++			    dsa->attrcnt * sizeof(*attr));
++	}
++	memset(dsa, 0, sizeof(*dsa));
++	isc_mem_put(key->mctx, dsa, sizeof(*dsa));
++	key->keydata.pkey = NULL;
++}
++
++
++static isc_result_t
++pkcs11dsa_todns(const dst_key_t *key, isc_buffer_t *data) {
++	pk11_object_t *dsa;
++	CK_ATTRIBUTE *attr;
++	isc_region_t r;
++	int dnslen;
++	unsigned int t, p_bytes;
++	CK_ATTRIBUTE *prime = NULL, *subprime = NULL;
++	CK_ATTRIBUTE *base = NULL, *pub_key = NULL;
++	CK_BYTE *cp;
++
++	REQUIRE(key->keydata.pkey != NULL);
++
++	dsa = key->keydata.pkey;
++
++	for (attr = pk11_attribute_first(dsa);
++	     attr != NULL;
++	     attr = pk11_attribute_next(dsa, attr))
++		switch (attr->type) {
++		case CKA_PRIME:
++			prime = attr;
++			break;
++		case CKA_SUBPRIME:
++			subprime = attr;
++			break;
++		case CKA_BASE:
++			base = attr;
++			break;
++		case CKA_VALUE:
++			pub_key = attr;
++			break;
++		}
++	REQUIRE((prime != NULL) && (subprime != NULL) &&
++		(base != NULL) && (pub_key != NULL));
++
++	isc_buffer_availableregion(data, &r);
++
++	t = (prime->ulValueLen - 64) / 8;
++	if (t > 8)
++		return (DST_R_INVALIDPUBLICKEY);
++	p_bytes = 64 + 8 * t;
++
++	dnslen = 1 + (key->key_size * 3)/8 + ISC_SHA1_DIGESTLENGTH;
++	if (r.length < (unsigned int) dnslen)
++		return (ISC_R_NOSPACE);
++
++	memset(r.base, 0, dnslen);
++	*r.base++ = t;
++	cp = (CK_BYTE *) subprime->pValue;
++	memcpy(r.base + ISC_SHA1_DIGESTLENGTH - subprime->ulValueLen,
++	       cp, subprime->ulValueLen);
++	r.base += ISC_SHA1_DIGESTLENGTH;
++	cp = (CK_BYTE *) prime->pValue;
++	memcpy(r.base + key->key_size/8 - prime->ulValueLen,
++	       cp, prime->ulValueLen);
++	r.base += p_bytes;
++	cp = (CK_BYTE *) base->pValue;
++	memcpy(r.base + key->key_size/8 - base->ulValueLen,
++	       cp, base->ulValueLen);
++	r.base += p_bytes;
++	cp = (CK_BYTE *) pub_key->pValue;
++	memcpy(r.base + key->key_size/8 - pub_key->ulValueLen,
++	       cp, pub_key->ulValueLen);
++	r.base += p_bytes;
++
++	isc_buffer_add(data, dnslen);
++
++	return (ISC_R_SUCCESS);
++}
++
++static isc_result_t
++pkcs11dsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
++	pk11_object_t *dsa;
++	isc_region_t r;
++	unsigned int t, p_bytes;
++	CK_BYTE *prime, *subprime, *base, *pub_key;
++	CK_ATTRIBUTE *attr;
++
++	isc_buffer_remainingregion(data, &r);
++	if (r.length == 0)
++		return (ISC_R_SUCCESS);
++
++	dsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*dsa));
++	if (dsa == NULL)
++		return (ISC_R_NOMEMORY);
++	memset(dsa, 0, sizeof(*dsa));
++
++	t = (unsigned int) *r.base++;
++	if (t > 8) {
++		memset(dsa, 0, sizeof(*dsa));
++		isc_mem_put(key->mctx, dsa, sizeof(*dsa));
++		return (DST_R_INVALIDPUBLICKEY);
++	}
++	p_bytes = 64 + 8 * t;
++
++	if (r.length < 1 + ISC_SHA1_DIGESTLENGTH + 3 * p_bytes) {
++		memset(dsa, 0, sizeof(*dsa));
++		isc_mem_put(key->mctx, dsa, sizeof(*dsa));
++		return (DST_R_INVALIDPUBLICKEY);
++	}
++
++	subprime = r.base;
++	r.base += ISC_SHA1_DIGESTLENGTH;
++
++	prime = r.base;
++	r.base += p_bytes;
++
++	base = r.base;
++	r.base += p_bytes;
++
++	pub_key = r.base;
++	r.base += p_bytes;
++
++	key->key_size = p_bytes * 8;
++
++	isc_buffer_forward(data, 1 + ISC_SHA1_DIGESTLENGTH + 3 * p_bytes);
++
++	dsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 4);
++	if (dsa->repr == NULL)
++		goto nomemory;
++	memset(dsa->repr, 0, sizeof(*attr) * 4);
++	dsa->attrcnt = 4;
++
++	attr = dsa->repr;
++	attr[0].type = CKA_PRIME;
++	attr[0].pValue = isc_mem_get(key->mctx, p_bytes);
++	if (attr[0].pValue == NULL)
++		goto nomemory;
++	memcpy(attr[0].pValue, prime, p_bytes);
++	attr[0].ulValueLen = p_bytes;
++
++	attr[1].type = CKA_SUBPRIME;
++	attr[1].pValue = isc_mem_get(key->mctx, ISC_SHA1_DIGESTLENGTH);
++	if (attr[1].pValue == NULL)
++		goto nomemory;
++	memcpy(attr[1].pValue, subprime, ISC_SHA1_DIGESTLENGTH);
++	attr[1].ulValueLen = ISC_SHA1_DIGESTLENGTH;
++
++	attr[2].type = CKA_BASE;
++	attr[2].pValue = isc_mem_get(key->mctx, p_bytes);
++	if (attr[2].pValue == NULL)
++		goto nomemory;
++	memcpy(attr[2].pValue, base, p_bytes);
++	attr[2].ulValueLen = p_bytes;
++
++	attr[3].type = CKA_VALUE;
++	attr[3].pValue = isc_mem_get(key->mctx, p_bytes);
++	if (attr[3].pValue == NULL)
++		goto nomemory;
++	memcpy(attr[3].pValue, pub_key, p_bytes);
++	attr[3].ulValueLen = p_bytes;
++
++	key->keydata.pkey = dsa;
++
++	return (ISC_R_SUCCESS);
++
++    nomemory:
++	for (attr = pk11_attribute_first(dsa);
++	     attr != NULL;
++	     attr = pk11_attribute_next(dsa, attr))
++		switch (attr->type) {
++		case CKA_PRIME:
++		case CKA_SUBPRIME:
++		case CKA_BASE:
++		case CKA_VALUE:
++			if (attr->pValue != NULL) {
++				memset(attr->pValue, 0, attr->ulValueLen);
++				isc_mem_put(key->mctx,
++					    attr->pValue,
++					    attr->ulValueLen);
++			}
++			break;
++		}
++	if (dsa->repr != NULL) {
++		memset(dsa->repr, 0, dsa->attrcnt * sizeof(*attr));
++		isc_mem_put(key->mctx,
++			    dsa->repr,
++			    dsa->attrcnt * sizeof(*attr));
++	}
++	memset(dsa, 0, sizeof(*dsa));
++	isc_mem_put(key->mctx, dsa, sizeof(*dsa));
++	return (ISC_R_NOMEMORY);
++}
++
++static isc_result_t
++pkcs11dsa_tofile(const dst_key_t *key, const char *directory) {
++	int cnt = 0;
++	pk11_object_t *dsa;
++	CK_ATTRIBUTE *attr;
++	CK_ATTRIBUTE *prime = NULL, *subprime = NULL, *base = NULL;
++	CK_ATTRIBUTE *pub_key = NULL, *priv_key = NULL;
++	dst_private_t priv;
++	unsigned char bufs[5][128];
++
++	if (key->keydata.pkey == NULL)
++		return (DST_R_NULLKEY);
++
++	if (key->external) {
++		priv.nelements = 0;
++		return (dst__privstruct_writefile(key, &priv, directory));
++	}
++
++	dsa = key->keydata.pkey;
++
++	for (attr = pk11_attribute_first(dsa);
++	     attr != NULL;
++	     attr = pk11_attribute_next(dsa, attr))
++		switch (attr->type) {
++		case CKA_PRIME:
++			prime = attr;
++			break;
++		case CKA_SUBPRIME:
++			subprime = attr;
++			break;
++		case CKA_BASE:
++			base = attr;
++			break;
++		case CKA_VALUE:
++			pub_key = attr;
++			break;
++		case CKA_VALUE2:
++			priv_key = attr;
++			break;
++		}
++	if ((prime == NULL) || (subprime == NULL) || (base == NULL) ||
++	    (pub_key == NULL) || (priv_key ==NULL))
++		return (DST_R_NULLKEY);
++
++	priv.elements[cnt].tag = TAG_DSA_PRIME;
++	priv.elements[cnt].length = (unsigned short) prime->ulValueLen;
++	memcpy(bufs[cnt], prime->pValue, prime->ulValueLen);
++	priv.elements[cnt].data = bufs[cnt];
++	cnt++;
++
++	priv.elements[cnt].tag = TAG_DSA_SUBPRIME;
++	priv.elements[cnt].length = (unsigned short) subprime->ulValueLen;
++	memcpy(bufs[cnt], subprime->pValue, subprime->ulValueLen);
++	priv.elements[cnt].data = bufs[cnt];
++	cnt++;
++
++	priv.elements[cnt].tag = TAG_DSA_BASE;
++	priv.elements[cnt].length = (unsigned short) base->ulValueLen;
++	memcpy(bufs[cnt], base->pValue, base->ulValueLen);
++	priv.elements[cnt].data = bufs[cnt];
++	cnt++;
++
++	priv.elements[cnt].tag = TAG_DSA_PRIVATE;
++	priv.elements[cnt].length = (unsigned short) priv_key->ulValueLen;
++	memcpy(bufs[cnt], priv_key->pValue, priv_key->ulValueLen);
++	priv.elements[cnt].data = bufs[cnt];
++	cnt++;
++
++	priv.elements[cnt].tag = TAG_DSA_PUBLIC;
++	priv.elements[cnt].length = (unsigned short) pub_key->ulValueLen;
++	memcpy(bufs[cnt], pub_key->pValue, pub_key->ulValueLen);
++	priv.elements[cnt].data = bufs[cnt];
++	cnt++;
++
++	priv.nelements = cnt;
++	return (dst__privstruct_writefile(key, &priv, directory));
++}
++
++static isc_result_t
++pkcs11dsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
++	dst_private_t priv;
++	isc_result_t ret;
++	int i;
++	pk11_object_t *dsa = NULL;
++	CK_ATTRIBUTE *attr;
++	isc_mem_t *mctx = key->mctx;
++
++	/* read private key file */
++	ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv);
++	if (ret != ISC_R_SUCCESS)
++		return (ret);
++
++	if (key->external) {
++		if (priv.nelements != 0)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		if (pub == NULL)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++
++		key->keydata.pkey = pub->keydata.pkey;
++		pub->keydata.pkey = NULL;
++		key->key_size = pub->key_size;
++
++		dst__privstruct_free(&priv, mctx);
++		memset(&priv, 0, sizeof(priv));
++
++		return (ISC_R_SUCCESS);
++	}
++
++	dsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*dsa));
++	if (dsa == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(dsa, 0, sizeof(*dsa));
++	key->keydata.pkey = dsa;
++
++	dsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 5);
++	if (dsa->repr == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(dsa->repr, 0, sizeof(*attr) * 5);
++	dsa->attrcnt = 5;
++	attr = dsa->repr;
++	attr[0].type = CKA_PRIME;
++	attr[1].type = CKA_SUBPRIME;
++	attr[2].type = CKA_BASE;
++	attr[3].type = CKA_VALUE;
++	attr[4].type = CKA_VALUE2;
++
++	for (i = 0; i < priv.nelements; i++) {
++		CK_BYTE *bn;
++
++		bn = isc_mem_get(key->mctx, priv.elements[i].length);
++		if (bn == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++		memcpy(bn,
++		       priv.elements[i].data,
++		       priv.elements[i].length);
++
++		switch (priv.elements[i].tag) {
++			case TAG_DSA_PRIME:
++				attr = pk11_attribute_bytype(dsa, CKA_PRIME);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++			case TAG_DSA_SUBPRIME:
++				attr = pk11_attribute_bytype(dsa,
++							     CKA_SUBPRIME);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++			case TAG_DSA_BASE:
++				attr = pk11_attribute_bytype(dsa, CKA_BASE);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++			case TAG_DSA_PRIVATE:
++				attr = pk11_attribute_bytype(dsa, CKA_VALUE2);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++			case TAG_DSA_PUBLIC:
++				attr = pk11_attribute_bytype(dsa, CKA_VALUE);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++		}
++	}
++	dst__privstruct_free(&priv, mctx);
++
++	attr = pk11_attribute_bytype(dsa, CKA_PRIME);
++	INSIST(attr != NULL);
++	key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen);
++
++	return (ISC_R_SUCCESS);
++
++ err:
++	pkcs11dsa_destroy(key);
++	dst__privstruct_free(&priv, mctx);
++	memset(&priv, 0, sizeof(priv));
++	return (ret);
++}
++
++static dst_func_t pkcs11dsa_functions = {
++	pkcs11dsa_createctx,
++	NULL, /*%< createctx2 */
++	pkcs11dsa_destroyctx,
++	pkcs11dsa_adddata,
++	pkcs11dsa_sign,
++	pkcs11dsa_verify,
++	NULL, /*%< verify2 */
++	NULL, /*%< computesecret */
++	pkcs11dsa_compare,
++	NULL, /*%< paramcompare */
++	pkcs11dsa_generate,
++	pkcs11dsa_isprivate,
++	pkcs11dsa_destroy,
++	pkcs11dsa_todns,
++	pkcs11dsa_fromdns,
++	pkcs11dsa_tofile,
++	pkcs11dsa_parse,
++	NULL, /*%< cleanup */
++	NULL, /*%< fromlabel */
++	NULL, /*%< dump */
++	NULL, /*%< restore */
++};
++
++isc_result_t
++dst__pkcs11dsa_init(dst_func_t **funcp) {
++	REQUIRE(funcp != NULL);
++	if (*funcp == NULL)
++		*funcp = &pkcs11dsa_functions;
++	return (ISC_R_SUCCESS);
++}
++
++#else /* PKCS11CRYPTO */
++
++#include <isc/util.h>
++
++EMPTY_TRANSLATION_UNIT
++
++#endif /* PKCS11CRYPTO */
++/*! \file */
+diff --git a/lib/dns/pkcs11ecdsa_link.c b/lib/dns/pkcs11ecdsa_link.c
+new file mode 100644
+index 0000000..4f56050
+--- /dev/null
++++ b/lib/dns/pkcs11ecdsa_link.c
+@@ -0,0 +1,1189 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* $Id$ */
++
++#include <config.h>
++
++#if defined(PKCS11CRYPTO) && defined(HAVE_PKCS11_ECDSA)
++
++#include <isc/entropy.h>
++#include <isc/mem.h>
++#include <isc/sha2.h>
++#include <isc/string.h>
++#include <isc/util.h>
++
++#include <dns/keyvalues.h>
++#include <dst/result.h>
++
++#include "dst_internal.h"
++#include "dst_parse.h"
++#include "dst_pkcs11.h"
++
++#include <pk11/pk11.h>
++#include <pk11/internal.h>
++#define WANT_ECC_CURVES
++#include <pk11/constants.h>
++
++#include <pkcs11/pkcs11.h>
++
++/*
++ * FIPS 186-3 ECDSA keys:
++ *  mechanisms:
++ *    CKM_ECDSA,
++ *    CKM_EC_KEY_PAIR_GEN
++ *  domain parameters:
++ *    CKA_EC_PARAMS (choice with OID namedCurve)
++ *  public keys:
++ *    object class CKO_PUBLIC_KEY
++ *    key type CKK_EC
++ *    attribute CKA_EC_PARAMS (choice with OID namedCurve)
++ *    attribute CKA_EC_POINT (point Q)
++ *  private keys:
++ *    object class CKO_PRIVATE_KEY
++ *    key type CKK_EC
++ *    attribute CKA_EC_PARAMS (choice with OID namedCurve)
++ *    attribute CKA_VALUE (big int d)
++ *  point format: 0x04 (octet-string) <2*size+1> 0x4 (uncompressed) <x> <y>
++ */
++
++#define TAG_OCTECT_STRING	0x04
++#define UNCOMPRESSED		0x04
++
++#define DST_RET(a) {ret = a; goto err;}
++
++static CK_BBOOL truevalue = TRUE;
++static CK_BBOOL falsevalue = FALSE;
++
++static isc_result_t pkcs11ecdsa_todns(const dst_key_t *key,
++				      isc_buffer_t *data);
++static void pkcs11ecdsa_destroy(dst_key_t *key);
++static isc_result_t pkcs11ecdsa_fetch(dst_key_t *key, const char *engine,
++				      const char *label, dst_key_t *pub);
++
++static isc_result_t
++pkcs11ecdsa_createctx(dst_key_t *key, dst_context_t *dctx) {
++	CK_RV rv;
++	CK_MECHANISM mech = {0, NULL, 0 };
++	CK_SLOT_ID slotid;
++	pk11_context_t *pk11_ctx;
++	pk11_object_t *ec = key->keydata.pkey;
++	isc_result_t ret;
++
++	UNUSED(key);
++	REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
++		dctx->key->key_alg == DST_ALG_ECDSA384);
++
++	if (dctx->key->key_alg == DST_ALG_ECDSA256)
++		mech.mechanism = CKM_SHA256;
++	else
++		mech.mechanism = CKM_SHA384;
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		return (ISC_R_NOMEMORY);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	if (ec->ontoken && (dctx->use == DO_SIGN))
++		slotid = ec->slot;
++	else
++		slotid = pk11_get_best_token(OP_EC);
++	ret = pk11_get_session(pk11_ctx, OP_EC, ISC_TRUE, ISC_FALSE, ISC_FALSE,
++			       NULL, slotid);
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	PK11_RET(pkcs_C_DigestInit, (pk11_ctx->session, &mech), ISC_R_FAILURE);
++	dctx->ctxdata.pk11_ctx = pk11_ctx;
++	return (ISC_R_SUCCESS);
++
++ err:
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ret);
++}
++
++static void
++pkcs11ecdsa_destroyctx(dst_context_t *dctx) {
++	CK_BYTE garbage[ISC_SHA384_DIGESTLENGTH];
++	CK_ULONG len = ISC_SHA384_DIGESTLENGTH;
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++
++	REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
++		dctx->key->key_alg == DST_ALG_ECDSA384);
++
++	if (pk11_ctx != NULL) {
++		(void) pkcs_C_DigestFinal(pk11_ctx->session, garbage, &len);
++		memset(garbage, 0, sizeof(garbage));
++		pk11_return_session(pk11_ctx);
++		memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++		isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
++		dctx->ctxdata.pk11_ctx = NULL;
++	}
++}
++
++static isc_result_t
++pkcs11ecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
++	CK_RV rv;
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++	isc_result_t ret = ISC_R_SUCCESS;
++
++	REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
++		dctx->key->key_alg == DST_ALG_ECDSA384);
++
++	PK11_CALL(pkcs_C_DigestUpdate,
++		  (pk11_ctx->session,
++		   (CK_BYTE_PTR) data->base,
++		   (CK_ULONG) data->length),
++		  ISC_R_FAILURE);
++
++	return (ret);
++}
++
++static isc_result_t
++pkcs11ecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_ECDSA, NULL, 0 };
++	CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
++	CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
++	CK_KEY_TYPE keyType = CKK_EC;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_EC_PARAMS, NULL, 0 },
++		{ CKA_VALUE, NULL, 0 }
++	};
++	CK_ATTRIBUTE *attr;
++	CK_BYTE digest[ISC_SHA384_DIGESTLENGTH];
++	CK_ULONG dgstlen;
++	CK_ULONG siglen;
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++	dst_key_t *key = dctx->key;
++	pk11_object_t *ec = key->keydata.pkey;
++	isc_region_t r;
++	isc_result_t ret = ISC_R_SUCCESS;
++	unsigned int i;
++
++	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
++		key->key_alg == DST_ALG_ECDSA384);
++	REQUIRE(ec != NULL);
++
++	if (key->key_alg == DST_ALG_ECDSA256) {
++		dgstlen = ISC_SHA256_DIGESTLENGTH;
++		siglen = DNS_SIG_ECDSA256SIZE;
++	} else {
++		siglen = DNS_SIG_ECDSA384SIZE;
++		dgstlen = ISC_SHA384_DIGESTLENGTH;
++	}
++
++	PK11_RET(pkcs_C_DigestFinal,
++		 (pk11_ctx->session, digest, &dgstlen),
++		 ISC_R_FAILURE);
++
++	isc_buffer_availableregion(sig, &r);
++	if (r.length < siglen)
++		DST_RET(ISC_R_NOSPACE);
++
++	if (ec->ontoken && (ec->object != CK_INVALID_HANDLE)) {
++		pk11_ctx->ontoken = ec->ontoken;
++		pk11_ctx->object = ec->object;
++		goto token_key;
++	}
++
++	for (attr = pk11_attribute_first(ec);
++	     attr != NULL;
++	     attr = pk11_attribute_next(ec, attr))
++		switch (attr->type) {
++		case CKA_EC_PARAMS:
++			INSIST(keyTemplate[5].type == attr->type);
++			keyTemplate[5].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[5].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[5].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[5].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_VALUE:
++			INSIST(keyTemplate[6].type == attr->type);
++			keyTemplate[6].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[6].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[6].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[6].ulValueLen = attr->ulValueLen;
++			break;
++		}
++	pk11_ctx->object = CK_INVALID_HANDLE;
++	pk11_ctx->ontoken = ISC_FALSE;
++	PK11_RET(pkcs_C_CreateObject,
++		 (pk11_ctx->session,
++		  keyTemplate, (CK_ULONG) 7,
++		  &hKey),
++		 ISC_R_FAILURE);
++
++ token_key:
++
++	PK11_RET(pkcs_C_SignInit,
++		 (pk11_ctx->session, &mech,
++		  pk11_ctx->ontoken ? pk11_ctx->object : hKey),
++		 ISC_R_FAILURE);
++
++	PK11_RET(pkcs_C_Sign,
++		 (pk11_ctx->session,
++		  digest, dgstlen,
++		  (CK_BYTE_PTR) r.base, &siglen),
++		 DST_R_SIGNFAILURE);
++
++	isc_buffer_add(sig, (unsigned int) siglen);
++
++ err:
++
++	if (hKey != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, hKey);
++	for (i = 5; i <= 6; i++)
++		if (keyTemplate[i].pValue != NULL) {
++			memset(keyTemplate[i].pValue, 0,
++			       keyTemplate[i].ulValueLen);
++			isc_mem_put(dctx->mctx,
++				    keyTemplate[i].pValue,
++				    keyTemplate[i].ulValueLen);
++		}
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
++	dctx->ctxdata.pk11_ctx = NULL;
++
++	return (ret);
++}
++
++static isc_result_t
++pkcs11ecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_ECDSA, NULL, 0 };
++	CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
++	CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
++	CK_KEY_TYPE keyType = CKK_EC;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_EC_PARAMS, NULL, 0 },
++		{ CKA_EC_POINT, NULL, 0 }
++	};
++	CK_ATTRIBUTE *attr;
++	CK_BYTE digest[ISC_SHA384_DIGESTLENGTH];
++	CK_ULONG dgstlen;
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++	dst_key_t *key = dctx->key;
++	pk11_object_t *ec = key->keydata.pkey;
++	isc_result_t ret = ISC_R_SUCCESS;
++	unsigned int i;
++
++	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
++		key->key_alg == DST_ALG_ECDSA384);
++	REQUIRE(ec != NULL);
++
++	if (key->key_alg == DST_ALG_ECDSA256)
++		dgstlen = ISC_SHA256_DIGESTLENGTH;
++	else
++		dgstlen = ISC_SHA384_DIGESTLENGTH;
++
++	PK11_RET(pkcs_C_DigestFinal,
++		 (pk11_ctx->session, digest, &dgstlen),
++		 ISC_R_FAILURE);
++
++	for (attr = pk11_attribute_first(ec);
++	     attr != NULL;
++	     attr = pk11_attribute_next(ec, attr))
++		switch (attr->type) {
++		case CKA_EC_PARAMS:
++			INSIST(keyTemplate[5].type == attr->type);
++			keyTemplate[5].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[5].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[5].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[5].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_EC_POINT:
++			INSIST(keyTemplate[6].type == attr->type);
++			keyTemplate[6].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[6].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[6].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[6].ulValueLen = attr->ulValueLen;
++			break;
++		}
++	pk11_ctx->object = CK_INVALID_HANDLE;
++	pk11_ctx->ontoken = ISC_FALSE;
++	PK11_RET(pkcs_C_CreateObject,
++		 (pk11_ctx->session,
++		  keyTemplate, (CK_ULONG) 7,
++		  &hKey),
++		 ISC_R_FAILURE);
++
++	PK11_RET(pkcs_C_VerifyInit,
++		 (pk11_ctx->session, &mech, hKey),
++		 ISC_R_FAILURE);
++
++	PK11_RET(pkcs_C_Verify,
++		 (pk11_ctx->session,
++		  digest, dgstlen,
++		  (CK_BYTE_PTR) sig->base, (CK_ULONG) sig->length),
++		 DST_R_SIGNFAILURE);
++
++ err:
++
++	if (hKey != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, hKey);
++	for (i = 5; i <= 6; i++)
++		if (keyTemplate[i].pValue != NULL) {
++			memset(keyTemplate[i].pValue, 0,
++			       keyTemplate[i].ulValueLen);
++			isc_mem_put(dctx->mctx,
++				    keyTemplate[i].pValue,
++				    keyTemplate[i].ulValueLen);
++		}
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
++	dctx->ctxdata.pk11_ctx = NULL;
++
++	return (ret);
++}
++
++static isc_boolean_t
++pkcs11ecdsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
++	pk11_object_t *ec1, *ec2;
++	CK_ATTRIBUTE *attr1, *attr2;
++
++	ec1 = key1->keydata.pkey;
++	ec2 = key2->keydata.pkey;
++
++	if ((ec1 == NULL) && (ec2 == NULL))
++		return (ISC_TRUE);
++	else if ((ec1 == NULL) || (ec2 == NULL))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(ec1, CKA_EC_PARAMS);
++	attr2 = pk11_attribute_bytype(ec2, CKA_EC_PARAMS);
++	if ((attr1 == NULL) && (attr2 == NULL))
++		return (ISC_TRUE);
++	else if ((attr1 == NULL) || (attr2 == NULL) ||
++		 (attr1->ulValueLen != attr2->ulValueLen) ||
++		 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(ec1, CKA_EC_POINT);
++	attr2 = pk11_attribute_bytype(ec2, CKA_EC_POINT);
++	if ((attr1 == NULL) && (attr2 == NULL))
++		return (ISC_TRUE);
++	else if ((attr1 == NULL) || (attr2 == NULL) ||
++		 (attr1->ulValueLen != attr2->ulValueLen) ||
++		 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(ec1, CKA_VALUE);
++	attr2 = pk11_attribute_bytype(ec2, CKA_VALUE);
++	if (((attr1 != NULL) || (attr2 != NULL)) &&
++	    ((attr1 == NULL) || (attr2 == NULL) ||
++	     (attr1->ulValueLen != attr2->ulValueLen) ||
++	     memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)))
++		return (ISC_FALSE);
++
++	if (!ec1->ontoken && !ec2->ontoken)
++		return (ISC_TRUE);
++	else if (ec1->ontoken || ec2->ontoken ||
++		 (ec1->object != ec2->object))
++		return (ISC_FALSE);
++
++	return (ISC_TRUE);
++}
++
++#define SETCURVE() \
++	if (key->key_alg == DST_ALG_ECDSA256) { \
++		attr->pValue = isc_mem_get(key->mctx, \
++					   sizeof(pk11_ecc_prime256v1)); \
++		if (attr->pValue == NULL) \
++			DST_RET(ISC_R_NOMEMORY); \
++		memcpy(attr->pValue, \
++		       pk11_ecc_prime256v1, sizeof(pk11_ecc_prime256v1)); \
++		attr->ulValueLen = sizeof(pk11_ecc_prime256v1); \
++	} else { \
++		attr->pValue = isc_mem_get(key->mctx, \
++					   sizeof(pk11_ecc_secp384r1)); \
++		if (attr->pValue == NULL) \
++			DST_RET(ISC_R_NOMEMORY); \
++		memcpy(attr->pValue, \
++		       pk11_ecc_secp384r1, sizeof(pk11_ecc_secp384r1)); \
++		attr->ulValueLen = sizeof(pk11_ecc_secp384r1); \
++	}
++
++#define FREECURVE() \
++	if (attr->pValue != NULL) { \
++		memset(attr->pValue, 0, attr->ulValueLen); \
++		isc_mem_put(key->mctx, attr->pValue, attr->ulValueLen); \
++		attr->pValue = NULL; \
++	}
++
++static isc_result_t
++pkcs11ecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_EC_KEY_PAIR_GEN, NULL, 0 };
++	CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE;
++	CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY;
++	CK_KEY_TYPE  keyType = CKK_EC;
++	CK_ATTRIBUTE pubTemplate[] =
++	{
++		{ CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_EC_PARAMS, NULL, 0 }
++	};
++	CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE;
++	CK_OBJECT_HANDLE privClass = CKO_PRIVATE_KEY;
++	CK_ATTRIBUTE privTemplate[] =
++	{
++		{ CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }
++	};
++	CK_ATTRIBUTE *attr;
++	pk11_object_t *ec;
++	pk11_context_t *pk11_ctx;
++	isc_result_t ret;
++
++	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
++		key->key_alg == DST_ALG_ECDSA384);
++	UNUSED(unused);
++	UNUSED(callback);
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		return (ISC_R_NOMEMORY);
++	ret = pk11_get_session(pk11_ctx, OP_EC, ISC_TRUE, ISC_FALSE,
++			       ISC_FALSE, NULL, pk11_get_best_token(OP_EC));
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	ec = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*ec));
++	if (ec == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(ec, 0, sizeof(*ec));
++	key->keydata.pkey = ec;
++	ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 3);
++	if (ec->repr == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(ec->repr, 0, sizeof(*attr) * 3);
++	ec->attrcnt = 3;
++
++	attr = ec->repr;
++	attr[0].type = CKA_EC_PARAMS;
++	attr[1].type = CKA_EC_POINT;
++	attr[2].type = CKA_VALUE;
++
++	attr = &pubTemplate[5];
++	SETCURVE();
++
++	PK11_RET(pkcs_C_GenerateKeyPair,
++		 (pk11_ctx->session, &mech,
++		  pubTemplate, (CK_ULONG) 6,
++		  privTemplate, (CK_ULONG) 7,
++		  &pub, &priv),
++		 DST_R_CRYPTOFAILURE);
++
++	attr = &pubTemplate[5];
++	FREECURVE();
++
++	attr = ec->repr;
++	SETCURVE();
++
++	attr++;
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, pub, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++	attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(attr->pValue, 0, attr->ulValueLen);
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, pub, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++
++	attr++;
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, priv, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++	attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(attr->pValue, 0, attr->ulValueLen);
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, priv, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++
++	(void) pkcs_C_DestroyObject(pk11_ctx->session, priv);
++	(void) pkcs_C_DestroyObject(pk11_ctx->session, pub);
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ISC_R_SUCCESS);
++
++ err:
++	pkcs11ecdsa_destroy(key);
++	if (priv != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, priv);
++	if (pub != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, pub);
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ret);
++}
++
++static isc_boolean_t
++pkcs11ecdsa_isprivate(const dst_key_t *key) {
++	pk11_object_t *ec = key->keydata.pkey;
++	CK_ATTRIBUTE *attr;
++
++	if (ec == NULL)
++		return (ISC_FALSE);
++	attr = pk11_attribute_bytype(ec, CKA_VALUE);
++	return (ISC_TF((attr != NULL) || ec->ontoken));
++}
++
++static void
++pkcs11ecdsa_destroy(dst_key_t *key) {
++	pk11_object_t *ec = key->keydata.pkey;
++	CK_ATTRIBUTE *attr;
++
++	if (ec == NULL)
++		return;
++
++	INSIST((ec->object == CK_INVALID_HANDLE) || ec->ontoken);
++
++	for (attr = pk11_attribute_first(ec);
++	     attr != NULL;
++	     attr = pk11_attribute_next(ec, attr))
++		switch (attr->type) {
++		case CKA_LABEL:
++		case CKA_ID:
++		case CKA_EC_PARAMS:
++		case CKA_EC_POINT:
++		case CKA_VALUE:
++			FREECURVE();
++			break;
++		}
++	if (ec->repr != NULL) {
++		memset(ec->repr, 0, ec->attrcnt * sizeof(*attr));
++		isc_mem_put(key->mctx,
++			    ec->repr,
++			    ec->attrcnt * sizeof(*attr));
++	}
++	memset(ec, 0, sizeof(*ec));
++	isc_mem_put(key->mctx, ec, sizeof(*ec));
++	key->keydata.pkey = NULL;
++}
++
++static isc_result_t
++pkcs11ecdsa_todns(const dst_key_t *key, isc_buffer_t *data) {
++	pk11_object_t *ec;
++	isc_region_t r;
++	unsigned int len;
++	CK_ATTRIBUTE *attr;
++
++	REQUIRE(key->keydata.pkey != NULL);
++
++	if (key->key_alg == DST_ALG_ECDSA256)
++		len = DNS_KEY_ECDSA256SIZE;
++	else
++		len = DNS_KEY_ECDSA384SIZE;
++
++	ec = key->keydata.pkey;
++	attr = pk11_attribute_bytype(ec, CKA_EC_POINT);
++	if ((attr == NULL) ||
++	    (attr->ulValueLen != len + 3) ||
++	    (((CK_BYTE_PTR) attr->pValue)[0] != TAG_OCTECT_STRING) ||
++	    (((CK_BYTE_PTR) attr->pValue)[1] != len + 1) ||
++	    (((CK_BYTE_PTR) attr->pValue)[2] != UNCOMPRESSED))
++		return (ISC_R_FAILURE);
++
++	isc_buffer_availableregion(data, &r);
++	if (r.length < len)
++		return (ISC_R_NOSPACE);
++	memcpy(r.base, (CK_BYTE_PTR) attr->pValue + 3, len);
++	isc_buffer_add(data, len);
++
++	return (ISC_R_SUCCESS);
++}
++
++static isc_result_t
++pkcs11ecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
++	pk11_object_t *ec;
++	isc_region_t r;
++	unsigned int len;
++	CK_ATTRIBUTE *attr;
++
++	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
++		key->key_alg == DST_ALG_ECDSA384);
++
++	if (key->key_alg == DST_ALG_ECDSA256)
++		len = DNS_KEY_ECDSA256SIZE;
++	else
++		len = DNS_KEY_ECDSA384SIZE;
++
++	isc_buffer_remainingregion(data, &r);
++	if (r.length == 0)
++		return (ISC_R_SUCCESS);
++	if (r.length != len)
++		return (DST_R_INVALIDPUBLICKEY);
++
++	ec = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*ec));
++	if (ec == NULL)
++		return (ISC_R_NOMEMORY);
++	memset(ec, 0, sizeof(*ec));
++	ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2);
++	if (ec->repr == NULL)
++		goto nomemory;
++	ec->attrcnt = 2;
++
++	attr = ec->repr;
++	attr->type = CKA_EC_PARAMS;
++	if (key->key_alg == DST_ALG_ECDSA256) {
++		attr->pValue =
++			isc_mem_get(key->mctx, sizeof(pk11_ecc_prime256v1));
++		if (attr->pValue == NULL)
++			goto nomemory;
++		memcpy(attr->pValue,
++		       pk11_ecc_prime256v1, sizeof(pk11_ecc_prime256v1));
++		attr->ulValueLen = sizeof(pk11_ecc_prime256v1);
++	} else {
++		attr->pValue =
++			isc_mem_get(key->mctx, sizeof(pk11_ecc_secp384r1));
++		if (attr->pValue == NULL)
++			goto nomemory;
++		memcpy(attr->pValue,
++		       pk11_ecc_secp384r1, sizeof(pk11_ecc_secp384r1));
++		attr->ulValueLen = sizeof(pk11_ecc_secp384r1);
++	}
++
++	attr++;
++	attr->type = CKA_EC_POINT;
++	attr->pValue = isc_mem_get(key->mctx, len + 3);
++	if (attr->pValue == NULL)
++		goto nomemory;
++	((CK_BYTE_PTR) attr->pValue)[0] = TAG_OCTECT_STRING;
++	((CK_BYTE_PTR) attr->pValue)[1] = len + 1;
++	((CK_BYTE_PTR) attr->pValue)[2] = UNCOMPRESSED;
++	memcpy((CK_BYTE_PTR) attr->pValue + 3, r.base, len);
++	attr->ulValueLen = len + 3;
++
++	isc_buffer_forward(data, len);
++	key->keydata.pkey = ec;
++	return (ISC_R_SUCCESS);
++
++ nomemory:
++	for (attr = pk11_attribute_first(ec);
++	     attr != NULL;
++	     attr = pk11_attribute_next(ec, attr))
++		switch (attr->type) {
++		case CKA_EC_PARAMS:
++		case CKA_EC_POINT:
++			FREECURVE();
++			break;
++		}
++	if (ec->repr != NULL) {
++		memset(ec->repr, 0, ec->attrcnt * sizeof(*attr));
++		isc_mem_put(key->mctx,
++			    ec->repr,
++			    ec->attrcnt * sizeof(*attr));
++	}
++	memset(ec, 0, sizeof(*ec));
++	isc_mem_put(key->mctx, ec, sizeof(*ec));
++	return (ISC_R_NOMEMORY);
++}
++
++static isc_result_t
++pkcs11ecdsa_tofile(const dst_key_t *key, const char *directory) {
++	isc_result_t ret;
++	pk11_object_t *ec;
++	dst_private_t priv;
++	unsigned char *buf = NULL;
++	unsigned int i = 0;
++	CK_ATTRIBUTE *attr;
++
++	if (key->keydata.pkey == NULL)
++		return (DST_R_NULLKEY);
++
++	if (key->external) {
++		priv.nelements = 0;
++		return (dst__privstruct_writefile(key, &priv, directory));
++	}
++
++	ec = key->keydata.pkey;
++	attr = pk11_attribute_bytype(ec, CKA_VALUE);
++	if (attr != NULL) {
++		buf = isc_mem_get(key->mctx, attr->ulValueLen);
++		if (buf == NULL)
++			return (ISC_R_NOMEMORY);
++		priv.elements[i].tag = TAG_ECDSA_PRIVATEKEY;
++		priv.elements[i].length = (unsigned short) attr->ulValueLen;
++		memcpy(buf, attr->pValue, attr->ulValueLen);
++		priv.elements[i].data = buf;
++		i++;
++	}
++
++	if (key->engine != NULL) {
++		priv.elements[i].tag = TAG_ECDSA_ENGINE;
++		priv.elements[i].length = strlen(key->engine) + 1;
++		priv.elements[i].data = (unsigned char *)key->engine;
++		i++;
++	}
++
++	if (key->label != NULL) {
++		priv.elements[i].tag = TAG_ECDSA_LABEL;
++		priv.elements[i].length = strlen(key->label) + 1;
++		priv.elements[i].data = (unsigned char *)key->label;
++		i++;
++	}
++
++	priv.nelements = i;
++	ret = dst__privstruct_writefile(key, &priv, directory);
++
++	if (buf != NULL) {
++		memset(buf, 0, attr->ulValueLen);
++		isc_mem_put(key->mctx, buf, attr->ulValueLen);
++	}
++	return (ret);
++}
++
++static isc_result_t
++pkcs11ecdsa_fetch(dst_key_t *key, const char *engine, const char *label,
++		  dst_key_t *pub)
++{
++	CK_RV rv;
++	CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
++	CK_KEY_TYPE keyType = CKK_EC;
++	CK_ATTRIBUTE searchTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_LABEL, NULL, 0 }
++	};
++	CK_ULONG cnt;
++	CK_ATTRIBUTE *attr;
++	CK_ATTRIBUTE *pubattr;
++	pk11_object_t *ec;
++	pk11_object_t *pubec;
++	pk11_context_t *pk11_ctx = NULL;
++	isc_result_t ret;
++
++	if (label == NULL)
++		return (DST_R_NOENGINE);
++
++	ec = key->keydata.pkey;
++	pubec = pub->keydata.pkey;
++
++	ec->object = CK_INVALID_HANDLE;
++	ec->ontoken = ISC_TRUE;
++	ec->reqlogon = ISC_TRUE;
++	ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2);
++	if (ec->repr == NULL)
++		return (ISC_R_NOMEMORY);
++	memset(ec->repr, 0, sizeof(*attr) * 2);
++	ec->attrcnt = 2;
++	attr = ec->repr;
++
++	attr->type = CKA_EC_PARAMS;
++	pubattr = pk11_attribute_bytype(pubec, CKA_EC_PARAMS);
++	attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memcpy(attr->pValue, pubattr->pValue, pubattr->ulValueLen);
++	attr->ulValueLen = pubattr->ulValueLen;
++	attr++;
++
++	attr->type = CKA_EC_POINT;
++	pubattr = pk11_attribute_bytype(pubec, CKA_EC_POINT);
++	attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memcpy(attr->pValue, pubattr->pValue, pubattr->ulValueLen);
++	attr->ulValueLen = pubattr->ulValueLen;
++
++	ret = pk11_parse_uri(ec, label, key->mctx, OP_EC);
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	ret = pk11_get_session(pk11_ctx, OP_EC, ISC_TRUE, ISC_FALSE,
++			       ec->reqlogon, NULL, ec->slot);
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	attr = pk11_attribute_bytype(ec, CKA_LABEL);
++	if (attr == NULL) {
++		attr = pk11_attribute_bytype(ec, CKA_ID);
++		INSIST(attr != NULL);
++		searchTemplate[3].type = CKA_ID;
++	}
++	searchTemplate[3].pValue = attr->pValue;
++	searchTemplate[3].ulValueLen = attr->ulValueLen;
++
++	PK11_RET(pkcs_C_FindObjectsInit,
++		 (pk11_ctx->session, searchTemplate, (CK_ULONG) 4),
++		 DST_R_CRYPTOFAILURE);
++	PK11_RET(pkcs_C_FindObjects,
++		 (pk11_ctx->session, &ec->object, (CK_ULONG) 1, &cnt),
++		 DST_R_CRYPTOFAILURE);
++	(void) pkcs_C_FindObjectsFinal(pk11_ctx->session);
++	if (cnt == 0)
++		DST_RET(ISC_R_NOTFOUND);
++	if (cnt > 1)
++		DST_RET(ISC_R_EXISTS);
++
++	if (engine != NULL) {
++		key->engine = isc_mem_strdup(key->mctx, engine);
++		if (key->engine == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++	}
++
++	key->label = isc_mem_strdup(key->mctx, label);
++	if (key->label == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++	return (ISC_R_SUCCESS);
++
++ err:
++	if (pk11_ctx != NULL) {
++		pk11_return_session(pk11_ctx);
++		memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++		isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++	}
++	return (ret);
++}
++
++static isc_result_t
++pkcs11ecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
++	dst_private_t priv;
++	isc_result_t ret;
++	pk11_object_t *ec = NULL;
++	CK_ATTRIBUTE *attr, *pattr;
++	isc_mem_t *mctx = key->mctx;
++	unsigned int i;
++	const char *engine = NULL, *label = NULL;
++
++	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
++		key->key_alg == DST_ALG_ECDSA384);
++
++	if ((pub == NULL) || (pub->keydata.pkey == NULL))
++		DST_RET(DST_R_INVALIDPRIVATEKEY);
++
++	/* read private key file */
++	ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv);
++	if (ret != ISC_R_SUCCESS)
++		return (ret);
++
++	if (key->external) {
++		if (priv.nelements != 0)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++
++		key->keydata.pkey = pub->keydata.pkey;
++		pub->keydata.pkey = NULL;
++		key->key_size = pub->key_size;
++
++		dst__privstruct_free(&priv, mctx);
++		memset(&priv, 0, sizeof(priv));
++
++		return (ISC_R_SUCCESS);
++	}
++
++	for (i = 0; i < priv.nelements; i++) {
++		switch (priv.elements[i].tag) {
++		case TAG_ECDSA_ENGINE:
++			engine = (char *)priv.elements[i].data;
++			break;
++		case TAG_ECDSA_LABEL:
++			label = (char *)priv.elements[i].data;
++			break;
++		default:
++			break;
++		}
++	}
++	ec = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*ec));
++	if (ec == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(ec, 0, sizeof(*ec));
++	key->keydata.pkey = ec;
++
++	/* Is this key is stored in a HSM? See if we can fetch it. */
++	if ((label != NULL) || (engine != NULL)) {
++		ret = pkcs11ecdsa_fetch(key, engine, label, pub);
++		if (ret != ISC_R_SUCCESS)
++			goto err;
++		dst__privstruct_free(&priv, mctx);
++		memset(&priv, 0, sizeof(priv));
++		return (ret);
++	}
++
++	ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 3);
++	if (ec->repr == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(ec->repr, 0, sizeof(*attr) * 3);
++	ec->attrcnt = 3;
++
++	attr = ec->repr;
++	attr->type = CKA_EC_PARAMS;
++	pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_EC_PARAMS);
++	INSIST(pattr != NULL);
++	attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memcpy(attr->pValue, pattr->pValue, pattr->ulValueLen);
++	attr->ulValueLen = pattr->ulValueLen;
++
++	attr++;
++	attr->type = CKA_EC_POINT;
++	pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_EC_POINT);
++	INSIST(pattr != NULL);
++	attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memcpy(attr->pValue, pattr->pValue, pattr->ulValueLen);
++	attr->ulValueLen = pattr->ulValueLen;
++
++	attr++;
++	attr->type = CKA_VALUE;
++	attr->pValue = isc_mem_get(key->mctx, priv.elements[0].length);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memcpy(attr->pValue, priv.elements[0].data, priv.elements[0].length);
++	attr->ulValueLen = priv.elements[0].length;
++
++	dst__privstruct_free(&priv, mctx);
++	memset(&priv, 0, sizeof(priv));
++
++	return (ISC_R_SUCCESS);
++
++ err:
++	pkcs11ecdsa_destroy(key);
++	dst__privstruct_free(&priv, mctx);
++	memset(&priv, 0, sizeof(priv));
++	return (ret);
++}
++
++static isc_result_t
++pkcs11ecdsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
++		      const char *pin)
++{
++	CK_RV rv;
++	CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
++	CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
++	CK_KEY_TYPE keyType = CKK_EC;
++	CK_ATTRIBUTE searchTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_LABEL, NULL, 0 }
++	};
++	CK_ULONG cnt;
++	CK_ATTRIBUTE *attr;
++	pk11_object_t *ec;
++	pk11_context_t *pk11_ctx = NULL;
++	isc_result_t ret;
++	unsigned int i;
++
++	UNUSED(pin);
++
++	ec = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*ec));
++	if (ec == NULL)
++		return (ISC_R_NOMEMORY);
++	memset(ec, 0, sizeof(*ec));
++	ec->object = CK_INVALID_HANDLE;
++	ec->ontoken = ISC_TRUE;
++	ec->reqlogon = ISC_TRUE;
++	key->keydata.pkey = ec;
++
++	ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2);
++	if (ec->repr == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(ec->repr, 0, sizeof(*attr) * 2);
++	ec->attrcnt = 2;
++	attr = ec->repr;
++	attr[0].type = CKA_EC_PARAMS;
++	attr[1].type = CKA_EC_POINT;
++
++	ret = pk11_parse_uri(ec, label, key->mctx, OP_EC);
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	ret = pk11_get_session(pk11_ctx, OP_EC, ISC_TRUE, ISC_FALSE,
++			       ec->reqlogon, NULL, ec->slot);
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	attr = pk11_attribute_bytype(ec, CKA_LABEL);
++	if (attr == NULL) {
++		attr = pk11_attribute_bytype(ec, CKA_ID);
++		INSIST(attr != NULL);
++		searchTemplate[3].type = CKA_ID;
++	}
++	searchTemplate[3].pValue = attr->pValue;
++	searchTemplate[3].ulValueLen = attr->ulValueLen;
++
++	PK11_RET(pkcs_C_FindObjectsInit,
++		 (pk11_ctx->session, searchTemplate, (CK_ULONG) 4),
++		 DST_R_CRYPTOFAILURE);
++	PK11_RET(pkcs_C_FindObjects,
++		 (pk11_ctx->session, &hKey, (CK_ULONG) 1, &cnt),
++		 DST_R_CRYPTOFAILURE);
++	(void) pkcs_C_FindObjectsFinal(pk11_ctx->session);
++	if (cnt == 0)
++		DST_RET(ISC_R_NOTFOUND);
++	if (cnt > 1)
++		DST_RET(ISC_R_EXISTS);
++
++	attr = ec->repr;
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, hKey, attr, 2),
++		 DST_R_CRYPTOFAILURE);
++	for (i = 0; i <= 1; i++) {
++		attr[i].pValue = isc_mem_get(key->mctx, attr[i].ulValueLen);
++		if (attr[i].pValue == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++		memset(attr[i].pValue, 0, attr[i].ulValueLen);
++	}
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, hKey, attr, 2),
++		 DST_R_CRYPTOFAILURE);
++
++	keyClass = CKO_PRIVATE_KEY;
++	PK11_RET(pkcs_C_FindObjectsInit,
++		 (pk11_ctx->session, searchTemplate, (CK_ULONG) 4),
++		 DST_R_CRYPTOFAILURE);
++	PK11_RET(pkcs_C_FindObjects,
++		 (pk11_ctx->session, &ec->object, (CK_ULONG) 1, &cnt),
++		 DST_R_CRYPTOFAILURE);
++	(void) pkcs_C_FindObjectsFinal(pk11_ctx->session);
++	if (cnt == 0)
++		DST_RET(ISC_R_NOTFOUND);
++	if (cnt > 1)
++		DST_RET(ISC_R_EXISTS);
++
++	if (engine != NULL) {
++		key->engine = isc_mem_strdup(key->mctx, engine);
++		if (key->engine == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++	}
++
++	key->label = isc_mem_strdup(key->mctx, label);
++	if (key->label == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++	return (ISC_R_SUCCESS);
++
++ err:
++	pkcs11ecdsa_destroy(key);
++	if (pk11_ctx != NULL) {
++		pk11_return_session(pk11_ctx);
++		memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++		isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++	}
++	return (ret);
++}
++
++static dst_func_t pkcs11ecdsa_functions = {
++	pkcs11ecdsa_createctx,
++	NULL, /*%< createctx2 */
++	pkcs11ecdsa_destroyctx,
++	pkcs11ecdsa_adddata,
++	pkcs11ecdsa_sign,
++	pkcs11ecdsa_verify,
++	NULL, /*%< verify2 */
++	NULL, /*%< computesecret */
++	pkcs11ecdsa_compare,
++	NULL, /*%< paramcompare */
++	pkcs11ecdsa_generate,
++	pkcs11ecdsa_isprivate,
++	pkcs11ecdsa_destroy,
++	pkcs11ecdsa_todns,
++	pkcs11ecdsa_fromdns,
++	pkcs11ecdsa_tofile,
++	pkcs11ecdsa_parse,
++	NULL, /*%< cleanup */
++	pkcs11ecdsa_fromlabel,
++	NULL, /*%< dump */
++	NULL, /*%< restore */
++};
++
++isc_result_t
++dst__pkcs11ecdsa_init(dst_func_t **funcp) {
++	REQUIRE(funcp != NULL);
++	if (*funcp == NULL)
++		*funcp = &pkcs11ecdsa_functions;
++	return (ISC_R_SUCCESS);
++}
++
++#else /* PKCS11CRYPTO && HAVE_PKCS11_ECDSA */
++
++#include <isc/util.h>
++
++EMPTY_TRANSLATION_UNIT
++
++#endif /* PKCS11CRYPTO && HAVE_PKCS11_ECDSA */
++/*! \file */
+diff --git a/lib/dns/pkcs11gost_link.c b/lib/dns/pkcs11gost_link.c
+new file mode 100644
+index 0000000..c03b285
+--- /dev/null
++++ b/lib/dns/pkcs11gost_link.c
+@@ -0,0 +1,949 @@
++/*
++ * Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* $Id$ */
++
++#include <config.h>
++
++#if defined(PKCS11CRYPTO) && defined(HAVE_PKCS11_GOST)
++
++#include <isc/entropy.h>
++#include <isc/mem.h>
++#include <isc/sha2.h>
++#include <isc/string.h>
++#include <isc/util.h>
++
++#include <dns/keyvalues.h>
++#include <dns/log.h>
++#include <dst/result.h>
++
++#include "dst_internal.h"
++#include "dst_parse.h"
++#include "dst_pkcs11.h"
++#include "dst_gost.h"
++
++#include <pk11/pk11.h>
++#include <pk11/internal.h>
++#define WANT_GOST_PARAMS
++#include <pk11/constants.h>
++
++#include <pkcs11/pkcs11.h>
++
++/*
++ * RU CryptoPro GOST keys:
++ *  mechanisms:
++ *    CKM_GOSTR3411
++ *    CKM_GOSTR3410_WITH_GOSTR3411
++ *    CKM_GOSTR3410_KEY_PAIR_GEN
++ *  domain parameters:
++ *    CKA_GOSTR3410_PARAMS (fixed BER OID 1.2.643.2.2.35.1)
++ *    CKA_GOSTR3411_PARAMS (fixed BER OID 1.2.643.2.2.30.1)
++ *    CKA_GOST28147_PARAMS (optional, don't use)
++ *  public keys:
++ *    object class CKO_PUBLIC_KEY
++ *    key type CKK_GOSTR3410
++ *    attribute CKA_VALUE (point Q)
++ *    attribute CKA_GOSTR3410_PARAMS
++ *    attribute CKA_GOSTR3411_PARAMS
++ *    attribute CKA_GOST28147_PARAMS
++ *  private keys:
++ *    object class CKO_PRIVATE_KEY
++ *    key type CKK_GOSTR3410
++ *    attribute CKA_VALUE (big int d)
++ *    attribute CKA_GOSTR3410_PARAMS
++ *    attribute CKA_GOSTR3411_PARAMS
++ *    attribute CKA_GOST28147_PARAMS
++ *  point format: <x> <y> (little endian)
++ */
++
++#define CKA_VALUE2			CKA_PRIVATE_EXPONENT
++
++#define ISC_GOST_SIGNATURELENGTH	64
++#define ISC_GOST_PUBKEYLENGTH		64
++
++/* HASH methods */
++
++isc_result_t
++isc_gost_init(isc_gost_t *ctx) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_GOSTR3411, NULL, 0 };
++	int ret = ISC_R_SUCCESS;
++
++	ret = pk11_get_session(ctx, OP_GOST, ISC_TRUE, ISC_FALSE,
++			       ISC_FALSE, NULL, 0);
++	if (ret != ISC_R_SUCCESS)
++		return (ret);
++	PK11_CALL(pkcs_C_DigestInit, (ctx->session, &mech), ISC_R_FAILURE);
++	return (ret);
++}
++
++void
++isc_gost_invalidate(isc_gost_t *ctx) {
++	CK_BYTE garbage[ISC_GOST_DIGESTLENGTH];
++	CK_ULONG len = ISC_GOST_DIGESTLENGTH;
++
++	if (ctx->handle == NULL)
++		return;
++	(void) pkcs_C_DigestFinal(ctx->session, garbage, &len);
++	memset(garbage, 0, sizeof(garbage));
++	pk11_return_session(ctx);
++}
++
++isc_result_t
++isc_gost_update(isc_gost_t *ctx, const unsigned char *buf, unsigned int len) {
++	CK_RV rv;
++	CK_BYTE_PTR pPart;
++	int ret = ISC_R_SUCCESS;
++
++	DE_CONST(buf, pPart);
++	PK11_CALL(pkcs_C_DigestUpdate,
++		  (ctx->session, pPart, (CK_ULONG) len),
++		  ISC_R_FAILURE);
++	return (ret);
++}
++
++isc_result_t
++isc_gost_final(isc_gost_t *ctx, unsigned char *digest) {
++	CK_RV rv;
++	CK_ULONG len = ISC_GOST_DIGESTLENGTH;
++	int ret = ISC_R_SUCCESS;
++
++	PK11_CALL(pkcs_C_DigestFinal,
++		  (ctx->session, (CK_BYTE_PTR) digest, &len),
++		  ISC_R_FAILURE);
++	pk11_return_session(ctx);
++	return (ret);
++}
++
++/* DST methods */
++
++static CK_BBOOL truevalue = TRUE;
++static CK_BBOOL falsevalue = FALSE;
++
++#define DST_RET(a) {ret = a; goto err;}
++
++static isc_result_t pkcs11gost_todns(const dst_key_t *key, isc_buffer_t *data);
++static void pkcs11gost_destroy(dst_key_t *key);
++
++static isc_result_t
++pkcs11gost_createctx_sign(dst_key_t *key, dst_context_t *dctx) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_GOSTR3410_WITH_GOSTR3411, NULL, 0 };
++	CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
++	CK_KEY_TYPE keyType = CKK_GOSTR3410;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_VALUE, NULL, 0 },
++		{ CKA_GOSTR3410_PARAMS, pk11_gost_a_paramset,
++		  (CK_ULONG) sizeof(pk11_gost_a_paramset) },
++		{ CKA_GOSTR3411_PARAMS, pk11_gost_paramset,
++		  (CK_ULONG) sizeof(pk11_gost_paramset) }
++	};
++	CK_ATTRIBUTE *attr;
++	pk11_object_t *gost;
++	pk11_context_t *pk11_ctx;
++	isc_result_t ret;
++	unsigned int i;
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		return (ISC_R_NOMEMORY);
++	ret = pk11_get_session(pk11_ctx, OP_GOST, ISC_TRUE, ISC_FALSE,
++			       ISC_FALSE, NULL, pk11_get_best_token(OP_GOST));
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	gost = key->keydata.pkey;
++	if (gost->ontoken && (gost->object != CK_INVALID_HANDLE)) {
++		pk11_ctx->ontoken = gost->ontoken;
++		pk11_ctx->object = gost->object;
++		goto token_key;
++	}
++
++	for (attr = pk11_attribute_first(gost);
++	     attr != NULL;
++	     attr = pk11_attribute_next(gost, attr))
++		switch (attr->type) {
++		case CKA_VALUE2:
++			INSIST(keyTemplate[6].type == CKA_VALUE);
++			keyTemplate[6].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[6].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[6].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[6].ulValueLen = attr->ulValueLen;
++			break;
++		}
++	pk11_ctx->object = CK_INVALID_HANDLE;
++	pk11_ctx->ontoken = ISC_FALSE;
++	PK11_RET(pkcs_C_CreateObject,
++		 (pk11_ctx->session,
++		  keyTemplate, (CK_ULONG) 9,
++		  &pk11_ctx->object),
++		 ISC_R_FAILURE);
++
++    token_key:
++
++	PK11_RET(pkcs_C_SignInit,
++		 (pk11_ctx->session, &mech, pk11_ctx->object),
++		 ISC_R_FAILURE);
++
++	dctx->ctxdata.pk11_ctx = pk11_ctx;
++
++	for (i = 6; i <= 6; i++)
++		if (keyTemplate[i].pValue != NULL) {
++			memset(keyTemplate[i].pValue, 0,
++			       keyTemplate[i].ulValueLen);
++			isc_mem_put(dctx->mctx,
++				    keyTemplate[i].pValue,
++				    keyTemplate[i].ulValueLen);
++		}
++
++	return (ISC_R_SUCCESS);
++
++    err:
++	if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE))
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, pk11_ctx->object);
++	for (i = 6; i <= 6; i++)
++		if (keyTemplate[i].pValue != NULL) {
++			memset(keyTemplate[i].pValue, 0,
++			       keyTemplate[i].ulValueLen);
++			isc_mem_put(dctx->mctx,
++				    keyTemplate[i].pValue,
++				    keyTemplate[i].ulValueLen);
++		}
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ret);
++}
++
++static isc_result_t
++pkcs11gost_createctx_verify(dst_key_t *key, dst_context_t *dctx) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_GOSTR3410_WITH_GOSTR3411, NULL, 0 };
++	CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
++	CK_KEY_TYPE keyType = CKK_GOSTR3410;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_VALUE, NULL, 0 },
++		{ CKA_GOSTR3410_PARAMS, pk11_gost_a_paramset,
++		  (CK_ULONG) sizeof(pk11_gost_a_paramset) },
++		{ CKA_GOSTR3411_PARAMS, pk11_gost_paramset,
++		  (CK_ULONG) sizeof(pk11_gost_paramset) }
++	};
++	CK_ATTRIBUTE *attr;
++	pk11_object_t *gost;
++	pk11_context_t *pk11_ctx;
++	isc_result_t ret;
++	unsigned int i;
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		return (ISC_R_NOMEMORY);
++	ret = pk11_get_session(pk11_ctx, OP_GOST, ISC_TRUE, ISC_FALSE,
++			       ISC_FALSE, NULL, pk11_get_best_token(OP_GOST));
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	gost = key->keydata.pkey;
++	if (gost->ontoken && (gost->object != CK_INVALID_HANDLE)) {
++		pk11_ctx->ontoken = gost->ontoken;
++		pk11_ctx->object = gost->object;
++		goto token_key;
++	}
++
++	for (attr = pk11_attribute_first(gost);
++	     attr != NULL;
++	     attr = pk11_attribute_next(gost, attr))
++		switch (attr->type) {
++		case CKA_VALUE:
++			INSIST(keyTemplate[5].type == attr->type);
++			keyTemplate[5].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[5].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[5].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[5].ulValueLen = attr->ulValueLen;
++			break;
++		}
++	pk11_ctx->object = CK_INVALID_HANDLE;
++	pk11_ctx->ontoken = ISC_FALSE;
++	PK11_RET(pkcs_C_CreateObject,
++		 (pk11_ctx->session,
++		  keyTemplate, (CK_ULONG) 8,
++		  &pk11_ctx->object),
++		 ISC_R_FAILURE);
++
++    token_key:
++
++	PK11_RET(pkcs_C_VerifyInit,
++		 (pk11_ctx->session, &mech, pk11_ctx->object),
++		 ISC_R_FAILURE);
++
++	dctx->ctxdata.pk11_ctx = pk11_ctx;
++
++	for (i = 5; i <= 5; i++)
++		if (keyTemplate[i].pValue != NULL) {
++			memset(keyTemplate[i].pValue, 0,
++			       keyTemplate[i].ulValueLen);
++			isc_mem_put(dctx->mctx,
++				    keyTemplate[i].pValue,
++				    keyTemplate[i].ulValueLen);
++		}
++
++	return (ISC_R_SUCCESS);
++
++    err:
++	if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE))
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, pk11_ctx->object);
++	for (i = 5; i <= 5; i++)
++		if (keyTemplate[i].pValue != NULL) {
++			memset(keyTemplate[i].pValue, 0,
++			       keyTemplate[i].ulValueLen);
++			isc_mem_put(dctx->mctx,
++				    keyTemplate[i].pValue,
++				    keyTemplate[i].ulValueLen);
++		}
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ret);
++}
++
++static isc_result_t
++pkcs11gost_createctx(dst_key_t *key, dst_context_t *dctx) {
++	if (dctx->use == DO_SIGN)
++		return (pkcs11gost_createctx_sign(key, dctx));
++	else
++		return (pkcs11gost_createctx_verify(key, dctx));
++}
++
++static void
++pkcs11gost_destroyctx(dst_context_t *dctx) {
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++
++	if (pk11_ctx != NULL) {
++		if (!pk11_ctx->ontoken &&
++		    (pk11_ctx->object != CK_INVALID_HANDLE))
++			(void) pkcs_C_DestroyObject(pk11_ctx->session,
++					       pk11_ctx->object);
++		pk11_return_session(pk11_ctx);
++		memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++		isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
++		dctx->ctxdata.pk11_ctx = NULL;
++	}
++}
++
++static isc_result_t
++pkcs11gost_adddata(dst_context_t *dctx, const isc_region_t *data) {
++	CK_RV rv;
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++	isc_result_t ret = ISC_R_SUCCESS;
++
++	if (dctx->use == DO_SIGN)
++		PK11_CALL(pkcs_C_SignUpdate,
++			  (pk11_ctx->session,
++			   (CK_BYTE_PTR) data->base,
++			   (CK_ULONG) data->length),
++			  ISC_R_FAILURE);
++	else
++		PK11_CALL(pkcs_C_VerifyUpdate,
++			  (pk11_ctx->session,
++			   (CK_BYTE_PTR) data->base,
++			   (CK_ULONG) data->length),
++			  ISC_R_FAILURE);
++	return (ret);
++}
++
++static isc_result_t
++pkcs11gost_sign(dst_context_t *dctx, isc_buffer_t *sig) {
++	CK_RV rv;
++	CK_ULONG siglen = ISC_GOST_SIGNATURELENGTH;
++	isc_region_t r;
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++	isc_result_t ret = ISC_R_SUCCESS;
++
++	isc_buffer_availableregion(sig, &r);
++	if (r.length < ISC_GOST_SIGNATURELENGTH)
++		return (ISC_R_NOSPACE);
++
++	PK11_RET(pkcs_C_SignFinal,
++		 (pk11_ctx->session, (CK_BYTE_PTR) r.base, &siglen),
++		 DST_R_SIGNFAILURE);
++	if (siglen != ISC_GOST_SIGNATURELENGTH)
++		return (DST_R_SIGNFAILURE);
++
++	isc_buffer_add(sig, ISC_GOST_SIGNATURELENGTH);
++
++    err:
++	return (ret);
++}
++
++static isc_result_t
++pkcs11gost_verify(dst_context_t *dctx, const isc_region_t *sig) {
++	CK_RV rv;
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++	isc_result_t ret = ISC_R_SUCCESS;
++
++	PK11_CALL(pkcs_C_VerifyFinal,
++		  (pk11_ctx->session,
++		   (CK_BYTE_PTR) sig->base,
++		   (CK_ULONG) sig->length),
++		  DST_R_VERIFYFAILURE);
++	return (ret);
++}
++
++static isc_boolean_t
++pkcs11gost_compare(const dst_key_t *key1, const dst_key_t *key2) {
++	pk11_object_t *gost1, *gost2;
++	CK_ATTRIBUTE *attr1, *attr2;
++
++	gost1 = key1->keydata.pkey;
++	gost2 = key2->keydata.pkey;
++
++	if ((gost1 == NULL) && (gost2 == NULL))
++		return (ISC_TRUE);
++	else if ((gost1 == NULL) || (gost2 == NULL))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(gost1, CKA_VALUE);
++	attr2 = pk11_attribute_bytype(gost2, CKA_VALUE);
++	if ((attr1 == NULL) && (attr2 == NULL))
++		return (ISC_TRUE);
++	else if ((attr1 == NULL) || (attr2 == NULL) ||
++		 (attr1->ulValueLen != attr2->ulValueLen) ||
++		 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(gost1, CKA_VALUE2);
++	attr2 = pk11_attribute_bytype(gost2, CKA_VALUE2);
++	if (((attr1 != NULL) || (attr2 != NULL)) &&
++	    ((attr1 == NULL) || (attr2 == NULL) ||
++	     (attr1->ulValueLen != attr2->ulValueLen) ||
++	     memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)))
++		return (ISC_FALSE);
++
++	if (!gost1->ontoken && !gost2->ontoken)
++		return (ISC_TRUE);
++	else if (gost1->ontoken || gost2->ontoken ||
++		 (gost1->object != gost2->object))
++		return (ISC_FALSE);
++
++	return (ISC_TRUE);
++}
++
++static isc_result_t
++pkcs11gost_generate(dst_key_t *key, int unused, void (*callback)(int)) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_GOSTR3410_KEY_PAIR_GEN, NULL, 0 };
++	CK_KEY_TYPE  keyType = CKK_GOSTR3410;
++	CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE;
++	CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY;
++	CK_ATTRIBUTE pubTemplate[] =
++	{
++		{ CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_GOSTR3410_PARAMS, pk11_gost_a_paramset,
++		  (CK_ULONG) sizeof(pk11_gost_a_paramset) },
++		{ CKA_GOSTR3411_PARAMS, pk11_gost_paramset,
++		  (CK_ULONG) sizeof(pk11_gost_paramset) }
++	};
++	CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE;
++	CK_OBJECT_HANDLE privClass = CKO_PRIVATE_KEY;
++	CK_ATTRIBUTE privTemplate[] =
++	{
++		{ CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++	};
++	CK_ATTRIBUTE *attr;
++	pk11_object_t *gost;
++	pk11_context_t *pk11_ctx;
++	isc_result_t ret;
++
++	UNUSED(unused);
++	UNUSED(callback);
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		return (ISC_R_NOMEMORY);
++	ret = pk11_get_session(pk11_ctx, OP_GOST, ISC_TRUE, ISC_FALSE,
++			       ISC_FALSE, NULL, pk11_get_best_token(OP_GOST));
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	PK11_RET(pkcs_C_GenerateKeyPair,
++		 (pk11_ctx->session, &mech,
++		  pubTemplate, (CK_ULONG) 7,
++		  privTemplate, (CK_ULONG) 7,
++		  &pub, &priv),
++		 DST_R_CRYPTOFAILURE);
++
++	gost = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*gost));
++	if (gost == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(gost, 0, sizeof(*gost));
++	key->keydata.pkey = gost;
++	gost->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx,
++						  sizeof(*attr) * 2);
++	if (gost->repr == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(gost->repr, 0, sizeof(*attr) * 2);
++	gost->attrcnt = 2;
++
++	attr = gost->repr;
++	attr[0].type = CKA_VALUE;
++	attr[1].type = CKA_VALUE2;
++
++	attr = gost->repr;
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, pub, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++	attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(attr->pValue, 0, attr->ulValueLen);
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, pub, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++
++	attr++;
++	attr->type = CKA_VALUE;
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, priv, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++	attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(attr->pValue, 0, attr->ulValueLen);
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, priv, attr, 1),
++		 DST_R_CRYPTOFAILURE);
++	attr->type = CKA_VALUE2;
++
++	(void) pkcs_C_DestroyObject(pk11_ctx->session, priv);
++	(void) pkcs_C_DestroyObject(pk11_ctx->session, pub);
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ISC_R_SUCCESS);
++
++    err:
++	pkcs11gost_destroy(key);
++	if (priv != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, priv);
++	if (pub != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, pub);
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ret);
++}
++
++static isc_boolean_t
++pkcs11gost_isprivate(const dst_key_t *key) {
++	pk11_object_t *gost = key->keydata.pkey;
++	CK_ATTRIBUTE *attr;
++
++	if (gost == NULL)
++		return (ISC_FALSE);
++	attr = pk11_attribute_bytype(gost, CKA_VALUE2);
++	return (ISC_TF((attr != NULL) || gost->ontoken));
++}
++
++static void
++pkcs11gost_destroy(dst_key_t *key) {
++	pk11_object_t *gost = key->keydata.pkey;
++	CK_ATTRIBUTE *attr;
++
++	if (gost == NULL)
++		return;
++
++	INSIST((gost->object == CK_INVALID_HANDLE) || gost->ontoken);
++
++	for (attr = pk11_attribute_first(gost);
++	     attr != NULL;
++	     attr = pk11_attribute_next(gost, attr))
++		switch (attr->type) {
++		case CKA_VALUE:
++		case CKA_VALUE2:
++			if (attr->pValue != NULL) {
++				memset(attr->pValue, 0, attr->ulValueLen);
++				isc_mem_put(key->mctx,
++					    attr->pValue,
++					    attr->ulValueLen);
++			}
++			break;
++		}
++	if (gost->repr != NULL) {
++		memset(gost->repr, 0, gost->attrcnt * sizeof(*attr));
++		isc_mem_put(key->mctx,
++			    gost->repr,
++			    gost->attrcnt * sizeof(*attr));
++	}
++	memset(gost, 0, sizeof(*gost));
++	isc_mem_put(key->mctx, gost, sizeof(*gost));
++	key->keydata.pkey = NULL;
++}
++
++static isc_result_t
++pkcs11gost_todns(const dst_key_t *key, isc_buffer_t *data) {
++	pk11_object_t *gost;
++	isc_region_t r;
++	CK_ATTRIBUTE *attr;
++
++	REQUIRE(key->keydata.pkey != NULL);
++
++	gost = key->keydata.pkey;
++	attr = pk11_attribute_bytype(gost, CKA_VALUE);
++	if ((attr == NULL) || (attr->ulValueLen != ISC_GOST_PUBKEYLENGTH))
++		return (ISC_R_FAILURE);
++
++	isc_buffer_availableregion(data, &r);
++	if (r.length < ISC_GOST_PUBKEYLENGTH)
++		return (ISC_R_NOSPACE);
++	memcpy(r.base, (CK_BYTE_PTR) attr->pValue, ISC_GOST_PUBKEYLENGTH);
++	isc_buffer_add(data, ISC_GOST_PUBKEYLENGTH);
++
++	return (ISC_R_SUCCESS);
++}
++
++static isc_result_t
++pkcs11gost_fromdns(dst_key_t *key, isc_buffer_t *data) {
++	pk11_object_t *gost;
++	isc_region_t r;
++	CK_ATTRIBUTE *attr;
++
++	isc_buffer_remainingregion(data, &r);
++	if (r.length == 0)
++		return (ISC_R_SUCCESS);
++	if (r.length != ISC_GOST_PUBKEYLENGTH)
++		return (DST_R_INVALIDPUBLICKEY);
++
++	gost = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*gost));
++	if (gost == NULL)
++		return (ISC_R_NOMEMORY);
++	memset(gost, 0, sizeof(*gost));
++	gost->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr));
++	if (gost->repr == NULL)
++		goto nomemory;
++	gost->attrcnt = 1;
++
++	attr = gost->repr;
++	attr->type = CKA_VALUE;
++	attr->pValue = isc_mem_get(key->mctx, ISC_GOST_PUBKEYLENGTH);
++	if (attr->pValue == NULL)
++		goto nomemory;
++	memcpy((CK_BYTE_PTR) attr->pValue, r.base, ISC_GOST_PUBKEYLENGTH);
++	attr->ulValueLen = ISC_GOST_PUBKEYLENGTH;
++
++	isc_buffer_forward(data, ISC_GOST_PUBKEYLENGTH);
++	key->keydata.pkey = gost;
++	return (ISC_R_SUCCESS);
++
++ nomemory:
++	for (attr = pk11_attribute_first(gost);
++	     attr != NULL;
++	     attr = pk11_attribute_next(gost, attr))
++		switch (attr->type) {
++		case CKA_VALUE:
++			if (attr->pValue != NULL) {
++				memset(attr->pValue, 0, attr->ulValueLen);
++				isc_mem_put(key->mctx,
++					    attr->pValue,
++					    attr->ulValueLen);
++			}
++			break;
++		}
++	if (gost->repr != NULL) {
++		memset(gost->repr, 0, gost->attrcnt * sizeof(*attr));
++		isc_mem_put(key->mctx,
++			    gost->repr,
++			    gost->attrcnt * sizeof(*attr));
++	}
++	memset(gost, 0, sizeof(*gost));
++	isc_mem_put(key->mctx, gost, sizeof(*gost));
++	return (ISC_R_NOMEMORY);
++}
++
++static unsigned char gost_private_der[39] = {
++	0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06,
++	0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30,
++	0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02,
++	0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02,
++	0x02, 0x1e, 0x01, 0x04, 0x22, 0x02, 0x20
++};
++
++#ifdef PREFER_GOSTASN1
++
++static isc_result_t
++pkcs11gost_tofile(const dst_key_t *key, const char *directory) {
++	isc_result_t ret;
++	pk11_object_t *gost;
++	dst_private_t priv;
++	unsigned char *buf = NULL;
++	unsigned int i = 0;
++	CK_ATTRIBUTE *attr;
++	int adj;
++
++	if (key->keydata.pkey == NULL)
++		return (DST_R_NULLKEY);
++
++	if (key->external) {
++		priv.nelements = 0;
++		return (dst__privstruct_writefile(key, &priv, directory));
++	}
++
++	gost = key->keydata.pkey;
++	attr = pk11_attribute_bytype(gost, CKA_VALUE2);
++	if (attr != NULL) {
++		buf = isc_mem_get(key->mctx, attr->ulValueLen + 39);
++		if (buf == NULL)
++			return (ISC_R_NOMEMORY);
++		priv.elements[i].tag = TAG_GOST_PRIVASN1;
++		priv.elements[i].length =
++			(unsigned short) attr->ulValueLen + 39;
++		memcpy(buf, gost_private_der, 39);
++		memcpy(buf +39, attr->pValue, attr->ulValueLen);
++		adj = (int) attr->ulValueLen - 32;
++		if (adj != 0) {
++			buf[1] += adj;
++			buf[36] += adj;
++			buf[38] += adj;
++		}
++		priv.elements[i].data = buf;
++		i++;
++	} else
++		return (DST_R_CRYPTOFAILURE);
++
++	priv.nelements = i;
++	ret = dst__privstruct_writefile(key, &priv, directory);
++
++	if (buf != NULL) {
++		memset(buf, 0, attr->ulValueLen);
++		isc_mem_put(key->mctx, buf, attr->ulValueLen);
++	}
++	return (ret);
++}
++
++#else
++
++static isc_result_t
++pkcs11gost_tofile(const dst_key_t *key, const char *directory) {
++	isc_result_t ret;
++	pk11_object_t *gost;
++	dst_private_t priv;
++	unsigned char *buf = NULL;
++	unsigned int i = 0;
++	CK_ATTRIBUTE *attr;
++
++	if (key->keydata.pkey == NULL)
++		return (DST_R_NULLKEY);
++
++	if (key->external) {
++		priv.nelements = 0;
++		return (dst__privstruct_writefile(key, &priv, directory));
++	}
++
++	gost = key->keydata.pkey;
++	attr = pk11_attribute_bytype(gost, CKA_VALUE2);
++	if (attr != NULL) {
++		buf = isc_mem_get(key->mctx, attr->ulValueLen);
++		if (buf == NULL)
++			return (ISC_R_NOMEMORY);
++		priv.elements[i].tag = TAG_GOST_PRIVRAW;
++		priv.elements[i].length = (unsigned short) attr->ulValueLen;
++		memcpy(buf, attr->pValue, attr->ulValueLen);
++		priv.elements[i].data = buf;
++		i++;
++	} else
++		return (DST_R_CRYPTOFAILURE);
++
++	priv.nelements = i;
++	ret = dst__privstruct_writefile(key, &priv, directory);
++
++	if (buf != NULL) {
++		memset(buf, 0, attr->ulValueLen);
++		isc_mem_put(key->mctx, buf, attr->ulValueLen);
++	}
++	return (ret);
++}
++#endif
++
++static isc_result_t
++pkcs11gost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
++	dst_private_t priv;
++	isc_result_t ret;
++	pk11_object_t *gost = NULL;
++	CK_ATTRIBUTE *attr, *pattr;
++	isc_mem_t *mctx = key->mctx;
++
++	if ((pub == NULL) || (pub->keydata.pkey == NULL))
++		DST_RET(DST_R_INVALIDPRIVATEKEY);
++
++	/* read private key file */
++	ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv);
++	if (ret != ISC_R_SUCCESS)
++		return (ret);
++
++	if (key->external) {
++		if (priv.nelements != 0)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++
++		key->keydata.pkey = pub->keydata.pkey;
++		pub->keydata.pkey = NULL;
++		key->key_size = pub->key_size;
++
++		dst__privstruct_free(&priv, mctx);
++		memset(&priv, 0, sizeof(priv));
++
++		return (ISC_R_SUCCESS);
++	}
++
++	if (priv.elements[0].tag == TAG_GOST_PRIVASN1) {
++		int adj = (int) priv.elements[0].length - (39 + 32);
++		unsigned char buf[39];
++
++		if ((adj > 0) || (adj < -31))
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		memcpy(buf, gost_private_der, 39);
++		if (adj != 0) {
++			buf[1] += adj;
++			buf[36] += adj;
++			buf[38] += adj;
++		}
++		if (memcmp(priv.elements[0].data, buf, 39) != 0)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		priv.elements[0].tag = TAG_GOST_PRIVRAW;
++		priv.elements[0].length -= 39;
++		memmove(priv.elements[0].data,
++			priv.elements[0].data + 39,
++			32 + adj);
++	}
++
++	gost = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*gost));
++	if (gost == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(gost, 0, sizeof(*gost));
++	key->keydata.pkey = gost;
++
++	gost->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx,
++						  sizeof(*attr) * 2);
++	if (gost->repr == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(gost->repr, 0, sizeof(*attr) * 2);
++	gost->attrcnt = 2;
++
++	attr = gost->repr;
++	attr->type = CKA_VALUE;
++	pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_VALUE);
++	INSIST(pattr != NULL);
++	attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memcpy(attr->pValue, pattr->pValue, pattr->ulValueLen);
++	attr->ulValueLen = pattr->ulValueLen;
++
++	attr++;
++	attr->type = CKA_VALUE2;
++	attr->pValue = isc_mem_get(key->mctx, priv.elements[0].length);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memcpy(attr->pValue, priv.elements[0].data, priv.elements[0].length);
++	attr->ulValueLen = priv.elements[0].length;
++
++	dst__privstruct_free(&priv, mctx);
++	memset(&priv, 0, sizeof(priv));
++
++	return (ISC_R_SUCCESS);
++
++ err:
++	pkcs11gost_destroy(key);
++	dst__privstruct_free(&priv, mctx);
++	memset(&priv, 0, sizeof(priv));
++	return (ret);
++}
++
++static dst_func_t pkcs11gost_functions = {
++	pkcs11gost_createctx,
++	NULL, /*%< createctx2 */
++	pkcs11gost_destroyctx,
++	pkcs11gost_adddata,
++	pkcs11gost_sign,
++	pkcs11gost_verify,
++	NULL, /*%< verify2 */
++	NULL, /*%< computesecret */
++	pkcs11gost_compare,
++	NULL, /*%< paramcompare */
++	pkcs11gost_generate,
++	pkcs11gost_isprivate,
++	pkcs11gost_destroy,
++	pkcs11gost_todns,
++	pkcs11gost_fromdns,
++	pkcs11gost_tofile,
++	pkcs11gost_parse,
++	NULL, /*%< cleanup */
++	NULL, /*%< fromlabel */
++	NULL, /*%< dump */
++	NULL, /*%< restore */
++};
++
++isc_result_t
++dst__pkcs11gost_init(dst_func_t **funcp) {
++	REQUIRE(funcp != NULL);
++	if (*funcp == NULL)
++		*funcp = &pkcs11gost_functions;
++	return (ISC_R_SUCCESS);
++}
++
++#else /* PKCS11CRYPTO && HAVE_PKCS11_GOST */
++
++#include <isc/util.h>
++
++EMPTY_TRANSLATION_UNIT
++
++#endif /* PKCS11CRYPTO && HAVE_PKCS11_GOST */
++/*! \file */
+diff --git a/lib/dns/pkcs11rsa_link.c b/lib/dns/pkcs11rsa_link.c
+new file mode 100644
+index 0000000..010d4b6
+--- /dev/null
++++ b/lib/dns/pkcs11rsa_link.c
+@@ -0,0 +1,1583 @@
++/*
++ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* $Id$ */
++
++#ifdef PKCS11CRYPTO
++
++#include <config.h>
++
++#include <isc/entropy.h>
++#include <isc/md5.h>
++#include <isc/sha1.h>
++#include <isc/sha2.h>
++#include <isc/mem.h>
++#include <isc/string.h>
++#include <isc/util.h>
++
++#include <dst/result.h>
++
++#include "dst_internal.h"
++#include "dst_parse.h"
++#include "dst_pkcs11.h"
++
++#include <pk11/internal.h>
++
++/*
++ * Limit the size of public exponents.
++ */
++#ifndef RSA_MAX_PUBEXP_BITS
++#define RSA_MAX_PUBEXP_BITS    35
++#endif
++
++#define DST_RET(a) {ret = a; goto err;}
++
++static CK_BBOOL truevalue = TRUE;
++static CK_BBOOL falsevalue = FALSE;
++
++static isc_result_t pkcs11rsa_todns(const dst_key_t *key, isc_buffer_t *data);
++static void pkcs11rsa_destroy(dst_key_t *key);
++static isc_result_t pkcs11rsa_fetch(dst_key_t *key, const char *engine,
++				    const char *label, dst_key_t *pub);
++
++static isc_result_t
++pkcs11rsa_createctx_sign(dst_key_t *key, dst_context_t *dctx) {
++	CK_RV rv;
++	CK_MECHANISM mech = { 0, NULL, 0 };
++	CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
++	CK_KEY_TYPE keyType = CKK_RSA;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_MODULUS, NULL, 0 },
++		{ CKA_PUBLIC_EXPONENT, NULL, 0 },
++		{ CKA_PRIVATE_EXPONENT, NULL, 0 },
++		{ CKA_PRIME_1, NULL, 0 },
++		{ CKA_PRIME_2, NULL, 0 },
++		{ CKA_EXPONENT_1, NULL, 0 },
++		{ CKA_EXPONENT_2, NULL, 0 },
++		{ CKA_COEFFICIENT, NULL, 0 }
++	};
++	CK_ATTRIBUTE *attr;
++	CK_SLOT_ID slotid;
++	pk11_object_t *rsa;
++	pk11_context_t *pk11_ctx;
++	isc_result_t ret;
++	unsigned int i;
++
++	REQUIRE(key->key_alg == DST_ALG_RSAMD5 ||
++		key->key_alg == DST_ALG_RSASHA1 ||
++		key->key_alg == DST_ALG_NSEC3RSASHA1 ||
++		key->key_alg == DST_ALG_RSASHA256 ||
++		key->key_alg == DST_ALG_RSASHA512);
++
++	rsa = key->keydata.pkey;
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		return (ISC_R_NOMEMORY);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	if (rsa->ontoken)
++		slotid = rsa->slot;
++	else
++		slotid = pk11_get_best_token(OP_RSA);
++	ret = pk11_get_session(pk11_ctx, OP_RSA, ISC_TRUE, ISC_FALSE,
++			       rsa->reqlogon, NULL, slotid);
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	if (rsa->ontoken && (rsa->object != CK_INVALID_HANDLE)) {
++		pk11_ctx->ontoken = rsa->ontoken;
++		pk11_ctx->object = rsa->object;
++		goto token_key;
++	}
++
++	for (attr = pk11_attribute_first(rsa);
++	     attr != NULL;
++	     attr = pk11_attribute_next(rsa, attr))
++		switch (attr->type) {
++		case CKA_MODULUS:
++			INSIST(keyTemplate[6].type == attr->type);
++			keyTemplate[6].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[6].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[6].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[6].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_PUBLIC_EXPONENT:
++			INSIST(keyTemplate[7].type == attr->type);
++			keyTemplate[7].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[7].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[7].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[7].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_PRIVATE_EXPONENT:
++			INSIST(keyTemplate[8].type == attr->type);
++			keyTemplate[8].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[8].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[8].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[8].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_PRIME_1:
++			INSIST(keyTemplate[9].type == attr->type);
++			keyTemplate[9].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[9].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[9].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[9].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_PRIME_2:
++			INSIST(keyTemplate[10].type == attr->type);
++			keyTemplate[10].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[10].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[10].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[10].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_EXPONENT_1:
++			INSIST(keyTemplate[11].type == attr->type);
++			keyTemplate[11].pValue = isc_mem_get(dctx->mctx,
++							     attr->ulValueLen);
++			if (keyTemplate[11].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[11].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[11].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_EXPONENT_2:
++			INSIST(keyTemplate[12].type == attr->type);
++			keyTemplate[12].pValue = isc_mem_get(dctx->mctx,
++							     attr->ulValueLen);
++			if (keyTemplate[12].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[12].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[12].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_COEFFICIENT:
++			INSIST(keyTemplate[13].type == attr->type);
++			keyTemplate[13].pValue = isc_mem_get(dctx->mctx,
++							     attr->ulValueLen);
++			if (keyTemplate[13].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[13].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[13].ulValueLen = attr->ulValueLen;
++			break;
++		}
++	pk11_ctx->object = CK_INVALID_HANDLE;
++	pk11_ctx->ontoken = ISC_FALSE;
++	PK11_RET(pkcs_C_CreateObject,
++		 (pk11_ctx->session,
++		  keyTemplate, (CK_ULONG) 14,
++		  &pk11_ctx->object),
++		 ISC_R_FAILURE);
++
++    token_key:
++
++	switch (dctx->key->key_alg) {
++	case DST_ALG_RSAMD5:
++		mech.mechanism = CKM_MD5_RSA_PKCS;
++		break;
++	case DST_ALG_RSASHA1:
++	case DST_ALG_NSEC3RSASHA1:
++		mech.mechanism = CKM_SHA1_RSA_PKCS;
++		break;
++	case DST_ALG_RSASHA256:
++		mech.mechanism = CKM_SHA256_RSA_PKCS;
++		break;
++	case DST_ALG_RSASHA512:
++		mech.mechanism = CKM_SHA512_RSA_PKCS;
++		break;
++	default:
++		INSIST(0);
++	}
++
++	PK11_RET(pkcs_C_SignInit,
++		 (pk11_ctx->session, &mech, pk11_ctx->object),
++		 ISC_R_FAILURE);
++
++	dctx->ctxdata.pk11_ctx = pk11_ctx;
++
++	for (i = 6; i <= 13; i++)
++		if (keyTemplate[i].pValue != NULL) {
++			memset(keyTemplate[i].pValue, 0,
++			       keyTemplate[i].ulValueLen);
++			isc_mem_put(dctx->mctx,
++				    keyTemplate[i].pValue,
++				    keyTemplate[i].ulValueLen);
++		}
++
++	return (ISC_R_SUCCESS);
++
++    err:
++	if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE))
++		(void) pkcs_C_DestroyObject(pk11_ctx->session,
++					    pk11_ctx->object);
++	for (i = 6; i <= 13; i++)
++		if (keyTemplate[i].pValue != NULL) {
++			memset(keyTemplate[i].pValue, 0,
++			       keyTemplate[i].ulValueLen);
++			isc_mem_put(dctx->mctx,
++				    keyTemplate[i].pValue,
++				    keyTemplate[i].ulValueLen);
++		}
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ret);
++}
++
++static isc_result_t
++pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits,
++			   dst_context_t *dctx) {
++	CK_RV rv;
++	CK_MECHANISM mech = { 0, NULL, 0 };
++	CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
++	CK_KEY_TYPE keyType = CKK_RSA;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_MODULUS, NULL, 0 },
++		{ CKA_PUBLIC_EXPONENT, NULL, 0 },
++	};
++	CK_ATTRIBUTE *attr;
++	pk11_object_t *rsa;
++	pk11_context_t *pk11_ctx;
++	isc_result_t ret;
++	unsigned int i;
++
++	REQUIRE(key->key_alg == DST_ALG_RSAMD5 ||
++		key->key_alg == DST_ALG_RSASHA1 ||
++		key->key_alg == DST_ALG_NSEC3RSASHA1 ||
++		key->key_alg == DST_ALG_RSASHA256 ||
++		key->key_alg == DST_ALG_RSASHA512);
++
++	rsa = key->keydata.pkey;
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		return (ISC_R_NOMEMORY);
++	ret = pk11_get_session(pk11_ctx, OP_RSA, ISC_TRUE, ISC_FALSE,
++			       rsa->reqlogon, NULL,
++			       pk11_get_best_token(OP_RSA));
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	for (attr = pk11_attribute_first(rsa);
++	     attr != NULL;
++	     attr = pk11_attribute_next(rsa, attr))
++		switch (attr->type) {
++		case CKA_MODULUS:
++			INSIST(keyTemplate[5].type == attr->type);
++			keyTemplate[5].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[5].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[5].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[5].ulValueLen = attr->ulValueLen;
++			break;
++		case CKA_PUBLIC_EXPONENT:
++			INSIST(keyTemplate[6].type == attr->type);
++			keyTemplate[6].pValue = isc_mem_get(dctx->mctx,
++							    attr->ulValueLen);
++			if (keyTemplate[6].pValue == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(keyTemplate[6].pValue,
++			       attr->pValue,
++			       attr->ulValueLen);
++			keyTemplate[6].ulValueLen = attr->ulValueLen;
++			if (pk11_numbits(attr->pValue,
++					 attr->ulValueLen) > maxbits &&
++			    maxbits != 0)
++				DST_RET(DST_R_VERIFYFAILURE);
++			break;
++		}
++	pk11_ctx->object = CK_INVALID_HANDLE;
++	pk11_ctx->ontoken = ISC_FALSE;
++	PK11_RET(pkcs_C_CreateObject,
++		 (pk11_ctx->session,
++		  keyTemplate, (CK_ULONG) 7,
++		  &pk11_ctx->object),
++		 ISC_R_FAILURE);
++
++	switch (dctx->key->key_alg) {
++	case DST_ALG_RSAMD5:
++		mech.mechanism = CKM_MD5_RSA_PKCS;
++		break;
++	case DST_ALG_RSASHA1:
++	case DST_ALG_NSEC3RSASHA1:
++		mech.mechanism = CKM_SHA1_RSA_PKCS;
++		break;
++	case DST_ALG_RSASHA256:
++		mech.mechanism = CKM_SHA256_RSA_PKCS;
++		break;
++	case DST_ALG_RSASHA512:
++		mech.mechanism = CKM_SHA512_RSA_PKCS;
++		break;
++	default:
++		INSIST(0);
++	}
++
++	PK11_RET(pkcs_C_VerifyInit,
++		 (pk11_ctx->session, &mech, pk11_ctx->object),
++		 ISC_R_FAILURE);
++
++	dctx->ctxdata.pk11_ctx = pk11_ctx;
++
++	for (i = 5; i <= 6; i++)
++		if (keyTemplate[i].pValue != NULL) {
++			memset(keyTemplate[i].pValue, 0,
++			       keyTemplate[i].ulValueLen);
++			isc_mem_put(dctx->mctx,
++				    keyTemplate[i].pValue,
++				    keyTemplate[i].ulValueLen);
++		}
++
++	return (ISC_R_SUCCESS);
++
++    err:
++	if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE))
++		(void) pkcs_C_DestroyObject(pk11_ctx->session,
++					    pk11_ctx->object);
++	for (i = 5; i <= 6; i++)
++		if (keyTemplate[i].pValue != NULL) {
++			memset(keyTemplate[i].pValue, 0,
++			       keyTemplate[i].ulValueLen);
++			isc_mem_put(dctx->mctx,
++				    keyTemplate[i].pValue,
++				    keyTemplate[i].ulValueLen);
++		}
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ret);
++}
++
++static isc_result_t
++pkcs11rsa_createctx(dst_key_t *key, dst_context_t *dctx) {
++	if (dctx->use == DO_SIGN)
++		return (pkcs11rsa_createctx_sign(key, dctx));
++	else
++		return (pkcs11rsa_createctx_verify(key, 0U, dctx));
++}
++
++static isc_result_t
++pkcs11rsa_createctx2(dst_key_t *key, int maxbits, dst_context_t *dctx) {
++	if (dctx->use == DO_SIGN)
++		return (pkcs11rsa_createctx_sign(key, dctx));
++	else
++		return (pkcs11rsa_createctx_verify(key,
++						   (unsigned) maxbits, dctx));
++}
++
++static void
++pkcs11rsa_destroyctx(dst_context_t *dctx) {
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++
++	if (pk11_ctx != NULL) {
++		if (!pk11_ctx->ontoken &&
++		    (pk11_ctx->object != CK_INVALID_HANDLE))
++			(void) pkcs_C_DestroyObject(pk11_ctx->session,
++						    pk11_ctx->object);
++		pk11_return_session(pk11_ctx);
++		memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++		isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx));
++		dctx->ctxdata.pk11_ctx = NULL;
++	}
++}
++
++static isc_result_t
++pkcs11rsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
++	CK_RV rv;
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++	isc_result_t ret = ISC_R_SUCCESS;
++
++	if (dctx->use == DO_SIGN)
++		PK11_CALL(pkcs_C_SignUpdate,
++			  (pk11_ctx->session,
++			   (CK_BYTE_PTR) data->base,
++			   (CK_ULONG) data->length),
++			  ISC_R_FAILURE);
++	else
++		PK11_CALL(pkcs_C_VerifyUpdate,
++			  (pk11_ctx->session,
++			   (CK_BYTE_PTR) data->base,
++			   (CK_ULONG) data->length),
++			  ISC_R_FAILURE);
++	return (ret);
++}
++
++static isc_result_t
++pkcs11rsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
++	CK_RV rv;
++	CK_ULONG siglen = 0;
++	isc_region_t r;
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++	isc_result_t ret = ISC_R_SUCCESS;
++
++	PK11_RET(pkcs_C_SignFinal,
++		 (pk11_ctx->session, NULL, &siglen),
++		 DST_R_SIGNFAILURE);
++
++	isc_buffer_availableregion(sig, &r);
++
++	if (r.length < (unsigned int) siglen)
++		return (ISC_R_NOSPACE);
++
++	PK11_RET(pkcs_C_SignFinal,
++		 (pk11_ctx->session, (CK_BYTE_PTR) r.base, &siglen),
++		 DST_R_SIGNFAILURE);
++
++	isc_buffer_add(sig, (unsigned int) siglen);
++
++    err:
++	return (ret);
++}
++
++static isc_result_t
++pkcs11rsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
++	CK_RV rv;
++	pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx;
++	isc_result_t ret = ISC_R_SUCCESS;
++
++	PK11_CALL(pkcs_C_VerifyFinal,
++		  (pk11_ctx->session,
++		   (CK_BYTE_PTR) sig->base,
++		   (CK_ULONG) sig->length),
++		  DST_R_VERIFYFAILURE);
++	return (ret);
++}
++
++static isc_boolean_t
++pkcs11rsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
++	pk11_object_t *rsa1, *rsa2;
++	CK_ATTRIBUTE *attr1, *attr2;
++
++	rsa1 = key1->keydata.pkey;
++	rsa2 = key2->keydata.pkey;
++
++	if ((rsa1 == NULL) && (rsa2 == NULL))
++		return (ISC_TRUE);
++	else if ((rsa1 == NULL) || (rsa2 == NULL))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(rsa1, CKA_MODULUS);
++	attr2 = pk11_attribute_bytype(rsa2, CKA_MODULUS);
++	if ((attr1 == NULL) && (attr2 == NULL))
++		return (ISC_TRUE);
++	else if ((attr1 == NULL) || (attr2 == NULL) ||
++		 (attr1->ulValueLen != attr2->ulValueLen) ||
++		 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(rsa1, CKA_PUBLIC_EXPONENT);
++	attr2 = pk11_attribute_bytype(rsa2, CKA_PUBLIC_EXPONENT);
++	if ((attr1 == NULL) && (attr2 == NULL))
++		return (ISC_TRUE);
++	else if ((attr1 == NULL) || (attr2 == NULL) ||
++		 (attr1->ulValueLen != attr2->ulValueLen) ||
++		 memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))
++		return (ISC_FALSE);
++
++	attr1 = pk11_attribute_bytype(rsa1, CKA_PRIVATE_EXPONENT);
++	attr2 = pk11_attribute_bytype(rsa2, CKA_PRIVATE_EXPONENT);
++	if (((attr1 != NULL) || (attr2 != NULL)) &&
++	    ((attr1 == NULL) || (attr2 == NULL) ||
++	     (attr1->ulValueLen != attr2->ulValueLen) ||
++	     memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)))
++		return (ISC_FALSE);
++
++	if (!rsa1->ontoken && !rsa2->ontoken)
++		return (ISC_TRUE);
++	else if (rsa1->ontoken || rsa2->ontoken ||
++		 (rsa1->object != rsa2->object))
++		return (ISC_FALSE);
++
++	return (ISC_TRUE);
++}
++
++static isc_result_t
++pkcs11rsa_generate(dst_key_t *key, int exp, void (*callback)(int)) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0 };
++	CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE;
++	CK_ULONG bits = 0;
++	CK_BYTE pubexp[5];
++	CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY;
++	CK_KEY_TYPE  keyType = CKK_RSA;
++	CK_ATTRIBUTE pubTemplate[] =
++	{
++		{ CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_MODULUS_BITS, &bits, (CK_ULONG) sizeof(bits) },
++		{ CKA_PUBLIC_EXPONENT, &pubexp, (CK_ULONG) sizeof(pubexp) }
++	};
++	CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE;
++	CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY;
++	CK_ATTRIBUTE privTemplate[] =
++	{
++		{ CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++	};
++	CK_ATTRIBUTE *attr;
++	pk11_object_t *rsa;
++	pk11_context_t *pk11_ctx;
++	isc_result_t ret;
++	unsigned int i;
++
++	UNUSED(callback);
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		return (ISC_R_NOMEMORY);
++	ret = pk11_get_session(pk11_ctx, OP_RSA, ISC_TRUE, ISC_FALSE,
++			       ISC_FALSE, NULL, pk11_get_best_token(OP_RSA));
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	bits = key->key_size;
++	if (exp == 0) {
++		/* RSA_F4 0x10001 */
++		pubexp[0] = 1;
++		pubexp[1] = 0;
++		pubexp[2] = 1;
++		pubTemplate[6].ulValueLen = 3;
++	} else {
++		/* F5 0x100000001 */
++		pubexp[0] = 1;
++		pubexp[1] = 0;
++		pubexp[2] = 0;
++		pubexp[3] = 0;
++		pubexp[4] = 1;
++		pubTemplate[6].ulValueLen = 5;
++	}
++
++	PK11_RET(pkcs_C_GenerateKeyPair,
++		 (pk11_ctx->session, &mech,
++		  pubTemplate, (CK_ULONG) 7,
++		  privTemplate, (CK_ULONG) 7,
++		  &pub, &priv),
++		 DST_R_CRYPTOFAILURE);
++
++	rsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*rsa));
++	if (rsa == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(rsa, 0, sizeof(*rsa));
++	key->keydata.pkey = rsa;
++	rsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 8);
++	if (rsa->repr == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(rsa->repr, 0, sizeof(*attr) * 8);
++	rsa->attrcnt = 8;
++
++	attr = rsa->repr;
++	attr[0].type = CKA_MODULUS;
++	attr[1].type = CKA_PUBLIC_EXPONENT;
++	attr[2].type = CKA_PRIVATE_EXPONENT;
++	attr[3].type = CKA_PRIME_1;
++	attr[4].type = CKA_PRIME_2;
++	attr[5].type = CKA_EXPONENT_1;
++	attr[6].type = CKA_EXPONENT_2;
++	attr[7].type = CKA_COEFFICIENT;
++
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, pub, attr, 2),
++		 DST_R_CRYPTOFAILURE);
++	for (i = 0; i <= 1; i++) {
++		attr[i].pValue = isc_mem_get(key->mctx, attr[i].ulValueLen);
++		if (attr[i].pValue == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++		memset(attr[i].pValue, 0, attr[i].ulValueLen);
++	}
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, pub, attr, 2),
++		 DST_R_CRYPTOFAILURE);
++
++	attr += 2;
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, priv, attr, 6),
++		 DST_R_CRYPTOFAILURE);
++	for (i = 0; i <= 5; i++) {
++		attr[i].pValue = isc_mem_get(key->mctx, attr[i].ulValueLen);
++		if (attr[i].pValue == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++		memset(attr[i].pValue, 0, attr[i].ulValueLen);
++	}
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, priv, attr, 6),
++		 DST_R_CRYPTOFAILURE);
++
++	(void) pkcs_C_DestroyObject(pk11_ctx->session, priv);
++	(void) pkcs_C_DestroyObject(pk11_ctx->session, pub);
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ISC_R_SUCCESS);
++
++    err:
++	pkcs11rsa_destroy(key);
++	if (priv != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, priv);
++	if (pub != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(pk11_ctx->session, pub);
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ret);
++}
++
++static isc_boolean_t
++pkcs11rsa_isprivate(const dst_key_t *key) {
++	pk11_object_t *rsa = key->keydata.pkey;
++	CK_ATTRIBUTE *attr;
++
++	if (rsa == NULL)
++		return (ISC_FALSE);
++	attr = pk11_attribute_bytype(rsa, CKA_PRIVATE_EXPONENT);
++	return (ISC_TF((attr != NULL) || rsa->ontoken));
++}
++
++static void
++pkcs11rsa_destroy(dst_key_t *key) {
++	pk11_object_t *rsa = key->keydata.pkey;
++	CK_ATTRIBUTE *attr;
++
++	if (rsa == NULL)
++		return;
++
++	INSIST((rsa->object == CK_INVALID_HANDLE) || rsa->ontoken);
++
++	for (attr = pk11_attribute_first(rsa);
++	     attr != NULL;
++	     attr = pk11_attribute_next(rsa, attr))
++		switch (attr->type) {
++		case CKA_LABEL:
++		case CKA_ID:
++		case CKA_MODULUS:
++		case CKA_PUBLIC_EXPONENT:
++		case CKA_PRIVATE_EXPONENT:
++		case CKA_PRIME_1:
++		case CKA_PRIME_2:
++		case CKA_EXPONENT_1:
++		case CKA_EXPONENT_2:
++		case CKA_COEFFICIENT:
++			if (attr->pValue != NULL) {
++				memset(attr->pValue, 0, attr->ulValueLen);
++				isc_mem_put(key->mctx,
++					    attr->pValue,
++					    attr->ulValueLen);
++			}
++			break;
++		}
++	if (rsa->repr != NULL) {
++		memset(rsa->repr, 0, rsa->attrcnt * sizeof(*attr));
++		isc_mem_put(key->mctx,
++			    rsa->repr,
++			    rsa->attrcnt * sizeof(*attr));
++	}
++	memset(rsa, 0, sizeof(*rsa));
++	isc_mem_put(key->mctx, rsa, sizeof(*rsa));
++	key->keydata.pkey = NULL;
++}
++
++static isc_result_t
++pkcs11rsa_todns(const dst_key_t *key, isc_buffer_t *data) {
++	pk11_object_t *rsa;
++	CK_ATTRIBUTE *attr;
++	isc_region_t r;
++	unsigned int e_bytes = 0, mod_bytes = 0;
++	CK_BYTE *exponent = NULL, *modulus = NULL;
++
++	REQUIRE(key->keydata.pkey != NULL);
++
++	rsa = key->keydata.pkey;
++
++	for (attr = pk11_attribute_first(rsa);
++	     attr != NULL;
++	     attr = pk11_attribute_next(rsa, attr))
++		switch (attr->type) {
++		case CKA_PUBLIC_EXPONENT:
++			exponent = (CK_BYTE *) attr->pValue;
++			e_bytes = (unsigned int) attr->ulValueLen;
++			break;
++		case CKA_MODULUS:
++			modulus = (CK_BYTE *) attr->pValue;
++			mod_bytes = (unsigned int) attr->ulValueLen;
++			break;
++		}
++	REQUIRE((exponent != NULL) && (modulus != NULL));
++
++	isc_buffer_availableregion(data, &r);
++
++	if (e_bytes < 256) {	/*%< key exponent is <= 2040 bits */
++		if (r.length < 1)
++			return (ISC_R_NOSPACE);
++		isc_buffer_putuint8(data, (isc_uint8_t) e_bytes);
++		isc_region_consume(&r, 1);
++	} else {
++		if (r.length < 3)
++			return (ISC_R_NOSPACE);
++		isc_buffer_putuint8(data, 0);
++		isc_buffer_putuint16(data, (isc_uint16_t) e_bytes);
++		isc_region_consume(&r, 3);
++	}
++
++	if (r.length < e_bytes + mod_bytes)
++		return (ISC_R_NOSPACE);
++
++	memcpy(r.base, exponent, e_bytes);
++	isc_region_consume(&r, e_bytes);
++	memcpy(r.base, modulus, mod_bytes);
++
++	isc_buffer_add(data, e_bytes + mod_bytes);
++
++	return (ISC_R_SUCCESS);
++}
++
++static isc_result_t
++pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
++	pk11_object_t *rsa;
++	isc_region_t r;
++	unsigned int e_bytes, mod_bytes;
++	CK_BYTE *exponent = NULL, *modulus = NULL;
++	CK_ATTRIBUTE *attr;
++
++	isc_buffer_remainingregion(data, &r);
++	if (r.length == 0)
++		return (ISC_R_SUCCESS);
++
++	rsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*rsa));
++	if (rsa == NULL)
++		return (ISC_R_NOMEMORY);
++	memset(rsa, 0, sizeof(*rsa));
++
++	if (r.length < 1) {
++		memset(rsa, 0, sizeof(*rsa));
++		isc_mem_put(key->mctx, rsa, sizeof(*rsa));
++		return (DST_R_INVALIDPUBLICKEY);
++	}
++	e_bytes = *r.base++;
++	r.length--;
++
++	if (e_bytes == 0) {
++		if (r.length < 2) {
++			memset(rsa, 0, sizeof(*rsa));
++			isc_mem_put(key->mctx, rsa, sizeof(*rsa));
++			return (DST_R_INVALIDPUBLICKEY);
++		}
++		e_bytes = ((*r.base++) << 8);
++		e_bytes += *r.base++;
++		r.length -= 2;
++	}
++
++	if (r.length < e_bytes) {
++		memset(rsa, 0, sizeof(*rsa));
++		isc_mem_put(key->mctx, rsa, sizeof(*rsa));
++		return (DST_R_INVALIDPUBLICKEY);
++	}
++	exponent = r.base;
++	r.base += e_bytes;
++	r.length -= e_bytes;
++	modulus = r.base;
++	mod_bytes = r.length;
++
++	key->key_size = pk11_numbits(modulus, mod_bytes);
++
++	isc_buffer_forward(data, r.length);
++
++	rsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2);
++	if (rsa->repr == NULL)
++		goto nomemory;
++	memset(rsa->repr, 0, sizeof(*attr) * 2);
++	rsa->attrcnt = 2;
++	attr = rsa->repr;
++	attr[0].type = CKA_MODULUS;
++	attr[0].pValue = isc_mem_get(key->mctx, mod_bytes);
++	if (attr[0].pValue == NULL)
++		goto nomemory;
++	memcpy(attr[0].pValue, modulus, mod_bytes);
++	attr[0].ulValueLen = (CK_ULONG) mod_bytes;
++	attr[1].type = CKA_PUBLIC_EXPONENT;
++	attr[1].pValue = isc_mem_get(key->mctx, e_bytes);
++	if (attr[1].pValue == NULL)
++		goto nomemory;
++	memcpy(attr[1].pValue, exponent, e_bytes);
++	attr[1].ulValueLen = (CK_ULONG) e_bytes;
++
++	key->keydata.pkey = rsa;
++
++	return (ISC_R_SUCCESS);
++
++    nomemory:
++	for (attr = pk11_attribute_first(rsa);
++	     attr != NULL;
++	     attr = pk11_attribute_next(rsa, attr))
++		switch (attr->type) {
++		case CKA_MODULUS:
++		case CKA_PUBLIC_EXPONENT:
++			if (attr->pValue != NULL) {
++				memset(attr->pValue, 0, attr->ulValueLen);
++				isc_mem_put(key->mctx,
++					    attr->pValue,
++					    attr->ulValueLen);
++			}
++			break;
++		}
++	if (rsa->repr != NULL) {
++		memset(rsa->repr, 0, rsa->attrcnt * sizeof(*attr));
++		isc_mem_put(key->mctx,
++			    rsa->repr,
++			    rsa->attrcnt * sizeof(*attr));
++	}
++	memset(rsa, 0, sizeof(*rsa));
++	isc_mem_put(key->mctx, rsa, sizeof(*rsa));
++	return (ISC_R_NOMEMORY);
++}
++
++static isc_result_t
++pkcs11rsa_tofile(const dst_key_t *key, const char *directory) {
++	int i;
++	pk11_object_t *rsa;
++	CK_ATTRIBUTE *attr;
++	CK_ATTRIBUTE *modulus = NULL, *exponent = NULL;
++	CK_ATTRIBUTE  *d = NULL, *p = NULL, *q = NULL;
++	CK_ATTRIBUTE *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
++	dst_private_t priv;
++	unsigned char *bufs[10];
++	isc_result_t result;
++
++	if (key->keydata.pkey == NULL)
++		return (DST_R_NULLKEY);
++
++	if (key->external) {
++		priv.nelements = 0;
++		return (dst__privstruct_writefile(key, &priv, directory));
++	}
++
++	rsa = key->keydata.pkey;
++
++	for (attr = pk11_attribute_first(rsa);
++	     attr != NULL;
++	     attr = pk11_attribute_next(rsa, attr))
++		switch (attr->type) {
++		case CKA_MODULUS:
++			modulus = attr;
++			break;
++		case CKA_PUBLIC_EXPONENT:
++			exponent = attr;
++			break;
++		case CKA_PRIVATE_EXPONENT:
++			d = attr;
++			break;
++		case CKA_PRIME_1:
++			p = attr;
++			break;
++		case CKA_PRIME_2:
++			q = attr;
++			break;
++		case CKA_EXPONENT_1:
++			dmp1 = attr;
++			break;
++		case CKA_EXPONENT_2:
++			dmq1 = attr;
++			break;
++		case CKA_COEFFICIENT:
++			iqmp = attr;
++			break;
++		}
++	if ((modulus == NULL) || (exponent == NULL))
++		return (DST_R_NULLKEY);
++
++	memset(bufs, 0, sizeof(bufs));
++
++	for (i = 0; i < 10; i++) {
++		bufs[i] = isc_mem_get(key->mctx, modulus->ulValueLen);
++		if (bufs[i] == NULL) {
++			result = ISC_R_NOMEMORY;
++			goto fail;
++		}
++		memset(bufs[i], 0, modulus->ulValueLen);
++	}
++
++	i = 0;
++
++	priv.elements[i].tag = TAG_RSA_MODULUS;
++	priv.elements[i].length = (unsigned short) modulus->ulValueLen;
++	memcpy(bufs[i], modulus->pValue, modulus->ulValueLen);
++	priv.elements[i].data = bufs[i];
++	i++;
++
++	priv.elements[i].tag = TAG_RSA_PUBLICEXPONENT;
++	priv.elements[i].length = (unsigned short) exponent->ulValueLen;
++	memcpy(bufs[i], exponent->pValue, exponent->ulValueLen);
++	priv.elements[i].data = bufs[i];
++	i++;
++
++	if (d != NULL) {
++		priv.elements[i].tag = TAG_RSA_PRIVATEEXPONENT;
++		priv.elements[i].length = (unsigned short) d->ulValueLen;
++		memcpy(bufs[i], d->pValue, d->ulValueLen);
++		priv.elements[i].data = bufs[i];
++		i++;
++	}
++
++	if (p != NULL) {
++		priv.elements[i].tag = TAG_RSA_PRIME1;
++		priv.elements[i].length = (unsigned short) p->ulValueLen;
++		memcpy(bufs[i], p->pValue, p->ulValueLen);
++		priv.elements[i].data = bufs[i];
++		i++;
++	}
++
++	if (q != NULL) {
++		priv.elements[i].tag = TAG_RSA_PRIME2;
++		priv.elements[i].length = (unsigned short) q->ulValueLen;
++		memcpy(bufs[i], q->pValue, q->ulValueLen);
++		priv.elements[i].data = bufs[i];
++		i++;
++	}
++
++	if (dmp1 != NULL) {
++		priv.elements[i].tag = TAG_RSA_EXPONENT1;
++		priv.elements[i].length = (unsigned short) dmp1->ulValueLen;
++		memcpy(bufs[i], dmp1->pValue, dmp1->ulValueLen);
++		priv.elements[i].data = bufs[i];
++		i++;
++	}
++
++	if (dmq1 != NULL) {
++		priv.elements[i].tag = TAG_RSA_EXPONENT2;
++		priv.elements[i].length = (unsigned short) dmq1->ulValueLen;
++		memcpy(bufs[i], dmq1->pValue, dmq1->ulValueLen);
++		priv.elements[i].data = bufs[i];
++		i++;
++	}
++
++	if (iqmp != NULL) {
++		priv.elements[i].tag = TAG_RSA_COEFFICIENT;
++		priv.elements[i].length = (unsigned short) iqmp->ulValueLen;
++		memcpy(bufs[i], iqmp->pValue, iqmp->ulValueLen);
++		priv.elements[i].data = bufs[i];
++		i++;
++	}
++
++	if (key->engine != NULL) {
++		priv.elements[i].tag = TAG_RSA_ENGINE;
++		priv.elements[i].length = strlen(key->engine) + 1;
++		priv.elements[i].data = (unsigned char *)key->engine;
++		i++;
++	}
++
++	if (key->label != NULL) {
++		priv.elements[i].tag = TAG_RSA_LABEL;
++		priv.elements[i].length = strlen(key->label) + 1;
++		priv.elements[i].data = (unsigned char *)key->label;
++		i++;
++	}
++
++	priv.nelements = i;
++	result = dst__privstruct_writefile(key, &priv, directory);
++ fail:
++	for (i = 0; i < 10; i++) {
++		if (bufs[i] == NULL)
++			break;
++		memset(bufs[i], 0, modulus->ulValueLen);
++		isc_mem_put(key->mctx, bufs[i], modulus->ulValueLen);
++	}
++	return (result);
++}
++
++static isc_result_t
++pkcs11rsa_fetch(dst_key_t *key, const char *engine, const char *label,
++		dst_key_t *pub)
++{
++	CK_RV rv;
++	CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
++	CK_KEY_TYPE keyType = CKK_RSA;
++	CK_ATTRIBUTE searchTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_LABEL, NULL, 0 }
++	};
++	CK_ULONG cnt;
++	CK_ATTRIBUTE *attr;
++	CK_ATTRIBUTE *pubattr;
++	pk11_object_t *rsa;
++	pk11_object_t *pubrsa;
++	pk11_context_t *pk11_ctx = NULL;
++	isc_result_t ret;
++
++	if (label == NULL)
++		return (DST_R_NOENGINE);
++
++	rsa = key->keydata.pkey;
++	pubrsa = pub->keydata.pkey;
++
++	rsa->object = CK_INVALID_HANDLE;
++	rsa->ontoken = ISC_TRUE;
++	rsa->reqlogon = ISC_TRUE;
++	rsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2);
++	if (rsa->repr == NULL)
++		return (ISC_R_NOMEMORY);
++	memset(rsa->repr, 0, sizeof(*attr) * 2);
++	rsa->attrcnt = 2;
++	attr = rsa->repr;
++
++	attr->type = CKA_MODULUS;
++	pubattr = pk11_attribute_bytype(pubrsa, CKA_MODULUS);
++	attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memcpy(attr->pValue, pubattr->pValue, pubattr->ulValueLen);
++	attr->ulValueLen = pubattr->ulValueLen;
++	attr++;
++
++	attr->type = CKA_PUBLIC_EXPONENT;
++	pubattr = pk11_attribute_bytype(pubrsa, CKA_PUBLIC_EXPONENT);
++	attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
++	if (attr->pValue == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memcpy(attr->pValue, pubattr->pValue, pubattr->ulValueLen);
++	attr->ulValueLen = pubattr->ulValueLen;
++
++	ret = pk11_parse_uri(rsa, label, key->mctx, OP_RSA);
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	ret = pk11_get_session(pk11_ctx, OP_RSA, ISC_TRUE, ISC_FALSE,
++			       rsa->reqlogon, NULL, rsa->slot);
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	attr = pk11_attribute_bytype(rsa, CKA_LABEL);
++	if (attr == NULL) {
++		attr = pk11_attribute_bytype(rsa, CKA_ID);
++		INSIST(attr != NULL);
++		searchTemplate[3].type = CKA_ID;
++	}
++	searchTemplate[3].pValue = attr->pValue;
++	searchTemplate[3].ulValueLen = attr->ulValueLen;
++
++	PK11_RET(pkcs_C_FindObjectsInit,
++		 (pk11_ctx->session, searchTemplate, (CK_ULONG) 4),
++		 DST_R_CRYPTOFAILURE);
++	PK11_RET(pkcs_C_FindObjects,
++		 (pk11_ctx->session, &rsa->object, (CK_ULONG) 1, &cnt),
++		 DST_R_CRYPTOFAILURE);
++	(void) pkcs_C_FindObjectsFinal(pk11_ctx->session);
++	if (cnt == 0)
++		DST_RET(ISC_R_NOTFOUND);
++	if (cnt > 1)
++		DST_RET(ISC_R_EXISTS);
++
++	if (engine != NULL) {
++		key->engine = isc_mem_strdup(key->mctx, engine);
++		if (key->engine == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++	}
++
++	key->label = isc_mem_strdup(key->mctx, label);
++	if (key->label == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	attr = pk11_attribute_bytype(rsa, CKA_MODULUS);
++	INSIST(attr != NULL);
++	key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen);
++
++	return (ISC_R_SUCCESS);
++
++    err:
++	if (pk11_ctx != NULL) {
++		pk11_return_session(pk11_ctx);
++		memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++		isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++	}
++
++	return (ret);
++}
++
++static isc_result_t
++rsa_check(pk11_object_t *rsa, pk11_object_t *pubrsa) {
++	CK_ATTRIBUTE *pubattr, *privattr;
++	CK_BYTE *priv_exp = NULL, *priv_mod = NULL;
++	CK_BYTE *pub_exp = NULL, *pub_mod = NULL;
++	unsigned int priv_explen = 0, priv_modlen = 0;
++	unsigned int pub_explen = 0, pub_modlen = 0;
++
++	REQUIRE(rsa != NULL && pubrsa != NULL);
++
++	privattr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT);
++	INSIST(privattr != NULL);
++	priv_exp = privattr->pValue;
++	priv_explen = privattr->ulValueLen;
++
++	pubattr = pk11_attribute_bytype(pubrsa, CKA_PUBLIC_EXPONENT);
++	INSIST(pubattr != NULL);
++	pub_exp = pubattr->pValue;
++	pub_explen = pubattr->ulValueLen;
++
++	if (priv_exp != NULL) {
++		if (priv_explen != pub_explen)
++			return (DST_R_INVALIDPRIVATEKEY);
++		if (memcmp(priv_exp, pub_exp, pub_explen) != 0)
++			return (DST_R_INVALIDPRIVATEKEY);
++	} else {
++		privattr->pValue = pub_exp;
++		privattr->ulValueLen = pub_explen;
++		pubattr->pValue = NULL;
++		pubattr->ulValueLen = 0;
++	}
++
++	if (privattr->pValue == NULL)
++		return (DST_R_INVALIDPRIVATEKEY);
++
++	privattr = pk11_attribute_bytype(rsa, CKA_MODULUS);
++	INSIST(privattr != NULL);
++	priv_mod = privattr->pValue;
++	priv_modlen = privattr->ulValueLen;
++
++	pubattr = pk11_attribute_bytype(pubrsa, CKA_MODULUS);
++	INSIST(pubattr != NULL);
++	pub_mod = pubattr->pValue;
++	pub_modlen = pubattr->ulValueLen;
++
++	if (priv_mod != NULL) {
++		if (priv_modlen != pub_modlen)
++			return (DST_R_INVALIDPRIVATEKEY);
++		if (memcmp(priv_mod, pub_mod, pub_modlen) != 0)
++			return (DST_R_INVALIDPRIVATEKEY);
++	} else {
++		privattr->pValue = pub_mod;
++		privattr->ulValueLen = pub_modlen;
++		pubattr->pValue = NULL;
++		pubattr->ulValueLen = 0;
++	}
++
++	if (privattr->pValue == NULL)
++		return (DST_R_INVALIDPRIVATEKEY);
++
++	return (ISC_R_SUCCESS);
++}
++
++static isc_result_t
++pkcs11rsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
++	dst_private_t priv;
++	isc_result_t ret;
++	int i;
++	pk11_object_t *rsa;
++	CK_ATTRIBUTE *attr;
++	isc_mem_t *mctx = key->mctx;
++	const char *engine = NULL, *label = NULL;
++
++	/* read private key file */
++	ret = dst__privstruct_parse(key, DST_ALG_RSA, lexer, mctx, &priv);
++	if (ret != ISC_R_SUCCESS)
++		return (ret);
++
++	if (key->external) {
++		if (priv.nelements != 0)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++		if (pub == NULL)
++			DST_RET(DST_R_INVALIDPRIVATEKEY);
++
++		key->keydata.pkey = pub->keydata.pkey;
++		pub->keydata.pkey = NULL;
++		key->key_size = pub->key_size;
++
++		dst__privstruct_free(&priv, mctx);
++		memset(&priv, 0, sizeof(priv));
++
++		return (ISC_R_SUCCESS);
++	}
++
++	for (i = 0; i < priv.nelements; i++) {
++		switch (priv.elements[i].tag) {
++		case TAG_RSA_ENGINE:
++			engine = (char *)priv.elements[i].data;
++			break;
++		case TAG_RSA_LABEL:
++			label = (char *)priv.elements[i].data;
++			break;
++		default:
++			break;
++		}
++	}
++	rsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*rsa));
++	if (rsa == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(rsa, 0, sizeof(*rsa));
++	key->keydata.pkey = rsa;
++
++	/* Is this key is stored in a HSM? See if we can fetch it. */
++	if ((label != NULL) || (engine != NULL)) {
++		ret = pkcs11rsa_fetch(key, engine, label, pub);
++		if (ret != ISC_R_SUCCESS)
++			goto err;
++		dst__privstruct_free(&priv, mctx);
++		memset(&priv, 0, sizeof(priv));
++		return (ret);
++	}
++
++	rsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 8);
++	if (rsa->repr == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(rsa->repr, 0, sizeof(*attr) * 8);
++	rsa->attrcnt = 8;
++	attr = rsa->repr;
++	attr[0].type = CKA_MODULUS;
++	attr[1].type = CKA_PUBLIC_EXPONENT;
++	attr[2].type = CKA_PRIVATE_EXPONENT;
++	attr[3].type = CKA_PRIME_1;
++	attr[4].type = CKA_PRIME_2;
++	attr[5].type = CKA_EXPONENT_1;
++	attr[6].type = CKA_EXPONENT_2;
++	attr[7].type = CKA_COEFFICIENT;
++
++	for (i = 0; i < priv.nelements; i++) {
++		CK_BYTE *bn;
++
++		switch (priv.elements[i].tag) {
++		case TAG_RSA_ENGINE:
++			continue;
++		case TAG_RSA_LABEL:
++			continue;
++		default:
++			bn = isc_mem_get(key->mctx, priv.elements[i].length);
++			if (bn == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			memcpy(bn,
++			       priv.elements[i].data,
++			       priv.elements[i].length);
++		}
++
++		switch (priv.elements[i].tag) {
++			case TAG_RSA_MODULUS:
++				attr = pk11_attribute_bytype(rsa, CKA_MODULUS);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++			case TAG_RSA_PUBLICEXPONENT:
++				attr = pk11_attribute_bytype(rsa,
++						CKA_PUBLIC_EXPONENT);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++			case TAG_RSA_PRIVATEEXPONENT:
++				attr = pk11_attribute_bytype(rsa,
++						CKA_PRIVATE_EXPONENT);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++			case TAG_RSA_PRIME1:
++				attr = pk11_attribute_bytype(rsa, CKA_PRIME_1);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++			case TAG_RSA_PRIME2:
++				attr = pk11_attribute_bytype(rsa, CKA_PRIME_2);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++			case TAG_RSA_EXPONENT1:
++				attr = pk11_attribute_bytype(rsa,
++							     CKA_EXPONENT_1);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++			case TAG_RSA_EXPONENT2:
++				attr = pk11_attribute_bytype(rsa,
++							     CKA_EXPONENT_2);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++			case TAG_RSA_COEFFICIENT:
++				attr = pk11_attribute_bytype(rsa,
++							     CKA_COEFFICIENT);
++				INSIST(attr != NULL);
++				attr->pValue = bn;
++				attr->ulValueLen = priv.elements[i].length;
++				break;
++		}
++	}
++
++	if (rsa_check(rsa, pub->keydata.pkey) != ISC_R_SUCCESS)
++		DST_RET(DST_R_INVALIDPRIVATEKEY);
++
++	attr = pk11_attribute_bytype(rsa, CKA_MODULUS);
++	INSIST(attr != NULL);
++	key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen);
++
++	attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT);
++	INSIST(attr != NULL);
++	if (pk11_numbits(attr->pValue, attr->ulValueLen) > RSA_MAX_PUBEXP_BITS)
++		DST_RET(ISC_R_RANGE);
++
++	dst__privstruct_free(&priv, mctx);
++	memset(&priv, 0, sizeof(priv));
++
++	return (ISC_R_SUCCESS);
++
++ err:
++	pkcs11rsa_destroy(key);
++	dst__privstruct_free(&priv, mctx);
++	memset(&priv, 0, sizeof(priv));
++	return (ret);
++}
++
++static isc_result_t
++pkcs11rsa_fromlabel(dst_key_t *key, const char *engine, const char *label,
++		    const char *pin)
++{
++	CK_RV rv;
++	CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE;
++	CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
++	CK_KEY_TYPE keyType = CKK_RSA;
++	CK_ATTRIBUTE searchTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_LABEL, NULL, 0 }
++	};
++	CK_ULONG cnt;
++	CK_ATTRIBUTE *attr;
++	pk11_object_t *rsa;
++	pk11_context_t *pk11_ctx = NULL;
++	isc_result_t ret;
++	unsigned int i;
++
++	UNUSED(pin);
++
++	rsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*rsa));
++	if (rsa == NULL)
++		return (ISC_R_NOMEMORY);
++	memset(rsa, 0, sizeof(*rsa));
++	rsa->object = CK_INVALID_HANDLE;
++	rsa->ontoken = ISC_TRUE;
++	rsa->reqlogon = ISC_TRUE;
++	key->keydata.pkey = rsa;
++
++	rsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2);
++	if (rsa->repr == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	memset(rsa->repr, 0, sizeof(*attr) * 2);
++	rsa->attrcnt = 2;
++	attr = rsa->repr;
++	attr[0].type = CKA_MODULUS;
++	attr[1].type = CKA_PUBLIC_EXPONENT;
++
++	ret = pk11_parse_uri(rsa, label, key->mctx, OP_RSA);
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx,
++						  sizeof(*pk11_ctx));
++	if (pk11_ctx == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++	ret = pk11_get_session(pk11_ctx, OP_RSA, ISC_TRUE, ISC_FALSE,
++			       rsa->reqlogon, NULL, rsa->slot);
++	if (ret != ISC_R_SUCCESS)
++		goto err;
++
++	attr = pk11_attribute_bytype(rsa, CKA_LABEL);
++	if (attr == NULL) {
++		attr = pk11_attribute_bytype(rsa, CKA_ID);
++		INSIST(attr != NULL);
++		searchTemplate[3].type = CKA_ID;
++	}
++	searchTemplate[3].pValue = attr->pValue;
++	searchTemplate[3].ulValueLen = attr->ulValueLen;
++
++	PK11_RET(pkcs_C_FindObjectsInit,
++		 (pk11_ctx->session, searchTemplate, (CK_ULONG) 4),
++		 DST_R_CRYPTOFAILURE);
++	PK11_RET(pkcs_C_FindObjects,
++		 (pk11_ctx->session, &hKey, (CK_ULONG) 1, &cnt),
++		 DST_R_CRYPTOFAILURE);
++	(void) pkcs_C_FindObjectsFinal(pk11_ctx->session);
++	if (cnt == 0)
++		DST_RET(ISC_R_NOTFOUND);
++	if (cnt > 1)
++		DST_RET(ISC_R_EXISTS);
++
++	attr = rsa->repr;
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, hKey, attr, 2),
++		 DST_R_CRYPTOFAILURE);
++	for (i = 0; i <= 1; i++) {
++		attr[i].pValue = isc_mem_get(key->mctx, attr[i].ulValueLen);
++		if (attr[i].pValue == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++		memset(attr[i].pValue, 0, attr[i].ulValueLen);
++	}
++	PK11_RET(pkcs_C_GetAttributeValue,
++		 (pk11_ctx->session, hKey, attr, 2),
++		 DST_R_CRYPTOFAILURE);
++
++	keyClass = CKO_PRIVATE_KEY;
++	PK11_RET(pkcs_C_FindObjectsInit,
++		 (pk11_ctx->session, searchTemplate, (CK_ULONG) 4),
++		 DST_R_CRYPTOFAILURE);
++	PK11_RET(pkcs_C_FindObjects,
++		 (pk11_ctx->session, &rsa->object, (CK_ULONG) 1, &cnt),
++		 DST_R_CRYPTOFAILURE);
++	(void) pkcs_C_FindObjectsFinal(pk11_ctx->session);
++	if (cnt == 0)
++		DST_RET(ISC_R_NOTFOUND);
++	if (cnt > 1)
++		DST_RET(ISC_R_EXISTS);
++
++	if (engine != NULL) {
++		key->engine = isc_mem_strdup(key->mctx, engine);
++		if (key->engine == NULL)
++			DST_RET(ISC_R_NOMEMORY);
++	}
++
++	key->label = isc_mem_strdup(key->mctx, label);
++	if (key->label == NULL)
++		DST_RET(ISC_R_NOMEMORY);
++
++	attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT);
++	INSIST(attr != NULL);
++	if (pk11_numbits(attr->pValue, attr->ulValueLen) > RSA_MAX_PUBEXP_BITS)
++		DST_RET(ISC_R_RANGE);
++
++	attr = pk11_attribute_bytype(rsa, CKA_MODULUS);
++	INSIST(attr != NULL);
++	key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen);
++
++	pk11_return_session(pk11_ctx);
++	memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++	isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++
++	return (ISC_R_SUCCESS);
++
++    err:
++	pkcs11rsa_destroy(key);
++	if (pk11_ctx != NULL) {
++		pk11_return_session(pk11_ctx);
++		memset(pk11_ctx, 0, sizeof(*pk11_ctx));
++		isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx));
++	}
++
++	return (ret);
++}
++
++static dst_func_t pkcs11rsa_functions = {
++	pkcs11rsa_createctx,
++	pkcs11rsa_createctx2,
++	pkcs11rsa_destroyctx,
++	pkcs11rsa_adddata,
++	pkcs11rsa_sign,
++	pkcs11rsa_verify,
++	NULL, /*%< verify2 */
++	NULL, /*%< computesecret */
++	pkcs11rsa_compare,
++	NULL, /*%< paramcompare */
++	pkcs11rsa_generate,
++	pkcs11rsa_isprivate,
++	pkcs11rsa_destroy,
++	pkcs11rsa_todns,
++	pkcs11rsa_fromdns,
++	pkcs11rsa_tofile,
++	pkcs11rsa_parse,
++	NULL, /*%< cleanup */
++	pkcs11rsa_fromlabel,
++	NULL, /*%< dump */
++	NULL, /*%< restore */
++};
++
++isc_result_t
++dst__pkcs11rsa_init(dst_func_t **funcp) {
++	REQUIRE(funcp != NULL);
++
++	if (*funcp == NULL)
++		*funcp = &pkcs11rsa_functions;
++	return (ISC_R_SUCCESS);
++}
++
++#else /* PKCS11CRYPTO */
++
++#include <isc/util.h>
++
++EMPTY_TRANSLATION_UNIT
++
++#endif /* PKCS11CRYPTO */
++/*! \file */
+diff --git a/lib/dns/rdata/generic/dlv_32769.c b/lib/dns/rdata/generic/dlv_32769.c
+index 5751ad8..732abdb 100644
+--- a/lib/dns/rdata/generic/dlv_32769.c
++++ b/lib/dns/rdata/generic/dlv_32769.c
+@@ -28,6 +28,7 @@
+ 
+ #include <dns/ds.h>
+ 
++#include "dst_gost.h"
+ 
+ static inline isc_result_t
+ fromtext_dlv(ARGS_FROMTEXT) {
+@@ -81,9 +82,11 @@ fromtext_dlv(ARGS_FROMTEXT) {
+ 	case DNS_DSDIGEST_SHA256:
+ 		length = ISC_SHA256_DIGESTLENGTH;
+ 		break;
++#ifdef ISC_GOST_DIGESTLENGTH
+ 	case DNS_DSDIGEST_GOST:
+ 		length = ISC_GOST_DIGESTLENGTH;
+ 		break;
++#endif
+ 	case DNS_DSDIGEST_SHA384:
+ 		length = ISC_SHA384_DIGESTLENGTH;
+ 		break;
+@@ -168,8 +171,10 @@ fromwire_dlv(ARGS_FROMWIRE) {
+ 	     sr.length < 4 + ISC_SHA1_DIGESTLENGTH) ||
+ 	    (sr.base[3] == DNS_DSDIGEST_SHA256 &&
+ 	     sr.length < 4 + ISC_SHA256_DIGESTLENGTH) ||
++#ifdef ISC_GOST_DIGESTLENGTH
+ 	    (sr.base[3] == DNS_DSDIGEST_GOST &&
+ 	     sr.length < 4 + ISC_GOST_DIGESTLENGTH) ||
++#endif
+ 	    (sr.base[3] == DNS_DSDIGEST_SHA384 &&
+ 	     sr.length < 4 + ISC_SHA384_DIGESTLENGTH))
+ 		return (ISC_R_UNEXPECTEDEND);
+@@ -183,8 +188,10 @@ fromwire_dlv(ARGS_FROMWIRE) {
+ 		sr.length = 4 + ISC_SHA1_DIGESTLENGTH;
+ 	else if (sr.base[3] == DNS_DSDIGEST_SHA256)
+ 		sr.length = 4 + ISC_SHA256_DIGESTLENGTH;
++#ifdef ISC_GOST_DIGESTLENGTH
+ 	else if (sr.base[3] == DNS_DSDIGEST_GOST)
+ 		sr.length = 4 + ISC_GOST_DIGESTLENGTH;
++#endif
+ 	else if (sr.base[3] == DNS_DSDIGEST_SHA384)
+ 		sr.length = 4 + ISC_SHA384_DIGESTLENGTH;
+ 
+@@ -236,9 +243,11 @@ fromstruct_dlv(ARGS_FROMSTRUCT) {
+ 	case DNS_DSDIGEST_SHA256:
+ 		REQUIRE(dlv->length == ISC_SHA256_DIGESTLENGTH);
+ 		break;
++#ifdef ISC_GOST_DIGESTLENGTH
+ 	case DNS_DSDIGEST_GOST:
+ 		REQUIRE(dlv->length == ISC_GOST_DIGESTLENGTH);
+ 		break;
++#endif
+ 	case DNS_DSDIGEST_SHA384:
+ 		REQUIRE(dlv->length == ISC_SHA384_DIGESTLENGTH);
+ 		break;
+diff --git a/lib/dns/rdata/generic/ds_43.c b/lib/dns/rdata/generic/ds_43.c
+index dd47c8d..fc7f126 100644
+--- a/lib/dns/rdata/generic/ds_43.c
++++ b/lib/dns/rdata/generic/ds_43.c
+@@ -30,6 +30,8 @@
+ 
+ #include <dns/ds.h>
+ 
++#include "dst_gost.h"
++
+ static inline isc_result_t
+ fromtext_ds(ARGS_FROMTEXT) {
+ 	isc_token_t token;
+@@ -81,9 +83,11 @@ fromtext_ds(ARGS_FROMTEXT) {
+ 	case DNS_DSDIGEST_SHA256:
+ 		length = ISC_SHA256_DIGESTLENGTH;
+ 		break;
++#ifdef ISC_GOST_DIGESTLENGTH
+ 	case DNS_DSDIGEST_GOST:
+ 		length = ISC_GOST_DIGESTLENGTH;
+ 		break;
++#endif
+ 	case DNS_DSDIGEST_SHA384:
+ 		length = ISC_SHA384_DIGESTLENGTH;
+ 		break;
+@@ -168,8 +172,10 @@ fromwire_ds(ARGS_FROMWIRE) {
+ 	     sr.length < 4 + ISC_SHA1_DIGESTLENGTH) ||
+ 	    (sr.base[3] == DNS_DSDIGEST_SHA256 &&
+ 	     sr.length < 4 + ISC_SHA256_DIGESTLENGTH) ||
++#ifdef ISC_GOST_DIGESTLENGTH
+ 	    (sr.base[3] == DNS_DSDIGEST_GOST &&
+ 	     sr.length < 4 + ISC_GOST_DIGESTLENGTH) ||
++#endif
+ 	    (sr.base[3] == DNS_DSDIGEST_SHA384 &&
+ 	     sr.length < 4 + ISC_SHA384_DIGESTLENGTH))
+ 		return (ISC_R_UNEXPECTEDEND);
+@@ -183,8 +189,10 @@ fromwire_ds(ARGS_FROMWIRE) {
+ 		sr.length = 4 + ISC_SHA1_DIGESTLENGTH;
+ 	else if (sr.base[3] == DNS_DSDIGEST_SHA256)
+ 		sr.length = 4 + ISC_SHA256_DIGESTLENGTH;
++#ifdef ISC_GOST_DIGESTLENGTH
+ 	else if (sr.base[3] == DNS_DSDIGEST_GOST)
+ 		sr.length = 4 + ISC_GOST_DIGESTLENGTH;
++#endif
+ 	else if (sr.base[3] == DNS_DSDIGEST_SHA384)
+ 		sr.length = 4 + ISC_SHA384_DIGESTLENGTH;
+ 
+@@ -236,9 +244,11 @@ fromstruct_ds(ARGS_FROMSTRUCT) {
+ 	case DNS_DSDIGEST_SHA256:
+ 		REQUIRE(ds->length == ISC_SHA256_DIGESTLENGTH);
+ 		break;
++#ifdef ISC_GOST_DIGESTLENGTH
+ 	case DNS_DSDIGEST_GOST:
+ 		REQUIRE(ds->length == ISC_GOST_DIGESTLENGTH);
+ 		break;
++#endif
+ 	case DNS_DSDIGEST_SHA384:
+ 		REQUIRE(ds->length == ISC_SHA384_DIGESTLENGTH);
+ 		break;
+diff --git a/lib/dns/tests/Makefile.in b/lib/dns/tests/Makefile.in
+index db47476..3b19784 100644
+--- a/lib/dns/tests/Makefile.in
++++ b/lib/dns/tests/Makefile.in
+@@ -26,8 +26,9 @@ top_srcdir =	@top_srcdir@
+ 
+ @BIND9_MAKE_INCLUDES@
+ 
+-CINCLUDES =	-I. -Iinclude ${DNS_INCLUDES} ${ISC_INCLUDES} @DST_OPENSSL_INC@
+-CDEFINES =	@USE_OPENSSL@ -DTESTS="\"${top_builddir}/lib/dns/tests/\""
++CINCLUDES =	-I. -Iinclude ${DNS_INCLUDES} ${ISC_INCLUDES} \
++		@DST_OPENSSL_INC@
++CDEFINES =	@CRYPTO@ -DTESTS="\"${top_builddir}/lib/dns/tests/\""
+ 
+ ISCLIBS =	../../isc/libisc.@A@
+ ISCDEPLIBS =	../../isc/libisc.@A@
+@@ -37,13 +38,13 @@ DNSDEPLIBS =	../libdns.@A@
+ LIBS =		@LIBS@ @ATFLIBS@
+ 
+ OBJS =		dnstest.@O@
+-SRCS =		dnstest.c master_test.c dbiterator_test.c time_test.c \
++SRCS =		dnstest.c gost_test.c master_test.c dbiterator_test.c time_test.c \
+ 		private_test.c update_test.c zonemgr_test.c zt_test.c \
+ 		dbdiff_test.c dispatch_test.c nsec3_test.c \
+ 		rdataset_test.c rdata_test.c
+ 
+ SUBDIRS =
+-TARGETS =	master_test@EXEEXT@ dbiterator_test@EXEEXT@ time_test@EXEEXT@ \
++TARGETS =	gost_test@EXEEXT@ master_test@EXEEXT@ dbiterator_test@EXEEXT@ time_test@EXEEXT@ \
+ 		private_test@EXEEXT@ update_test@EXEEXT@ zonemgr_test@EXEEXT@ \
+ 		zt_test@EXEEXT@ dbversion_test@EXEEXT@ dbdiff_test@EXEEXT@ \
+ 		dispatch_test@EXEEXT@ nsec3_test@EXEEXT@ \
+@@ -123,6 +124,11 @@ dispatch_test@EXEEXT@: dispatch_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ 			dispatch_test.@O@ dnstest.@O@ ${DNSLIBS} \
+ 				${ISCLIBS} ${LIBS}
+ 
++gost_test@EXEEXT@: gost_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
++	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
++			gost_test.@O@ dnstest.@O@ ${DNSLIBS} \
++			${ISCLIBS} ${LIBS}
++
+ unit::
+ 	sh ${top_srcdir}/unit/unittest.sh
+ 
+diff --git a/lib/dns/tests/gost_test.c b/lib/dns/tests/gost_test.c
+new file mode 100644
+index 0000000..0dd9e55
+--- /dev/null
++++ b/lib/dns/tests/gost_test.c
+@@ -0,0 +1,232 @@
++/*
++ * Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* $Id$ */
++
++/* ! \file */
++
++#include <config.h>
++
++#include <atf-c.h>
++
++#include <stdio.h>
++#include <string.h>
++
++#include <isc/util.h>
++#include <isc/string.h>
++
++#include "dnstest.h"
++
++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
++
++#include "../dst_gost.h"
++
++/*
++ * Test data from Wikipedia GOST (hash function)
++ */
++
++unsigned char digest[ISC_GOST_DIGESTLENGTH];
++unsigned char buffer[1024];
++const char *s;
++char str[ISC_GOST_DIGESTLENGTH];
++int i = 0;
++
++isc_result_t
++tohexstr(unsigned char *d, unsigned int len, char *out);
++/*
++ * Precondition: a hexadecimal number in *d, the length of that number in len,
++ *   and a pointer to a character array to put the output (*out).
++ * Postcondition: A String representation of the given hexadecimal number is
++ *   placed into the array *out
++ *
++ * 'out' MUST point to an array of at least len / 2 + 1
++ *
++ * Return values: ISC_R_SUCCESS if the operation is sucessful
++ */
++
++isc_result_t
++tohexstr(unsigned char *d, unsigned int len, char *out) {
++
++	out[0]='\0';
++	char c_ret[] = "AA";
++	unsigned int i;
++	strcat(out, "0x");
++	for (i = 0; i < len; i++) {
++		sprintf(c_ret, "%02X", d[i]);
++		strcat(out, c_ret);
++	}
++	strcat(out, "\0");
++	return (ISC_R_SUCCESS);
++}
++
++
++#define TEST_INPUT(x) (x), sizeof(x)-1
++
++typedef struct hash_testcase {
++	const char *input;
++	size_t input_len;
++	const char *result;
++	int repeats;
++} hash_testcase_t;
++
++ATF_TC(isc_gost);
++ATF_TC_HEAD(isc_gost, tc) {
++	atf_tc_set_md_var(tc, "descr",
++			  "GOST R 34.11-94 examples from Wikipedia");
++}
++ATF_TC_BODY(isc_gost, tc) {
++	isc_gost_t gost;
++	isc_result_t result;
++
++	UNUSED(tc);
++
++	/*
++	 * These are the various test vectors.  All of these are passed
++	 * through the hash function and the results are compared to the
++	 * result specified here.
++	 */
++	hash_testcase_t testcases[] = {
++		/* Test 1 */
++		{
++			TEST_INPUT(""),
++			"0x981E5F3CA30C841487830F84FB433E1"
++			"3AC1101569B9C13584AC483234CD656C0",
++			1
++		},
++		/* Test 2 */
++		{
++			TEST_INPUT("a"),
++			"0xE74C52DD282183BF37AF0079C9F7805"
++			"5715A103F17E3133CEFF1AACF2F403011",
++			1
++		},
++		/* Test 3 */
++		{
++			TEST_INPUT("abc"),
++			"0xB285056DBF18D7392D7677369524DD1"
++			"4747459ED8143997E163B2986F92FD42C",
++			1
++		},
++		/* Test 4 */
++		{
++			TEST_INPUT("message digest"),
++			"0xBC6041DD2AA401EBFA6E9886734174F"
++			"EBDB4729AA972D60F549AC39B29721BA0",
++			1
++		},
++		/* Test 5 */
++		{
++			TEST_INPUT("The quick brown fox jumps "
++				   "over the lazy dog"),
++			"0x9004294A361A508C586FE53D1F1B027"
++			"46765E71B765472786E4770D565830A76",
++			1
++		},
++		/* Test 6 */
++		{
++			TEST_INPUT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
++				   "fghijklmnopqrstuvwxyz0123456789"),
++			"0x73B70A39497DE53A6E08C67B6D4DB85"
++			"3540F03E9389299D9B0156EF7E85D0F61",
++			1
++		},
++		/* Test 7 */
++		{
++			TEST_INPUT("1234567890123456789012345678901"
++				   "2345678901234567890123456789012"
++				   "345678901234567890"),
++			"0x6BC7B38989B28CF93AE8842BF9D7529"
++			"05910A7528A61E5BCE0782DE43E610C90",
++			1
++		},
++		/* Test 8 */
++		{
++			TEST_INPUT("This is message, length=32 bytes"),
++			"0x2CEFC2F7B7BDC514E18EA57FA74FF35"
++			"7E7FA17D652C75F69CB1BE7893EDE48EB",
++			1
++		},
++		/* Test 9 */
++		{
++			TEST_INPUT("Suppose the original message "
++				   "has length = 50 bytes"),
++			"0xC3730C5CBCCACF915AC292676F21E8B"
++			"D4EF75331D9405E5F1A61DC3130A65011",
++			1
++		},
++		/* Test 10 */
++		{
++			TEST_INPUT("U") /* times 128 */,
++			"0x1C4AC7614691BBF427FA2316216BE8F"
++			"10D92EDFD37CD1027514C1008F649C4E8",
++			128
++		},
++		/* Test 11 */
++		{
++			TEST_INPUT("a") /* times 1000000 */,
++			"0x8693287AA62F9478F7CB312EC0866B6"
++			"C4E4A0F11160441E8F4FFCD2715DD554F",
++			1000000
++		},
++		{ NULL, 0, NULL, 1 }
++	};
++
++	result = dns_test_begin(NULL, ISC_FALSE);
++	ATF_REQUIRE(result == ISC_R_SUCCESS);
++
++	hash_testcase_t *testcase = testcases;
++
++	while (testcase->input != NULL && testcase->result != NULL) {
++		result = isc_gost_init(&gost);
++		ATF_REQUIRE(result == ISC_R_SUCCESS);
++		for(i = 0; i < testcase->repeats; i++) {
++			result = isc_gost_update(&gost,
++					(const isc_uint8_t *) testcase->input,
++					testcase->input_len);
++			ATF_REQUIRE(result == ISC_R_SUCCESS);
++		}
++		result = isc_gost_final(&gost, digest);
++		ATF_REQUIRE(result == ISC_R_SUCCESS);
++		tohexstr(digest, ISC_GOST_DIGESTLENGTH, str);
++		ATF_CHECK_STREQ(str, testcase->result);
++
++		testcase++;
++	}
++
++	dns_test_end();
++}
++#else
++ATF_TC(untested);
++ATF_TC_HEAD(untested, tc) {
++	atf_tc_set_md_var(tc, "descr", "skipping gost test");
++}
++ATF_TC_BODY(untested, tc) {
++	UNUSED(tc);
++	atf_tc_skip("GOST hash not available");
++}
++#endif
++/*
++ * Main
++ */
++ATF_TP_ADD_TCS(tp) {
++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
++	ATF_TP_ADD_TC(tp, isc_gost);
++#else
++	ATF_TP_ADD_TC(tp, untested);
++#endif
++	return (atf_no_error());
++}
++
+diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c
+index 161c188..20c98e5 100644
+--- a/lib/dns/tkey.c
++++ b/lib/dns/tkey.c
+@@ -45,8 +45,14 @@
+ #include <dst/dst.h>
+ #include <dst/gssapi.h>
+ 
++#include "dst_internal.h"
++
+ #define TKEY_RANDOM_AMOUNT 16
+ 
++#ifdef PKCS11CRYPTO
++#include <pk11/pk11.h>
++#endif
++
+ #define RETERR(x) do { \
+ 	result = (x); \
+ 	if (result != ISC_R_SUCCESS) \
+@@ -382,8 +388,8 @@ process_dhtkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name,
+ 	if (randomdata == NULL)
+ 		goto failure;
+ 
+-	result = isc_entropy_getdata(tctx->ectx, randomdata,
+-				     TKEY_RANDOM_AMOUNT, NULL, 0);
++	result = dst__entropy_getdata(randomdata, TKEY_RANDOM_AMOUNT,
++				      ISC_FALSE);
+ 	if (result != ISC_R_SUCCESS) {
+ 		tkey_log("process_dhtkey: failed to obtain entropy: %s",
+ 			 isc_result_totext(result));
+diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c
+index c7768f4..3239bff 100644
+--- a/lib/dns/tsig.c
++++ b/lib/dns/tsig.c
+@@ -946,8 +946,9 @@ dns_tsig_sign(dns_message_t *msg) {
+ 		isc_buffer_t headerbuf;
+ 		isc_uint16_t digestbits;
+ 
+-		ret = dst_context_create2(key->key, mctx,
+-					  DNS_LOGCATEGORY_DNSSEC, &ctx);
++		ret = dst_context_create3(key->key, mctx,
++					  DNS_LOGCATEGORY_DNSSEC,
++					  ISC_TRUE, &ctx);
+ 		if (ret != ISC_R_SUCCESS)
+ 			return (ret);
+ 
+@@ -1345,8 +1346,9 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
+ 		sig_r.base = tsig.signature;
+ 		sig_r.length = tsig.siglen;
+ 
+-		ret = dst_context_create2(key, mctx,
+-					  DNS_LOGCATEGORY_DNSSEC, &ctx);
++		ret = dst_context_create3(key, mctx,
++					  DNS_LOGCATEGORY_DNSSEC,
++					  ISC_FALSE, &ctx);
+ 		if (ret != ISC_R_SUCCESS)
+ 			return (ret);
+ 
+@@ -1577,9 +1579,9 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
+ 	key = tsigkey->key;
+ 
+ 	if (msg->tsigctx == NULL) {
+-		ret = dst_context_create2(key, mctx,
++		ret = dst_context_create3(key, mctx,
+ 					  DNS_LOGCATEGORY_DNSSEC,
+-					  &msg->tsigctx);
++					  ISC_FALSE, &msg->tsigctx);
+ 		if (ret != ISC_R_SUCCESS)
+ 			goto cleanup_querystruct;
+ 
+diff --git a/lib/export/dns/Makefile.in b/lib/export/dns/Makefile.in
+index 1e4540f..e10bf59 100644
+--- a/lib/export/dns/Makefile.in
++++ b/lib/export/dns/Makefile.in
+@@ -28,10 +28,10 @@ export_srcdir =	@top_srcdir@/lib/export
+ 
+ @BIND9_MAKE_INCLUDES@
+ 
+-CINCLUDES =	-I. -Iinclude ${DNS_INCLUDES} -I${export_srcdir}/isc/include \
++CINCLUDES =	-I. -I${top_srcdir}/lib/dns -Iinclude ${DNS_INCLUDES} -I${export_srcdir}/isc/include \
+ 		${ISC_INCLUDES} @DST_OPENSSL_INC@ @DST_GSSAPI_INC@
+ 
+-CDEFINES =	-DUSE_MD5 @USE_OPENSSL@ @USE_GSSAPI@
++CDEFINES =	-DUSE_MD5 @CRYPTO@ @USE_GSSAPI@
+ 
+ CWARNINGS =
+ 
+diff --git a/lib/export/isc/Makefile.in b/lib/export/isc/Makefile.in
+index 62e5acd..a5f8bd0 100644
+--- a/lib/export/isc/Makefile.in
++++ b/lib/export/isc/Makefile.in
+@@ -27,7 +27,7 @@ CINCLUDES =	-I${srcdir}/unix/include \
+ 		-I${srcdir}/@ISC_ARCH_DIR@/include \
+ 		-I${export_srcdir}/isc/include -I${srcdir}/include \
+ 		@ISC_OPENSSL_INC@
+-CDEFINES =	@USE_OPENSSL@ -DUSE_APPIMPREGISTER -DUSE_MEMIMPREGISTER \
++CDEFINES =	@CRYPTO@ -DUSE_APPIMPREGISTER -DUSE_MEMIMPREGISTER \
+ 		-DUSE_SOCKETIMPREGISTER -DUSE_TASKIMPREGISTER \
+ 		-DUSE_TIMERIMPREGISTER
+ CWARNINGS =
+@@ -48,7 +48,8 @@ UNIXOBJS =	@ISC_ISCIPV6_O@ \
+ 		unix/file.@O@ \
+ 		unix/fsaccess.@O@ \
+ 		unix/stdio.@O@ \
+-		unix/stdtime.@O@ unix/strerror.@O@ unix/time.@O@
++		unix/stdtime.@O@ unix/strerror.@O@ unix/time.@O@ unix/entropy.@O@ \
++		unix/keyboard.@O@
+ 
+ NLSOBJS =	nls/msgcat.@O@
+ 
+diff --git a/lib/export/isc/unix/Makefile.in b/lib/export/isc/unix/Makefile.in
+index 1873202..a904615 100644
+--- a/lib/export/isc/unix/Makefile.in
++++ b/lib/export/isc/unix/Makefile.in
+@@ -40,6 +40,8 @@ OBJS =		@ISC_IPV6_O@ \
+ 		file.@O@ fsaccess.@O@ \
+ 		stdio.@O@ stdtime.@O@ strerror.@O@ \
+ 		time.@O@ \
++		entropy.@O@ \
++		keyboard.@O@ \
+ 		${ISCDRIVEROBJS}
+ 
+ # Alphabetically
+@@ -51,6 +53,8 @@ SRCS =		@ISC_IPV6_C@ \
+ 		file.c fsaccess.c \
+ 		stdio.c stdtime.c strerror.c \
+ 		time.c \
++		entropy.c \
++		keyboard.c \
+ 		${ISCDRIVERSRCS}
+ 
+ SUBDIRS =	include
+diff --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in
+index eb718fd..df62ec9 100644
+--- a/lib/isc/Makefile.in
++++ b/lib/isc/Makefile.in
+@@ -23,16 +23,20 @@ top_srcdir =	@top_srcdir@
+ 
+ @LIBISC_API@
+ 
++@BIND9_MAKE_INCLUDES@
++
++PROVIDER =	@PKCS11_PROVIDER@
++
+ CINCLUDES =	-I${srcdir}/unix/include \
+ 		-I${srcdir}/@ISC_THREAD_DIR@/include \
+ 		-I${srcdir}/@ISC_ARCH_DIR@/include \
+ 		-I./include \
+-		-I${srcdir}/include @ISC_OPENSSL_INC@
+-CDEFINES =	@USE_OPENSSL@
++		-I${srcdir}/include @ISC_OPENSSL_INC@ ${DNS_INCLUDES}
++CDEFINES =	@CRYPTO@ -DPK11_LIB_LOCATION=\"${PROVIDER}\"
+ CWARNINGS =
+ 
+ # Alphabetically
+-UNIXOBJS =	@ISC_ISCIPV6_O@ \
++UNIXOBJS =	@ISC_ISCIPV6_O@ @ISC_ISCPK11_API_O@ \
+ 		unix/app.@O@ unix/dir.@O@ unix/entropy.@O@ \
+ 		unix/errno2result.@O@ unix/file.@O@ unix/fsaccess.@O@ \
+ 		unix/interfaceiter.@O@ unix/keyboard.@O@ unix/net.@O@ \
+@@ -50,7 +54,7 @@ WIN32OBJS = 	win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \
+ 		win32/thread.@O@ win32/time.@O@
+ 
+ # Alphabetically
+-OBJS =		@ISC_EXTRA_OBJS@ \
++OBJS =		@ISC_EXTRA_OBJS@ @ISC_PK11_O@ @ISC_PK11_RESULT_O@ \
+ 		assertions.@O@ backtrace.@O@ base32.@O@ base64.@O@ \
+ 		bitstring.@O@ buffer.@O@ bufferlist.@O@ commandline.@O@ \
+ 		counter.@O@ error.@O@ event.@O@ \
+@@ -68,7 +72,7 @@ OBJS =		@ISC_EXTRA_OBJS@ \
+ SYMTBLOBJS =	backtrace-emptytbl.@O@
+ 
+ # Alphabetically
+-SRCS =		@ISC_EXTRA_SRCS@ \
++SRCS =		@ISC_EXTRA_SRCS@ @ISC_PK11_C@ @ISC_PK11_RESULT_C@ \
+ 		assertions.c backtrace.c base32.c base64.c bitstring.c \
+ 		buffer.c bufferlist.c commandline.c counter.c \
+ 		error.c event.c heap.c hex.c hmacmd5.c hmacsha.c \
+diff --git a/lib/isc/entropy.c b/lib/isc/entropy.c
+index da9e81f..ae882d8 100644
+--- a/lib/isc/entropy.c
++++ b/lib/isc/entropy.c
+@@ -46,6 +46,9 @@
+ #include <isc/time.h>
+ #include <isc/util.h>
+ 
++#ifdef PKCS11CRYPTO
++#include <pk11/pk11.h>
++#endif
+ 
+ #define ENTROPY_MAGIC		ISC_MAGIC('E', 'n', 't', 'e')
+ #define SOURCE_MAGIC		ISC_MAGIC('E', 'n', 't', 's')
+@@ -1236,6 +1239,11 @@ isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
+ 		use_keyboard == ISC_ENTROPY_KEYBOARDNO  ||
+ 		use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE);
+ 
++#ifdef PKCS11CRYPTO
++	if (randomfile != NULL)
++		pk11_rand_seed_fromfile(randomfile);
++#endif
++
+ #ifdef PATH_RANDOMDEV
+ 	if (randomfile == NULL) {
+ 		randomfile = PATH_RANDOMDEV;
+diff --git a/lib/isc/hmacmd5.c b/lib/isc/hmacmd5.c
+index 4c4046d..79ec24a 100644
+--- a/lib/isc/hmacmd5.c
++++ b/lib/isc/hmacmd5.c
+@@ -33,6 +33,11 @@
+ #include <isc/types.h>
+ #include <isc/util.h>
+ 
++#if PKCS11CRYPTO || PKCS11CRYPTOWITHHMAC
++#include <pk11/internal.h>
++#include <pk11/pk11.h>
++#endif
++
+ #ifdef ISC_PLATFORM_OPENSSLHASH
+ 
+ void
+@@ -60,6 +65,167 @@ isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
+ 	HMAC_CTX_cleanup(ctx);
+ }
+ 
++#elif PKCS11CRYPTOWITHHMAC
++
++static CK_BBOOL truevalue = TRUE;
++static CK_BBOOL falsevalue = FALSE;
++
++void
++isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
++		 unsigned int len)
++{
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_MD5_HMAC, NULL, 0 };
++	CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
++	CK_KEY_TYPE keyType = CKK_MD5_HMAC;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_VALUE, NULL, (CK_ULONG) len }
++	};
++
++	DE_CONST(key, keyTemplate[5].pValue);
++	RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
++				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
++	ctx->object = CK_INVALID_HANDLE;
++	PK11_FATALCHECK(pkcs_C_CreateObject,
++			(ctx->session, keyTemplate,
++			 (CK_ULONG) 6, &ctx->object));
++	INSIST(ctx->object != CK_INVALID_HANDLE);
++	PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object));
++}
++
++void
++isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
++	CK_BYTE garbage[ISC_MD5_DIGESTLENGTH];
++	CK_ULONG len = ISC_MD5_DIGESTLENGTH;
++
++	if (ctx->handle == NULL)
++		return;
++	(void) pkcs_C_SignFinal(ctx->session, garbage, &len);
++	memset(garbage, 0, sizeof(garbage));
++	if (ctx->object != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(ctx->session, ctx->object);
++	ctx->object = CK_INVALID_HANDLE;
++	pk11_return_session(ctx);
++}
++
++void
++isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
++		   unsigned int len)
++{
++	CK_RV rv;
++	CK_BYTE_PTR pPart;
++
++	DE_CONST(buf, pPart);
++	PK11_FATALCHECK(pkcs_C_SignUpdate,
++			(ctx->session, pPart, (CK_ULONG) len));
++}
++
++void
++isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
++	CK_RV rv;
++	CK_ULONG len = ISC_MD5_DIGESTLENGTH;
++
++	PK11_FATALCHECK(pkcs_C_SignFinal,
++			(ctx->session, (CK_BYTE_PTR) digest, &len));
++	if (ctx->object != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(ctx->session, ctx->object);
++	ctx->object = CK_INVALID_HANDLE;
++	pk11_return_session(ctx);
++}
++
++#elif PKCS11CRYPTO
++
++#define PADLEN 64
++#define IPAD 0x36
++#define OPAD 0x5C
++
++void
++isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
++		 unsigned int len)
++{
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_MD5, NULL, 0 };
++	unsigned char ipad[PADLEN];
++	unsigned int i;
++
++	RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
++				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
++	RUNTIME_CHECK((ctx->key = pk11_mem_get(PADLEN)) != NULL);
++	if (len > PADLEN) {
++		CK_BYTE_PTR kPart;
++		CK_ULONG kl;
++
++		PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
++		DE_CONST(key, kPart);
++		PK11_FATALCHECK(pkcs_C_DigestUpdate,
++				(ctx->session, kPart, (CK_ULONG) len));
++		kl = ISC_MD5_DIGESTLENGTH;
++		PK11_FATALCHECK(pkcs_C_DigestFinal,
++				(ctx->session, (CK_BYTE_PTR) ctx->key, &kl));
++	} else
++		memcpy(ctx->key, key, len);
++	PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
++	memset(ipad, IPAD, PADLEN);
++	for (i = 0; i < PADLEN; i++)
++		ipad[i] ^= ctx->key[i];
++	PK11_FATALCHECK(pkcs_C_DigestUpdate,
++			(ctx->session, ipad, (CK_ULONG) PADLEN));
++}
++
++void
++isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
++	if (ctx->key != NULL)
++		pk11_mem_put(ctx->key, PADLEN);
++	ctx->key = NULL;
++	isc_md5_invalidate(ctx);
++}
++
++void
++isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
++		   unsigned int len)
++{
++	CK_RV rv;
++	CK_BYTE_PTR pPart;
++
++	DE_CONST(buf, pPart);
++	PK11_FATALCHECK(pkcs_C_DigestUpdate,
++			(ctx->session, pPart, (CK_ULONG) len));
++}
++
++void
++isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_MD5, NULL, 0 };
++	CK_ULONG len = ISC_MD5_DIGESTLENGTH;
++	CK_BYTE opad[PADLEN];
++	unsigned int i;
++
++	PK11_FATALCHECK(pkcs_C_DigestFinal,
++			(ctx->session, (CK_BYTE_PTR) digest,
++			 (CK_ULONG_PTR) &len));
++	memset(opad, OPAD, PADLEN);
++	for (i = 0; i < PADLEN; i++)
++		opad[i] ^= ctx->key[i];
++	pk11_mem_put(ctx->key, PADLEN);
++	ctx->key = NULL;
++	PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
++	PK11_FATALCHECK(pkcs_C_DigestUpdate,
++			(ctx->session, opad, (CK_ULONG) PADLEN));
++	PK11_FATALCHECK(pkcs_C_DigestUpdate,
++			(ctx->session, (CK_BYTE_PTR) digest, len));
++	PK11_FATALCHECK(pkcs_C_DigestFinal,
++			(ctx->session,
++			 (CK_BYTE_PTR) digest,
++			 (CK_ULONG_PTR) &len));
++	pk11_return_session(ctx);
++}
++
+ #else
+ 
+ #define PADLEN 64
+diff --git a/lib/isc/hmacsha.c b/lib/isc/hmacsha.c
+index 3870963..9b79bc7 100644
+--- a/lib/isc/hmacsha.c
++++ b/lib/isc/hmacsha.c
+@@ -34,6 +34,11 @@
+ #include <isc/types.h>
+ #include <isc/util.h>
+ 
++#if PKCS11CRYPTO
++#include <pk11/internal.h>
++#include <pk11/pk11.h>
++#endif
++ 
+ #ifdef ISC_PLATFORM_OPENSSLHASH
+ 
+ void
+@@ -191,6 +196,376 @@ isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) {
+ 	memset(newdigest, 0, sizeof(newdigest));
+ }
+ 
++#elif PKCS11CRYPTO
++
++static CK_BBOOL truevalue = TRUE;
++static CK_BBOOL falsevalue = FALSE;
++
++void
++isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key,
++		 unsigned int len)
++{
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_SHA_1_HMAC, NULL, 0 };
++	CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
++	CK_KEY_TYPE keyType = CKK_SHA_1_HMAC;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_VALUE, NULL, (CK_ULONG) len }
++	};
++
++	DE_CONST(key, keyTemplate[5].pValue);
++	RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
++				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
++	ctx->object = CK_INVALID_HANDLE;
++	PK11_FATALCHECK(pkcs_C_CreateObject,
++			(ctx->session, keyTemplate,
++			 (CK_ULONG) 6, &ctx->object));
++	INSIST(ctx->object != CK_INVALID_HANDLE);
++	PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object));
++}
++
++void
++isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx) {
++	CK_BYTE garbage[ISC_SHA1_DIGESTLENGTH];
++	CK_ULONG len = ISC_SHA1_DIGESTLENGTH;
++
++	if (ctx->handle == NULL)
++		return;
++	(void) pkcs_C_SignFinal(ctx->session, garbage, &len);
++	memset(garbage, 0, sizeof(garbage));
++	if (ctx->object != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(ctx->session, ctx->object);
++	ctx->object = CK_INVALID_HANDLE;
++	pk11_return_session(ctx);
++}
++
++void
++isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf,
++		   unsigned int len)
++{
++	CK_RV rv;
++	CK_BYTE_PTR pPart;
++
++	DE_CONST(buf, pPart);
++	PK11_FATALCHECK(pkcs_C_SignUpdate,
++			(ctx->session, pPart, (CK_ULONG) len));
++}
++
++void
++isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) {
++	CK_RV rv;
++	CK_BYTE newdigest[ISC_SHA1_DIGESTLENGTH];
++	CK_ULONG psl = ISC_SHA1_DIGESTLENGTH;
++
++	REQUIRE(len <= ISC_SHA1_DIGESTLENGTH);
++
++	PK11_FATALCHECK(pkcs_C_SignFinal, (ctx->session, newdigest, &psl));
++	if (ctx->object != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(ctx->session, ctx->object);
++	ctx->object = CK_INVALID_HANDLE;
++	pk11_return_session(ctx);
++	memcpy(digest, newdigest, len);
++	memset(newdigest, 0, sizeof(newdigest));
++}
++
++void
++isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key,
++		    unsigned int len)
++{
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_SHA224_HMAC, NULL, 0 };
++	CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
++	CK_KEY_TYPE keyType = CKK_SHA224_HMAC;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_VALUE, NULL, (CK_ULONG) len }
++	};
++
++	DE_CONST(key, keyTemplate[5].pValue);
++	RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
++				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
++	ctx->object = CK_INVALID_HANDLE;
++	PK11_FATALCHECK(pkcs_C_CreateObject,
++			(ctx->session, keyTemplate,
++			 (CK_ULONG) 6, &ctx->object));
++	INSIST(ctx->object != CK_INVALID_HANDLE);
++	PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object));
++}
++
++void
++isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx) {
++	CK_BYTE garbage[ISC_SHA224_DIGESTLENGTH];
++	CK_ULONG len = ISC_SHA224_DIGESTLENGTH;
++
++	if (ctx->handle == NULL)
++		return;
++	(void) pkcs_C_SignFinal(ctx->session, garbage, &len);
++	memset(garbage, 0, sizeof(garbage));
++	if (ctx->object != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(ctx->session, ctx->object);
++	ctx->object = CK_INVALID_HANDLE;
++	pk11_return_session(ctx);
++}
++
++void
++isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf,
++		      unsigned int len)
++{
++	CK_RV rv;
++	CK_BYTE_PTR pPart;
++
++	DE_CONST(buf, pPart);
++	PK11_FATALCHECK(pkcs_C_SignUpdate,
++			(ctx->session, pPart, (CK_ULONG) len));
++}
++
++void
++isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) {
++	CK_RV rv;
++	CK_BYTE newdigest[ISC_SHA224_DIGESTLENGTH];
++	CK_ULONG psl = ISC_SHA224_DIGESTLENGTH;
++
++	REQUIRE(len <= ISC_SHA224_DIGESTLENGTH);
++
++	PK11_FATALCHECK(pkcs_C_SignFinal, (ctx->session, newdigest, &psl));
++	if (ctx->object != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(ctx->session, ctx->object);
++	ctx->object = CK_INVALID_HANDLE;
++	pk11_return_session(ctx);
++	memcpy(digest, newdigest, len);
++	memset(newdigest, 0, sizeof(newdigest));
++}
++
++void
++isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key,
++		    unsigned int len)
++{
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_SHA256_HMAC, NULL, 0 };
++	CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
++	CK_KEY_TYPE keyType = CKK_SHA256_HMAC;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_VALUE, NULL, (CK_ULONG) len }
++	};
++
++	DE_CONST(key, keyTemplate[5].pValue);
++	RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
++				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
++	ctx->object = CK_INVALID_HANDLE;
++	PK11_FATALCHECK(pkcs_C_CreateObject,
++			(ctx->session, keyTemplate,
++			 (CK_ULONG) 6, &ctx->object));
++	INSIST(ctx->object != CK_INVALID_HANDLE);
++	PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object));
++}
++
++void
++isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx) {
++	CK_BYTE garbage[ISC_SHA256_DIGESTLENGTH];
++	CK_ULONG len = ISC_SHA256_DIGESTLENGTH;
++
++	if (ctx->handle == NULL)
++		return;
++	(void) pkcs_C_SignFinal(ctx->session, garbage, &len);
++	memset(garbage, 0, sizeof(garbage));
++	if (ctx->object != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(ctx->session, ctx->object);
++	ctx->object = CK_INVALID_HANDLE;
++	pk11_return_session(ctx);
++}
++
++void
++isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf,
++		      unsigned int len)
++{
++	CK_RV rv;
++	CK_BYTE_PTR pPart;
++
++	DE_CONST(buf, pPart);
++	PK11_FATALCHECK(pkcs_C_SignUpdate,
++			(ctx->session, pPart, (CK_ULONG) len));
++}
++
++void
++isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) {
++	CK_RV rv;
++	CK_BYTE newdigest[ISC_SHA256_DIGESTLENGTH];
++	CK_ULONG psl = ISC_SHA256_DIGESTLENGTH;
++
++	REQUIRE(len <= ISC_SHA256_DIGESTLENGTH);
++
++	PK11_FATALCHECK(pkcs_C_SignFinal, (ctx->session, newdigest, &psl));
++	if (ctx->object != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(ctx->session, ctx->object);
++	ctx->object = CK_INVALID_HANDLE;
++	pk11_return_session(ctx);
++	memcpy(digest, newdigest, len);
++	memset(newdigest, 0, sizeof(newdigest));
++}
++
++void
++isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key,
++		    unsigned int len)
++{
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_SHA384_HMAC, NULL, 0 };
++	CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
++	CK_KEY_TYPE keyType = CKK_SHA384_HMAC;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_VALUE, NULL, (CK_ULONG) len }
++	};
++
++	DE_CONST(key, keyTemplate[5].pValue);
++	RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
++				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
++	ctx->object = CK_INVALID_HANDLE;
++	PK11_FATALCHECK(pkcs_C_CreateObject,
++			(ctx->session, keyTemplate,
++			 (CK_ULONG) 6, &ctx->object));
++	INSIST(ctx->object != CK_INVALID_HANDLE);
++	PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object));
++}
++
++void
++isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx) {
++	CK_BYTE garbage[ISC_SHA384_DIGESTLENGTH];
++	CK_ULONG len = ISC_SHA384_DIGESTLENGTH;
++
++	if (ctx->handle == NULL)
++		return;
++	(void) pkcs_C_SignFinal(ctx->session, garbage, &len);
++	memset(garbage, 0, sizeof(garbage));
++	if (ctx->object != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(ctx->session, ctx->object);
++	ctx->object = CK_INVALID_HANDLE;
++	pk11_return_session(ctx);
++}
++
++void
++isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf,
++		      unsigned int len)
++{
++	CK_RV rv;
++	CK_BYTE_PTR pPart;
++
++	DE_CONST(buf, pPart);
++	PK11_FATALCHECK(pkcs_C_SignUpdate,
++			(ctx->session, pPart, (CK_ULONG) len));
++}
++
++void
++isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) {
++	CK_RV rv;
++	CK_BYTE newdigest[ISC_SHA384_DIGESTLENGTH];
++	CK_ULONG psl = ISC_SHA384_DIGESTLENGTH;
++
++	REQUIRE(len <= ISC_SHA384_DIGESTLENGTH);
++
++	PK11_FATALCHECK(pkcs_C_SignFinal, (ctx->session, newdigest, &psl));
++	if (ctx->object != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(ctx->session, ctx->object);
++	ctx->object = CK_INVALID_HANDLE;
++	pk11_return_session(ctx);
++	memcpy(digest, newdigest, len);
++	memset(newdigest, 0, sizeof(newdigest));
++}
++
++void
++isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key,
++		    unsigned int len)
++{
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_SHA512_HMAC, NULL, 0 };
++	CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
++	CK_KEY_TYPE keyType = CKK_SHA512_HMAC;
++	CK_ATTRIBUTE keyTemplate[] =
++	{
++		{ CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
++		{ CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
++		{ CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
++		{ CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
++		{ CKA_VALUE, NULL, (CK_ULONG) len }
++	};
++
++	DE_CONST(key, keyTemplate[5].pValue);
++	RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
++				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
++	ctx->object = CK_INVALID_HANDLE;
++	PK11_FATALCHECK(pkcs_C_CreateObject,
++			(ctx->session, keyTemplate,
++			 (CK_ULONG) 6, &ctx->object));
++	INSIST(ctx->object != CK_INVALID_HANDLE);
++	PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object));
++}
++
++void
++isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx) {
++	CK_BYTE garbage[ISC_SHA512_DIGESTLENGTH];
++	CK_ULONG len = ISC_SHA512_DIGESTLENGTH;
++
++	if (ctx->handle == NULL)
++		return;
++	(void) pkcs_C_SignFinal(ctx->session, garbage, &len);
++	memset(garbage, 0, sizeof(garbage));
++	if (ctx->object != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(ctx->session, ctx->object);
++	ctx->object = CK_INVALID_HANDLE;
++	pk11_return_session(ctx);
++}
++
++void
++isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf,
++		      unsigned int len)
++{
++	CK_RV rv;
++	CK_BYTE_PTR pPart;
++
++	DE_CONST(buf, pPart);
++	PK11_FATALCHECK(pkcs_C_SignUpdate,
++			(ctx->session, pPart, (CK_ULONG) len));
++}
++
++void
++isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) {
++	CK_RV rv;
++	CK_BYTE newdigest[ISC_SHA512_DIGESTLENGTH];
++	CK_ULONG psl = ISC_SHA512_DIGESTLENGTH;
++
++	REQUIRE(len <= ISC_SHA512_DIGESTLENGTH);
++
++	PK11_FATALCHECK(pkcs_C_SignFinal, (ctx->session, newdigest, &psl));
++	if (ctx->object != CK_INVALID_HANDLE)
++		(void) pkcs_C_DestroyObject(ctx->session, ctx->object);
++	ctx->object = CK_INVALID_HANDLE;
++	pk11_return_session(ctx);
++	memcpy(digest, newdigest, len);
++	memset(newdigest, 0, sizeof(newdigest));
++}
++
+ #else
+ 
+ #define IPAD 0x36
+diff --git a/lib/isc/include/Makefile.in b/lib/isc/include/Makefile.in
+index 70c165e..c92ad45 100644
+--- a/lib/isc/include/Makefile.in
++++ b/lib/isc/include/Makefile.in
+@@ -19,7 +19,7 @@ srcdir =	@srcdir@
+ VPATH =		@srcdir@
+ top_srcdir =	@top_srcdir@
+ 
+-SUBDIRS =	isc
++SUBDIRS =	isc pk11 pkcs11
+ TARGETS =
+ 
+ @BIND9_MAKE_RULES@
+diff --git a/lib/isc/include/isc/hmacmd5.h b/lib/isc/include/isc/hmacmd5.h
+index 9ecad45..e008328 100644
+--- a/lib/isc/include/isc/hmacmd5.h
++++ b/lib/isc/include/isc/hmacmd5.h
+@@ -37,6 +37,11 @@
+ 
+ typedef HMAC_CTX isc_hmacmd5_t;
+ 
++#elif PKCS11CRYPTO
++#include <pk11/pk11.h>
++
++typedef pk11_context_t isc_hmacmd5_t;
++
+ #else
+ 
+ typedef struct {
+diff --git a/lib/isc/include/isc/hmacsha.h b/lib/isc/include/isc/hmacsha.h
+index 1d0e184..c223897 100644
+--- a/lib/isc/include/isc/hmacsha.h
++++ b/lib/isc/include/isc/hmacsha.h
+@@ -45,6 +45,15 @@ typedef HMAC_CTX isc_hmacsha256_t;
+ typedef HMAC_CTX isc_hmacsha384_t;
+ typedef HMAC_CTX isc_hmacsha512_t;
+ 
++#elif PKCS11CRYPTO
++#include <pk11/pk11.h>
++
++typedef pk11_context_t isc_hmacsha1_t;
++typedef pk11_context_t isc_hmacsha224_t;
++typedef pk11_context_t isc_hmacsha256_t;
++typedef pk11_context_t isc_hmacsha384_t;
++typedef pk11_context_t isc_hmacsha512_t;
++
+ #else
+ 
+ typedef struct {
+diff --git a/lib/isc/include/isc/md5.h b/lib/isc/include/isc/md5.h
+index dfa586d..a2e00b3 100644
+--- a/lib/isc/include/isc/md5.h
++++ b/lib/isc/include/isc/md5.h
+@@ -55,6 +55,11 @@
+ 
+ typedef EVP_MD_CTX isc_md5_t;
+ 
++#elif PKCS11CRYPTO
++#include <pk11/pk11.h>
++
++typedef pk11_context_t isc_md5_t;
++
+ #else
+ 
+ typedef struct {
+diff --git a/lib/isc/include/isc/resultclass.h b/lib/isc/include/isc/resultclass.h
+index d91e800..44b0eb4 100644
+--- a/lib/isc/include/isc/resultclass.h
++++ b/lib/isc/include/isc/resultclass.h
+@@ -46,6 +46,6 @@
+ #define	ISC_RESULTCLASS_OMAPI		ISC_RESULTCLASS_FROMNUM(4)
+ #define	ISC_RESULTCLASS_ISCCC		ISC_RESULTCLASS_FROMNUM(5)
+ #define	ISC_RESULTCLASS_DHCP		ISC_RESULTCLASS_FROMNUM(6)
+-
++#define	ISC_RESULTCLASS_PK11		ISC_RESULTCLASS_FROMNUM(7)
+ 
+ #endif /* ISC_RESULTCLASS_H */
+diff --git a/lib/isc/include/isc/sha1.h b/lib/isc/include/isc/sha1.h
+index 313ff96..f11a783 100644
+--- a/lib/isc/include/isc/sha1.h
++++ b/lib/isc/include/isc/sha1.h
+@@ -40,6 +40,11 @@
+ 
+ typedef EVP_MD_CTX isc_sha1_t;
+ 
++#elif PKCS11CRYPTO
++#include <pk11/pk11.h>
++
++typedef pk11_context_t isc_sha1_t;
++
+ #else
+ 
+ typedef struct {
+diff --git a/lib/isc/include/isc/sha2.h b/lib/isc/include/isc/sha2.h
+index 439bbb9..14faa6e 100644
+--- a/lib/isc/include/isc/sha2.h
++++ b/lib/isc/include/isc/sha2.h
+@@ -84,6 +84,12 @@
+ typedef EVP_MD_CTX isc_sha256_t;
+ typedef EVP_MD_CTX isc_sha512_t;
+ 
++#elif PKCS11CRYPTO
++#include <pk11/pk11.h>
++
++typedef pk11_context_t isc_sha256_t;
++typedef pk11_context_t isc_sha512_t;
++
+ #else
+ 
+ /*
+diff --git a/lib/isc/include/pk11/Makefile.in b/lib/isc/include/pk11/Makefile.in
+new file mode 100644
+index 0000000..744c40e
+--- /dev/null
++++ b/lib/isc/include/pk11/Makefile.in
+@@ -0,0 +1,38 @@
++# Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
++#
++# Permission to use, copy, modify, and/or distribute this software for any
++# purpose with or without fee is hereby granted, provided that the above
++# copyright notice and this permission notice appear in all copies.
++#
++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++# PERFORMANCE OF THIS SOFTWARE.
++
++srcdir =	@srcdir@
++VPATH =		@srcdir@
++top_srcdir =	@top_srcdir@
++
++@BIND9_VERSION@
++
++#
++# Only list headers that are to be installed and are not
++# machine generated.  The latter are handled specially in the
++# install target below.
++#
++HEADERS =	constants.h internal.h pk11.h result.h
++SUBDIRS =
++TARGETS =
++
++@BIND9_MAKE_RULES@
++
++installdirs:
++	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/pk11
++
++install:: installdirs
++	for i in ${HEADERS}; do \
++		${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/pk11 ; \
++	done
+diff --git a/lib/isc/include/pk11/constants.h b/lib/isc/include/pk11/constants.h
+new file mode 100644
+index 0000000..e1e0581
+--- /dev/null
++++ b/lib/isc/include/pk11/constants.h
+@@ -0,0 +1,107 @@
++/*
++ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* $Id$ */
++
++#ifndef PK11_CONSTANTS_H
++#define PK11_CONSTANTS_H 1
++
++/*! \file pk11/constants.h */
++
++/*%
++ * Static arrays of data used for key template initalization
++ */
++#ifdef WANT_ECC_CURVES
++static CK_BYTE pk11_ecc_prime256v1[] = {
++	0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
++};
++static CK_BYTE pk11_ecc_secp384r1[] = {
++	0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22
++};
++#endif
++
++#ifdef WANT_DH_PRIMES
++static CK_BYTE pk11_dh_bn2[] = { 2 };
++static CK_BYTE pk11_dh_bn768[] = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
++	0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1,
++	0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
++	0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22,
++	0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
++	0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b,
++	0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
++	0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
++	0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
++	0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x3a, 0x36, 0x20,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static CK_BYTE pk11_dh_bn1024[] = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
++	0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1,
++	0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
++	0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22,
++	0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
++	0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b,
++	0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
++	0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
++	0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
++	0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b,
++	0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
++	0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5,
++	0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6,
++	0x49, 0x28, 0x66, 0x51, 0xec, 0xe6, 0x53, 0x81,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++static CK_BYTE pk11_dh_bn1536[] = {
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++	0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
++	0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1,
++	0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
++	0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22,
++	0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
++	0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b,
++	0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
++	0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
++	0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
++	0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b,
++	0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
++	0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5,
++	0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6,
++	0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d,
++	0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05,
++	0x98, 0xda, 0x48, 0x36, 0x1c, 0x55, 0xd3, 0x9a,
++	0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f,
++	0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96,
++	0x1c, 0x62, 0xf3, 0x56, 0x20, 0x85, 0x52, 0xbb,
++	0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d,
++	0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04,
++	0xf1, 0x74, 0x6c, 0x08, 0xca, 0x23, 0x73, 0x27,
++	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++#endif
++
++#ifdef WANT_GOST_PARAMS
++static CK_BYTE pk11_gost_a_paramset[] = {
++	0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01
++};
++static CK_BYTE pk11_gost_paramset[] = {
++	0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01
++};
++#endif
++
++#endif /* PK11_CONSTANTS_H */
+diff --git a/lib/isc/include/pk11/internal.h b/lib/isc/include/pk11/internal.h
+new file mode 100644
+index 0000000..14bef3c
+--- /dev/null
++++ b/lib/isc/include/pk11/internal.h
+@@ -0,0 +1,46 @@
++/*
++ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* $Id$ */
++
++#ifndef PK11_INTERNAL_H
++#define PK11_INTERNAL_H 1
++
++/*! \file pk11/internal.h */
++
++ISC_LANG_BEGINDECLS
++
++const char *pk11_get_lib_name(void);
++
++void *pk11_mem_get(size_t size);
++
++void pk11_mem_put(void *ptr, size_t size);
++
++CK_SLOT_ID pk11_get_best_token(pk11_optype_t optype);
++
++unsigned int pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt);
++
++CK_ATTRIBUTE *pk11_attribute_first(const pk11_object_t *obj);
++
++CK_ATTRIBUTE *pk11_attribute_next(const pk11_object_t *obj,
++				  CK_ATTRIBUTE *attr);
++
++CK_ATTRIBUTE *pk11_attribute_bytype(const pk11_object_t *obj,
++				    CK_ATTRIBUTE_TYPE type);
++
++ISC_LANG_ENDDECLS
++
++#endif /* PK11_INTERNAL_H */
+diff --git a/lib/isc/include/pk11/pk11.h b/lib/isc/include/pk11/pk11.h
+new file mode 100644
+index 0000000..964a2a7
+--- /dev/null
++++ b/lib/isc/include/pk11/pk11.h
+@@ -0,0 +1,295 @@
++/*
++ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#ifndef PK11_PK11_H
++#define PK11_PK11_H 1
++
++/*! \file pk11/pk11.h */
++
++#include <isc/lang.h>
++#include <isc/magic.h>
++#include <isc/types.h>
++
++#define PK11_FATALCHECK(func, args) \
++	((void) (((rv = (func) args) == CKR_OK) || \
++		 ((pk11_error_fatalcheck)(__FILE__, __LINE__, #func, rv), 0)))
++
++#include <pkcs11/cryptoki.h>
++
++ISC_LANG_BEGINDECLS
++
++#define SES_MAGIC	ISC_MAGIC('P','K','S','S')
++#define TOK_MAGIC	ISC_MAGIC('P','K','T','K')
++
++#define VALID_SES(x)	ISC_MAGIC_VALID(x, SES_MAGIC)
++#define VALID_TOK(x)	ISC_MAGIC_VALID(x, TOK_MAGIC)
++
++typedef struct pk11_context pk11_context_t;
++
++struct pk11_object {
++	CK_OBJECT_HANDLE	object;
++	CK_SLOT_ID		slot;
++	CK_BBOOL		ontoken;
++	CK_BBOOL		reqlogon;
++	CK_BYTE			attrcnt;
++	CK_ATTRIBUTE		*repr;
++};
++
++struct pk11_context {
++	void			*handle;
++	CK_SESSION_HANDLE	session;
++	CK_BBOOL		ontoken;
++	CK_OBJECT_HANDLE	object;
++#ifndef PKCS11CRYPTOWITHHMAC
++	unsigned char		*key;
++#endif
++};
++
++typedef struct pk11_object pk11_object_t;
++
++typedef enum {
++	OP_ANY = 0,
++	OP_RAND = 1,
++	OP_RSA = 2,
++	OP_DSA = 3,
++	OP_DH = 4,
++	OP_DIGEST = 5,
++	OP_EC = 6,
++	OP_GOST = 7,
++	OP_AES = 8,
++	OP_MAX = 9
++} pk11_optype_t;
++
++/*%
++ * Function prototypes
++ */
++
++void pk11_set_lib_name(const char *lib_name);
++/*%<
++ * Set the PKCS#11 provider (aka library) path/name.
++ */
++
++isc_result_t pk11_initialize(isc_mem_t *mctx, const char *engine);
++/*%<
++ * Initialize PKCS#11 device
++ *
++ * mctx:   memory context to attach to pk11_mctx.
++ * engine: PKCS#11 provider (aka library) path/name.
++ *
++ * returns:
++ *         ISC_R_SUCCESS
++ *         PK11_R_NOPROVIDER: can't load the provider
++ *         PK11_R_INITFAILED: C_Initialize() failed
++ *         PK11_R_NORANDOMSERVICE: can't find required random service
++ *         PK11_R_NODIGESTSERVICE: can't find required digest service
++ *         PK11_R_NOAESSERVICE: can't find required AES service
++ */
++
++isc_result_t pk11_get_session(pk11_context_t *ctx,
++			      pk11_optype_t optype,
++			      isc_boolean_t need_services,
++			      isc_boolean_t rw,
++			      isc_boolean_t logon,
++			      const char *pin,
++			      CK_SLOT_ID slot);
++/*%<
++ * Initialize PKCS#11 device and acquire a session.
++ *
++ * need_services:
++ * 	  if ISC_TRUE, this session requires full PKCS#11 API
++ * 	  support including random and digest services, and
++ * 	  the lack of these services will cause the session not
++ * 	  to be initialized.  If ISC_FALSE, the function will return
++ * 	  an error code indicating the missing service, but the
++ * 	  session will be usable for other purposes.
++ * rw:    if ISC_TRUE, session will be read/write (useful for
++ *        generating or destroying keys); otherwise read-only.
++ * login: indicates whether to log in to the device
++ * pin:   optional PIN, overriding any PIN currently associated
++ *        with the
++ * slot:  device slot ID
++ */
++
++void pk11_return_session(pk11_context_t *ctx);
++/*%<
++ * Release an active PKCS#11 session for reuse.
++ */
++
++isc_result_t pk11_finalize(void);
++/*%<
++ * Shut down PKCS#11 device and free all sessions.
++ */
++
++isc_result_t pk11_rand_bytes(unsigned char *buf, int num);
++
++void pk11_rand_seed_fromfile(const char *randomfile);
++
++isc_result_t pk11_parse_uri(pk11_object_t *obj, const char *label,
++			    isc_mem_t *mctx, pk11_optype_t optype);
++
++ISC_PLATFORM_NORETURN_PRE void
++pk11_error_fatalcheck(const char *file, int line,
++		      const char *funcname, CK_RV rv)
++ISC_PLATFORM_NORETURN_POST;
++
++void pk11_dump_tokens(void);
++
++CK_RV
++pkcs_C_Initialize(CK_VOID_PTR pReserved);
++
++CK_RV
++pkcs_C_Finalize(CK_VOID_PTR pReserved);
++
++CK_RV
++pkcs_C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList,
++		   CK_ULONG_PTR pulCount);
++
++CK_RV
++pkcs_C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo);
++
++CK_RV
++pkcs_C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
++			CK_MECHANISM_INFO_PTR pInfo);
++
++CK_RV
++pkcs_C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags,
++		   CK_VOID_PTR pApplication,
++		   CK_RV  (*Notify) (CK_SESSION_HANDLE hSession,
++				     CK_NOTIFICATION event,
++				     CK_VOID_PTR pApplication),
++		   CK_SESSION_HANDLE_PTR phSession);
++
++CK_RV
++pkcs_C_CloseSession(CK_SESSION_HANDLE hSession);
++
++CK_RV
++pkcs_C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
++	     CK_CHAR_PTR pPin, CK_ULONG usPinLen);
++
++CK_RV
++pkcs_C_Logout(CK_SESSION_HANDLE hSession);
++
++CK_RV
++pkcs_C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
++		    CK_ULONG usCount, CK_OBJECT_HANDLE_PTR phObject);
++
++CK_RV
++pkcs_C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject);
++
++CK_RV
++pkcs_C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
++			 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG usCount);
++
++CK_RV
++pkcs_C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
++			 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG usCount);
++
++CK_RV
++pkcs_C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
++		       CK_ULONG usCount);
++
++CK_RV
++pkcs_C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject,
++		   CK_ULONG usMaxObjectCount, CK_ULONG_PTR pusObjectCount);
++
++CK_RV
++pkcs_C_FindObjectsFinal(CK_SESSION_HANDLE hSession);
++
++CK_RV
++pkcs_C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
++		   CK_OBJECT_HANDLE hKey);
++
++CK_RV
++pkcs_C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
++	       CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData,
++	       CK_ULONG_PTR pulEncryptedDataLen);
++
++CK_RV
++pkcs_C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism);
++
++CK_RV
++pkcs_C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
++		    CK_ULONG ulPartLen);
++
++CK_RV
++pkcs_C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest,
++		   CK_ULONG_PTR pulDigestLen);
++
++CK_RV
++pkcs_C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
++		CK_OBJECT_HANDLE hKey);
++
++CK_RV
++pkcs_C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
++	    CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
++	    CK_ULONG_PTR pulSignatureLen);
++
++CK_RV
++pkcs_C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
++		  CK_ULONG ulPartLen);
++
++CK_RV
++pkcs_C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
++		 CK_ULONG_PTR pulSignatureLen);
++
++CK_RV
++pkcs_C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
++		  CK_OBJECT_HANDLE hKey);
++
++CK_RV
++pkcs_C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
++	      CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
++	      CK_ULONG ulSignatureLen);
++
++CK_RV
++pkcs_C_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
++		    CK_ULONG ulPartLen);
++
++CK_RV
++pkcs_C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
++		   CK_ULONG ulSignatureLen);
++
++CK_RV
++pkcs_C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
++		   CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
++		   CK_OBJECT_HANDLE_PTR phKey);
++
++CK_RV
++pkcs_C_GenerateKeyPair(CK_SESSION_HANDLE hSession,
++		       CK_MECHANISM_PTR pMechanism,
++		       CK_ATTRIBUTE_PTR pPublicKeyTemplate,
++		       CK_ULONG usPublicKeyAttributeCount,
++		       CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
++		       CK_ULONG usPrivateKeyAttributeCount,
++		       CK_OBJECT_HANDLE_PTR phPrivateKey,
++		       CK_OBJECT_HANDLE_PTR phPublicKey);
++
++CK_RV
++pkcs_C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
++		 CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
++		 CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey);
++
++CK_RV
++pkcs_C_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed,
++		  CK_ULONG ulSeedLen);
++
++CK_RV
++pkcs_C_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR RandomData,
++		      CK_ULONG ulRandomLen);
++
++ISC_LANG_ENDDECLS
++
++#endif /* PK11_PK11_H */
+diff --git a/lib/isc/include/pk11/result.h b/lib/isc/include/pk11/result.h
+new file mode 100644
+index 0000000..f624140
+--- /dev/null
++++ b/lib/isc/include/pk11/result.h
+@@ -0,0 +1,56 @@
++/*
++ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#ifndef PK11_RESULT_H
++#define PK11_RESULT_H 1
++
++/*! \file pk11/result.h */
++
++#include <isc/lang.h>
++#include <isc/resultclass.h>
++
++/*
++ * Nothing in this file truly depends on <isc/result.h>, but the
++ * PK11 result codes are considered to be publicly derived from
++ * the ISC result codes, so including this file buys you the ISC_R_
++ * namespace too.
++ */
++#include <isc/result.h>		/* Contractual promise. */
++
++#define PK11_R_INITFAILED		(ISC_RESULTCLASS_PK11 + 0)
++#define PK11_R_NOPROVIDER		(ISC_RESULTCLASS_PK11 + 1)
++#define PK11_R_NORANDOMSERVICE		(ISC_RESULTCLASS_PK11 + 2)
++#define PK11_R_NODIGESTSERVICE		(ISC_RESULTCLASS_PK11 + 3)
++#define PK11_R_NOAESSERVICE		(ISC_RESULTCLASS_PK11 + 4)
++
++#define PK11_R_NRESULTS			5	/* Number of results */
++
++ISC_LANG_BEGINDECLS
++
++LIBISC_EXTERNAL_DATA extern isc_msgcat_t *pk11_msgcat;
++
++void
++pk11_initmsgcat(void);
++
++const char *
++pk11_result_totext(isc_result_t);
++
++void
++pk11_result_register(void);
++
++ISC_LANG_ENDDECLS
++
++#endif /* PK11_RESULT_H */
+diff --git a/lib/isc/include/pkcs11/Makefile.in b/lib/isc/include/pkcs11/Makefile.in
+new file mode 100644
+index 0000000..6e98688
+--- /dev/null
++++ b/lib/isc/include/pkcs11/Makefile.in
+@@ -0,0 +1,40 @@
++# Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
++#
++# Permission to use, copy, modify, and/or distribute this software for any
++# purpose with or without fee is hereby granted, provided that the above
++# copyright notice and this permission notice appear in all copies.
++#
++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++# PERFORMANCE OF THIS SOFTWARE.
++
++# $Id: Makefile.in,v 1.7 2007/06/19 23:47:22 tbox Exp $
++
++srcdir =	@srcdir@
++VPATH =		@srcdir@
++top_srcdir =	@top_srcdir@
++
++@BIND9_VERSION@
++
++#
++# Only list headers that are to be installed and are not
++# machine generated.  The latter are handled specially in the
++# install target below.
++#
++HEADERS =	pkcs11f.h pkcs11.h pkcs11t.h
++SUBDIRS =
++TARGETS =
++
++@BIND9_MAKE_RULES@
++
++installdirs:
++	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/pkcs11
++
++install:: installdirs
++	for i in ${HEADERS}; do \
++		${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/pkcs11 ; \
++	done
+diff --git a/lib/isc/include/pkcs11/pkcs11.h b/lib/isc/include/pkcs11/pkcs11.h
+new file mode 100644
+index 0000000..9261e1e
+--- /dev/null
++++ b/lib/isc/include/pkcs11/pkcs11.h
+@@ -0,0 +1,299 @@
++/* pkcs11.h include file for PKCS #11. */
++/* $Revision: 1.2 $ */
++
++/* License to copy and use this software is granted provided that it is
++ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
++ * (Cryptoki)" in all material mentioning or referencing this software.
++
++ * License is also granted to make and use derivative works provided that
++ * such works are identified as "derived from the RSA Security Inc. PKCS #11
++ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or 
++ * referencing the derived work.
++
++ * RSA Security Inc. makes no representations concerning either the 
++ * merchantability of this software or the suitability of this software for
++ * any particular purpose. It is provided "as is" without express or implied
++ * warranty of any kind.
++ */
++
++#ifndef _PKCS11_H_
++#define _PKCS11_H_ 1
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* Before including this file (pkcs11.h) (or pkcs11t.h by
++ * itself), 6 platform-specific macros must be defined.  These
++ * macros are described below, and typical definitions for them
++ * are also given.  Be advised that these definitions can depend
++ * on both the platform and the compiler used (and possibly also
++ * on whether a Cryptoki library is linked statically or
++ * dynamically).
++ *
++ * In addition to defining these 6 macros, the packing convention
++ * for Cryptoki structures should be set.  The Cryptoki
++ * convention on packing is that structures should be 1-byte
++ * aligned.
++ *
++ * If you're using Microsoft Developer Studio 5.0 to produce
++ * Win32 stuff, this might be done by using the following
++ * preprocessor directive before including pkcs11.h or pkcs11t.h:
++ *
++ * #pragma pack(push, cryptoki, 1)
++ *
++ * and using the following preprocessor directive after including
++ * pkcs11.h or pkcs11t.h:
++ *
++ * #pragma pack(pop, cryptoki)
++ *
++ * If you're using an earlier version of Microsoft Developer
++ * Studio to produce Win16 stuff, this might be done by using
++ * the following preprocessor directive before including
++ * pkcs11.h or pkcs11t.h:
++ *
++ * #pragma pack(1)
++ *
++ * In a UNIX environment, you're on your own for this.  You might
++ * not need to do (or be able to do!) anything.
++ *
++ *
++ * Now for the macros:
++ *
++ *
++ * 1. CK_PTR: The indirection string for making a pointer to an
++ * object.  It can be used like this:
++ *
++ * typedef CK_BYTE CK_PTR CK_BYTE_PTR;
++ *
++ * If you're using Microsoft Developer Studio 5.0 to produce
++ * Win32 stuff, it might be defined by:
++ *
++ * #define CK_PTR *
++ *
++ * If you're using an earlier version of Microsoft Developer
++ * Studio to produce Win16 stuff, it might be defined by:
++ *
++ * #define CK_PTR far *
++ *
++ * In a typical UNIX environment, it might be defined by:
++ *
++ * #define CK_PTR *
++ *
++ *
++ * 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes
++ * an exportable Cryptoki library function definition out of a
++ * return type and a function name.  It should be used in the
++ * following fashion to define the exposed Cryptoki functions in
++ * a Cryptoki library:
++ *
++ * CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(
++ *   CK_VOID_PTR pReserved
++ * )
++ * {
++ *   ...
++ * }
++ *
++ * If you're using Microsoft Developer Studio 5.0 to define a
++ * function in a Win32 Cryptoki .dll, it might be defined by:
++ *
++ * #define CK_DEFINE_FUNCTION(returnType, name) \
++ *   returnType __declspec(dllexport) name
++ *
++ * If you're using an earlier version of Microsoft Developer
++ * Studio to define a function in a Win16 Cryptoki .dll, it
++ * might be defined by:
++ *
++ * #define CK_DEFINE_FUNCTION(returnType, name) \
++ *   returnType __export _far _pascal name
++ *
++ * In a UNIX environment, it might be defined by:
++ *
++ * #define CK_DEFINE_FUNCTION(returnType, name) \
++ *   returnType name
++ *
++ *
++ * 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
++ * an importable Cryptoki library function declaration out of a
++ * return type and a function name.  It should be used in the
++ * following fashion:
++ *
++ * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
++ *   CK_VOID_PTR pReserved
++ * );
++ *
++ * If you're using Microsoft Developer Studio 5.0 to declare a
++ * function in a Win32 Cryptoki .dll, it might be defined by:
++ *
++ * #define CK_DECLARE_FUNCTION(returnType, name) \
++ *   returnType __declspec(dllimport) name
++ *
++ * If you're using an earlier version of Microsoft Developer
++ * Studio to declare a function in a Win16 Cryptoki .dll, it
++ * might be defined by:
++ *
++ * #define CK_DECLARE_FUNCTION(returnType, name) \
++ *   returnType __export _far _pascal name
++ *
++ * In a UNIX environment, it might be defined by:
++ *
++ * #define CK_DECLARE_FUNCTION(returnType, name) \
++ *   returnType name
++ *
++ *
++ * 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
++ * which makes a Cryptoki API function pointer declaration or
++ * function pointer type declaration out of a return type and a
++ * function name.  It should be used in the following fashion:
++ *
++ * // Define funcPtr to be a pointer to a Cryptoki API function
++ * // taking arguments args and returning CK_RV.
++ * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
++ *
++ * or
++ *
++ * // Define funcPtrType to be the type of a pointer to a
++ * // Cryptoki API function taking arguments args and returning
++ * // CK_RV, and then define funcPtr to be a variable of type
++ * // funcPtrType.
++ * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
++ * funcPtrType funcPtr;
++ *
++ * If you're using Microsoft Developer Studio 5.0 to access
++ * functions in a Win32 Cryptoki .dll, in might be defined by:
++ *
++ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
++ *   returnType __declspec(dllimport) (* name)
++ *
++ * If you're using an earlier version of Microsoft Developer
++ * Studio to access functions in a Win16 Cryptoki .dll, it might
++ * be defined by:
++ *
++ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
++ *   returnType __export _far _pascal (* name)
++ *
++ * In a UNIX environment, it might be defined by:
++ *
++ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
++ *   returnType (* name)
++ *
++ *
++ * 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
++ * a function pointer type for an application callback out of
++ * a return type for the callback and a name for the callback.
++ * It should be used in the following fashion:
++ *
++ * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
++ *
++ * to declare a function pointer, myCallback, to a callback
++ * which takes arguments args and returns a CK_RV.  It can also
++ * be used like this:
++ *
++ * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
++ * myCallbackType myCallback;
++ *
++ * If you're using Microsoft Developer Studio 5.0 to do Win32
++ * Cryptoki development, it might be defined by:
++ *
++ * #define CK_CALLBACK_FUNCTION(returnType, name) \
++ *   returnType (* name)
++ *
++ * If you're using an earlier version of Microsoft Developer
++ * Studio to do Win16 development, it might be defined by:
++ *
++ * #define CK_CALLBACK_FUNCTION(returnType, name) \
++ *   returnType _far _pascal (* name)
++ *
++ * In a UNIX environment, it might be defined by:
++ *
++ * #define CK_CALLBACK_FUNCTION(returnType, name) \
++ *   returnType (* name)
++ *
++ *
++ * 6. NULL_PTR: This macro is the value of a NULL pointer.
++ *
++ * In any ANSI/ISO C environment (and in many others as well),
++ * this should best be defined by
++ *
++ * #ifndef NULL_PTR
++ * #define NULL_PTR 0
++ * #endif
++ */
++
++
++/* All the various Cryptoki types and #define'd values are in the
++ * file pkcs11t.h. */
++#include "pkcs11t.h"
++
++#define __PASTE(x,y)      x##y
++
++
++/* ==============================================================
++ * Define the "extern" form of all the entry points.
++ * ==============================================================
++ */
++
++#define CK_NEED_ARG_LIST  1
++#define CK_PKCS11_FUNCTION_INFO(name) \
++  extern CK_DECLARE_FUNCTION(CK_RV, name)
++
++/* pkcs11f.h has all the information about the Cryptoki
++ * function prototypes. */
++#include "pkcs11f.h"
++
++#undef CK_NEED_ARG_LIST
++#undef CK_PKCS11_FUNCTION_INFO
++
++
++/* ==============================================================
++ * Define the typedef form of all the entry points.  That is, for
++ * each Cryptoki function C_XXX, define a type CK_C_XXX which is
++ * a pointer to that kind of function.
++ * ==============================================================
++ */
++
++#define CK_NEED_ARG_LIST  1
++#define CK_PKCS11_FUNCTION_INFO(name) \
++  typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
++
++/* pkcs11f.h has all the information about the Cryptoki
++ * function prototypes. */
++#include "pkcs11f.h"
++
++#undef CK_NEED_ARG_LIST
++#undef CK_PKCS11_FUNCTION_INFO
++
++
++/* ==============================================================
++ * Define structed vector of entry points.  A CK_FUNCTION_LIST
++ * contains a CK_VERSION indicating a library's Cryptoki version
++ * and then a whole slew of function pointers to the routines in
++ * the library.  This type was declared, but not defined, in
++ * pkcs11t.h.
++ * ==============================================================
++ */
++
++#define CK_PKCS11_FUNCTION_INFO(name) \
++  __PASTE(CK_,name) name;
++  
++struct CK_FUNCTION_LIST {
++
++  CK_VERSION    version;  /* Cryptoki version */
++
++/* Pile all the function pointers into the CK_FUNCTION_LIST. */
++/* pkcs11f.h has all the information about the Cryptoki
++ * function prototypes. */
++#include "pkcs11f.h"
++
++};
++
++#undef CK_PKCS11_FUNCTION_INFO
++
++
++#undef __PASTE
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif
+diff --git a/lib/isc/include/pkcs11/pkcs11f.h b/lib/isc/include/pkcs11/pkcs11f.h
+new file mode 100644
+index 0000000..dec6315
+--- /dev/null
++++ b/lib/isc/include/pkcs11/pkcs11f.h
+@@ -0,0 +1,912 @@
++/* pkcs11f.h include file for PKCS #11. */
++/* $Revision: 1.2 $ */
++
++/* License to copy and use this software is granted provided that it is
++ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
++ * (Cryptoki)" in all material mentioning or referencing this software.
++
++ * License is also granted to make and use derivative works provided that
++ * such works are identified as "derived from the RSA Security Inc. PKCS #11
++ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or 
++ * referencing the derived work.
++
++ * RSA Security Inc. makes no representations concerning either the 
++ * merchantability of this software or the suitability of this software for
++ * any particular purpose. It is provided "as is" without express or implied
++ * warranty of any kind.
++ */
++
++/* This header file contains pretty much everything about all the */
++/* Cryptoki function prototypes.  Because this information is */
++/* used for more than just declaring function prototypes, the */
++/* order of the functions appearing herein is important, and */
++/* should not be altered. */
++
++/* General-purpose */
++
++/* C_Initialize initializes the Cryptoki library. */
++CK_PKCS11_FUNCTION_INFO(C_Initialize)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_VOID_PTR   pInitArgs  /* if this is not NULL_PTR, it gets
++                            * cast to CK_C_INITIALIZE_ARGS_PTR
++                            * and dereferenced */
++);
++#endif
++
++
++/* C_Finalize indicates that an application is done with the
++ * Cryptoki library. */
++CK_PKCS11_FUNCTION_INFO(C_Finalize)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_VOID_PTR   pReserved  /* reserved.  Should be NULL_PTR */
++);
++#endif
++
++
++/* C_GetInfo returns general information about Cryptoki. */
++CK_PKCS11_FUNCTION_INFO(C_GetInfo)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_INFO_PTR   pInfo  /* location that receives information */
++);
++#endif
++
++
++/* C_GetFunctionList returns the function list. */
++CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_FUNCTION_LIST_PTR_PTR ppFunctionList  /* receives pointer to
++                                            * function list */
++);
++#endif
++
++
++
++/* Slot and token management */
++
++/* C_GetSlotList obtains a list of slots in the system. */
++CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_BBOOL       tokenPresent,  /* only slots with tokens? */
++  CK_SLOT_ID_PTR pSlotList,     /* receives array of slot IDs */
++  CK_ULONG_PTR   pulCount       /* receives number of slots */
++);
++#endif
++
++
++/* C_GetSlotInfo obtains information about a particular slot in
++ * the system. */
++CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SLOT_ID       slotID,  /* the ID of the slot */
++  CK_SLOT_INFO_PTR pInfo    /* receives the slot information */
++);
++#endif
++
++
++/* C_GetTokenInfo obtains information about a particular token
++ * in the system. */
++CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SLOT_ID        slotID,  /* ID of the token's slot */
++  CK_TOKEN_INFO_PTR pInfo    /* receives the token information */
++);
++#endif
++
++
++/* C_GetMechanismList obtains a list of mechanism types
++ * supported by a token. */
++CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SLOT_ID            slotID,          /* ID of token's slot */
++  CK_MECHANISM_TYPE_PTR pMechanismList,  /* gets mech. array */
++  CK_ULONG_PTR          pulCount         /* gets # of mechs. */
++);
++#endif
++
++
++/* C_GetMechanismInfo obtains information about a particular
++ * mechanism possibly supported by a token. */
++CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SLOT_ID            slotID,  /* ID of the token's slot */
++  CK_MECHANISM_TYPE     type,    /* type of mechanism */
++  CK_MECHANISM_INFO_PTR pInfo    /* receives mechanism info */
++);
++#endif
++
++
++/* C_InitToken initializes a token. */
++CK_PKCS11_FUNCTION_INFO(C_InitToken)
++#ifdef CK_NEED_ARG_LIST
++/* pLabel changed from CK_CHAR_PTR to CK_UTF8CHAR_PTR for v2.10 */
++(
++  CK_SLOT_ID      slotID,    /* ID of the token's slot */
++  CK_UTF8CHAR_PTR pPin,      /* the SO's initial PIN */
++  CK_ULONG        ulPinLen,  /* length in bytes of the PIN */
++  CK_UTF8CHAR_PTR pLabel     /* 32-byte token label (blank padded) */
++);
++#endif
++
++
++/* C_InitPIN initializes the normal user's PIN. */
++CK_PKCS11_FUNCTION_INFO(C_InitPIN)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,  /* the session's handle */
++  CK_UTF8CHAR_PTR   pPin,      /* the normal user's PIN */
++  CK_ULONG          ulPinLen   /* length in bytes of the PIN */
++);
++#endif
++
++
++/* C_SetPIN modifies the PIN of the user who is logged in. */
++CK_PKCS11_FUNCTION_INFO(C_SetPIN)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,  /* the session's handle */
++  CK_UTF8CHAR_PTR   pOldPin,   /* the old PIN */
++  CK_ULONG          ulOldLen,  /* length of the old PIN */
++  CK_UTF8CHAR_PTR   pNewPin,   /* the new PIN */
++  CK_ULONG          ulNewLen   /* length of the new PIN */
++);
++#endif
++
++
++
++/* Session management */
++
++/* C_OpenSession opens a session between an application and a
++ * token. */
++CK_PKCS11_FUNCTION_INFO(C_OpenSession)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SLOT_ID            slotID,        /* the slot's ID */
++  CK_FLAGS              flags,         /* from CK_SESSION_INFO */
++  CK_VOID_PTR           pApplication,  /* passed to callback */
++  CK_NOTIFY             Notify,        /* callback function */
++  CK_SESSION_HANDLE_PTR phSession      /* gets session handle */
++);
++#endif
++
++
++/* C_CloseSession closes a session between an application and a
++ * token. */
++CK_PKCS11_FUNCTION_INFO(C_CloseSession)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession  /* the session's handle */
++);
++#endif
++
++
++/* C_CloseAllSessions closes all sessions with a token. */
++CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SLOT_ID     slotID  /* the token's slot */
++);
++#endif
++
++
++/* C_GetSessionInfo obtains information about the session. */
++CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE   hSession,  /* the session's handle */
++  CK_SESSION_INFO_PTR pInfo      /* receives session info */
++);
++#endif
++
++
++/* C_GetOperationState obtains the state of the cryptographic operation
++ * in a session. */
++CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,             /* session's handle */
++  CK_BYTE_PTR       pOperationState,      /* gets state */
++  CK_ULONG_PTR      pulOperationStateLen  /* gets state length */
++);
++#endif
++
++
++/* C_SetOperationState restores the state of the cryptographic
++ * operation in a session. */
++CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,            /* session's handle */
++  CK_BYTE_PTR      pOperationState,      /* holds state */
++  CK_ULONG         ulOperationStateLen,  /* holds state length */
++  CK_OBJECT_HANDLE hEncryptionKey,       /* en/decryption key */
++  CK_OBJECT_HANDLE hAuthenticationKey    /* sign/verify key */
++);
++#endif
++
++
++/* C_Login logs a user into a token. */
++CK_PKCS11_FUNCTION_INFO(C_Login)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,  /* the session's handle */
++  CK_USER_TYPE      userType,  /* the user type */
++  CK_UTF8CHAR_PTR   pPin,      /* the user's PIN */
++  CK_ULONG          ulPinLen   /* the length of the PIN */
++);
++#endif
++
++
++/* C_Logout logs a user out from a token. */
++CK_PKCS11_FUNCTION_INFO(C_Logout)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession  /* the session's handle */
++);
++#endif
++
++
++
++/* Object management */
++
++/* C_CreateObject creates a new object. */
++CK_PKCS11_FUNCTION_INFO(C_CreateObject)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,    /* the session's handle */
++  CK_ATTRIBUTE_PTR  pTemplate,   /* the object's template */
++  CK_ULONG          ulCount,     /* attributes in template */
++  CK_OBJECT_HANDLE_PTR phObject  /* gets new object's handle. */
++);
++#endif
++
++
++/* C_CopyObject copies an object, creating a new object for the
++ * copy. */
++CK_PKCS11_FUNCTION_INFO(C_CopyObject)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE    hSession,    /* the session's handle */
++  CK_OBJECT_HANDLE     hObject,     /* the object's handle */
++  CK_ATTRIBUTE_PTR     pTemplate,   /* template for new object */
++  CK_ULONG             ulCount,     /* attributes in template */
++  CK_OBJECT_HANDLE_PTR phNewObject  /* receives handle of copy */
++);
++#endif
++
++
++/* C_DestroyObject destroys an object. */
++CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,  /* the session's handle */
++  CK_OBJECT_HANDLE  hObject    /* the object's handle */
++);
++#endif
++
++
++/* C_GetObjectSize gets the size of an object in bytes. */
++CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,  /* the session's handle */
++  CK_OBJECT_HANDLE  hObject,   /* the object's handle */
++  CK_ULONG_PTR      pulSize    /* receives size of object */
++);
++#endif
++
++
++/* C_GetAttributeValue obtains the value of one or more object
++ * attributes. */
++CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,   /* the session's handle */
++  CK_OBJECT_HANDLE  hObject,    /* the object's handle */
++  CK_ATTRIBUTE_PTR  pTemplate,  /* specifies attrs; gets vals */
++  CK_ULONG          ulCount     /* attributes in template */
++);
++#endif
++
++
++/* C_SetAttributeValue modifies the value of one or more object
++ * attributes */
++CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,   /* the session's handle */
++  CK_OBJECT_HANDLE  hObject,    /* the object's handle */
++  CK_ATTRIBUTE_PTR  pTemplate,  /* specifies attrs and values */
++  CK_ULONG          ulCount     /* attributes in template */
++);
++#endif
++
++
++/* C_FindObjectsInit initializes a search for token and session
++ * objects that match a template. */
++CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,   /* the session's handle */
++  CK_ATTRIBUTE_PTR  pTemplate,  /* attribute values to match */
++  CK_ULONG          ulCount     /* attrs in search template */
++);
++#endif
++
++
++/* C_FindObjects continues a search for token and session
++ * objects that match a template, obtaining additional object
++ * handles. */
++CK_PKCS11_FUNCTION_INFO(C_FindObjects)
++#ifdef CK_NEED_ARG_LIST
++(
++ CK_SESSION_HANDLE    hSession,          /* session's handle */
++ CK_OBJECT_HANDLE_PTR phObject,          /* gets obj. handles */
++ CK_ULONG             ulMaxObjectCount,  /* max handles to get */
++ CK_ULONG_PTR         pulObjectCount     /* actual # returned */
++);
++#endif
++
++
++/* C_FindObjectsFinal finishes a search for token and session
++ * objects. */
++CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession  /* the session's handle */
++);
++#endif
++
++
++
++/* Encryption and decryption */
++
++/* C_EncryptInit initializes an encryption operation. */
++CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,    /* the session's handle */
++  CK_MECHANISM_PTR  pMechanism,  /* the encryption mechanism */
++  CK_OBJECT_HANDLE  hKey         /* handle of encryption key */
++);
++#endif
++
++
++/* C_Encrypt encrypts single-part data. */
++CK_PKCS11_FUNCTION_INFO(C_Encrypt)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,            /* session's handle */
++  CK_BYTE_PTR       pData,               /* the plaintext data */
++  CK_ULONG          ulDataLen,           /* bytes of plaintext */
++  CK_BYTE_PTR       pEncryptedData,      /* gets ciphertext */
++  CK_ULONG_PTR      pulEncryptedDataLen  /* gets c-text size */
++);
++#endif
++
++
++/* C_EncryptUpdate continues a multiple-part encryption
++ * operation. */
++CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,           /* session's handle */
++  CK_BYTE_PTR       pPart,              /* the plaintext data */
++  CK_ULONG          ulPartLen,          /* plaintext data len */
++  CK_BYTE_PTR       pEncryptedPart,     /* gets ciphertext */
++  CK_ULONG_PTR      pulEncryptedPartLen /* gets c-text size */
++);
++#endif
++
++
++/* C_EncryptFinal finishes a multiple-part encryption
++ * operation. */
++CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,                /* session handle */
++  CK_BYTE_PTR       pLastEncryptedPart,      /* last c-text */
++  CK_ULONG_PTR      pulLastEncryptedPartLen  /* gets last size */
++);
++#endif
++
++
++/* C_DecryptInit initializes a decryption operation. */
++CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,    /* the session's handle */
++  CK_MECHANISM_PTR  pMechanism,  /* the decryption mechanism */
++  CK_OBJECT_HANDLE  hKey         /* handle of decryption key */
++);
++#endif
++
++
++/* C_Decrypt decrypts encrypted data in a single part. */
++CK_PKCS11_FUNCTION_INFO(C_Decrypt)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,           /* session's handle */
++  CK_BYTE_PTR       pEncryptedData,     /* ciphertext */
++  CK_ULONG          ulEncryptedDataLen, /* ciphertext length */
++  CK_BYTE_PTR       pData,              /* gets plaintext */
++  CK_ULONG_PTR      pulDataLen          /* gets p-text size */
++);
++#endif
++
++
++/* C_DecryptUpdate continues a multiple-part decryption
++ * operation. */
++CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,            /* session's handle */
++  CK_BYTE_PTR       pEncryptedPart,      /* encrypted data */
++  CK_ULONG          ulEncryptedPartLen,  /* input length */
++  CK_BYTE_PTR       pPart,               /* gets plaintext */
++  CK_ULONG_PTR      pulPartLen           /* p-text size */
++);
++#endif
++
++
++/* C_DecryptFinal finishes a multiple-part decryption
++ * operation. */
++CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,       /* the session's handle */
++  CK_BYTE_PTR       pLastPart,      /* gets plaintext */
++  CK_ULONG_PTR      pulLastPartLen  /* p-text size */
++);
++#endif
++
++
++
++/* Message digesting */
++
++/* C_DigestInit initializes a message-digesting operation. */
++CK_PKCS11_FUNCTION_INFO(C_DigestInit)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,   /* the session's handle */
++  CK_MECHANISM_PTR  pMechanism  /* the digesting mechanism */
++);
++#endif
++
++
++/* C_Digest digests data in a single part. */
++CK_PKCS11_FUNCTION_INFO(C_Digest)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,     /* the session's handle */
++  CK_BYTE_PTR       pData,        /* data to be digested */
++  CK_ULONG          ulDataLen,    /* bytes of data to digest */
++  CK_BYTE_PTR       pDigest,      /* gets the message digest */
++  CK_ULONG_PTR      pulDigestLen  /* gets digest length */
++);
++#endif
++
++
++/* C_DigestUpdate continues a multiple-part message-digesting
++ * operation. */
++CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,  /* the session's handle */
++  CK_BYTE_PTR       pPart,     /* data to be digested */
++  CK_ULONG          ulPartLen  /* bytes of data to be digested */
++);
++#endif
++
++
++/* C_DigestKey continues a multi-part message-digesting
++ * operation, by digesting the value of a secret key as part of
++ * the data already digested. */
++CK_PKCS11_FUNCTION_INFO(C_DigestKey)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,  /* the session's handle */
++  CK_OBJECT_HANDLE  hKey       /* secret key to digest */
++);
++#endif
++
++
++/* C_DigestFinal finishes a multiple-part message-digesting
++ * operation. */
++CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,     /* the session's handle */
++  CK_BYTE_PTR       pDigest,      /* gets the message digest */
++  CK_ULONG_PTR      pulDigestLen  /* gets byte count of digest */
++);
++#endif
++
++
++
++/* Signing and MACing */
++
++/* C_SignInit initializes a signature (private key encryption)
++ * operation, where the signature is (will be) an appendix to
++ * the data, and plaintext cannot be recovered from the
++ *signature. */
++CK_PKCS11_FUNCTION_INFO(C_SignInit)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,    /* the session's handle */
++  CK_MECHANISM_PTR  pMechanism,  /* the signature mechanism */
++  CK_OBJECT_HANDLE  hKey         /* handle of signature key */
++);
++#endif
++
++
++/* C_Sign signs (encrypts with private key) data in a single
++ * part, where the signature is (will be) an appendix to the
++ * data, and plaintext cannot be recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_Sign)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,        /* the session's handle */
++  CK_BYTE_PTR       pData,           /* the data to sign */
++  CK_ULONG          ulDataLen,       /* count of bytes to sign */
++  CK_BYTE_PTR       pSignature,      /* gets the signature */
++  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
++);
++#endif
++
++
++/* C_SignUpdate continues a multiple-part signature operation,
++ * where the signature is (will be) an appendix to the data, 
++ * and plaintext cannot be recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,  /* the session's handle */
++  CK_BYTE_PTR       pPart,     /* the data to sign */
++  CK_ULONG          ulPartLen  /* count of bytes to sign */
++);
++#endif
++
++
++/* C_SignFinal finishes a multiple-part signature operation, 
++ * returning the signature. */
++CK_PKCS11_FUNCTION_INFO(C_SignFinal)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,        /* the session's handle */
++  CK_BYTE_PTR       pSignature,      /* gets the signature */
++  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
++);
++#endif
++
++
++/* C_SignRecoverInit initializes a signature operation, where
++ * the data can be recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,   /* the session's handle */
++  CK_MECHANISM_PTR  pMechanism, /* the signature mechanism */
++  CK_OBJECT_HANDLE  hKey        /* handle of the signature key */
++);
++#endif
++
++
++/* C_SignRecover signs data in a single operation, where the
++ * data can be recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_SignRecover)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,        /* the session's handle */
++  CK_BYTE_PTR       pData,           /* the data to sign */
++  CK_ULONG          ulDataLen,       /* count of bytes to sign */
++  CK_BYTE_PTR       pSignature,      /* gets the signature */
++  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
++);
++#endif
++
++
++
++/* Verifying signatures and MACs */
++
++/* C_VerifyInit initializes a verification operation, where the
++ * signature is an appendix to the data, and plaintext cannot
++ *  cannot be recovered from the signature (e.g. DSA). */
++CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,    /* the session's handle */
++  CK_MECHANISM_PTR  pMechanism,  /* the verification mechanism */
++  CK_OBJECT_HANDLE  hKey         /* verification key */ 
++);
++#endif
++
++
++/* C_Verify verifies a signature in a single-part operation, 
++ * where the signature is an appendix to the data, and plaintext
++ * cannot be recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_Verify)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,       /* the session's handle */
++  CK_BYTE_PTR       pData,          /* signed data */
++  CK_ULONG          ulDataLen,      /* length of signed data */
++  CK_BYTE_PTR       pSignature,     /* signature */
++  CK_ULONG          ulSignatureLen  /* signature length*/
++);
++#endif
++
++
++/* C_VerifyUpdate continues a multiple-part verification
++ * operation, where the signature is an appendix to the data, 
++ * and plaintext cannot be recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,  /* the session's handle */
++  CK_BYTE_PTR       pPart,     /* signed data */
++  CK_ULONG          ulPartLen  /* length of signed data */
++);
++#endif
++
++
++/* C_VerifyFinal finishes a multiple-part verification
++ * operation, checking the signature. */
++CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,       /* the session's handle */
++  CK_BYTE_PTR       pSignature,     /* signature to verify */
++  CK_ULONG          ulSignatureLen  /* signature length */
++);
++#endif
++
++
++/* C_VerifyRecoverInit initializes a signature verification
++ * operation, where the data is recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,    /* the session's handle */
++  CK_MECHANISM_PTR  pMechanism,  /* the verification mechanism */
++  CK_OBJECT_HANDLE  hKey         /* verification key */
++);
++#endif
++
++
++/* C_VerifyRecover verifies a signature in a single-part
++ * operation, where the data is recovered from the signature. */
++CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,        /* the session's handle */
++  CK_BYTE_PTR       pSignature,      /* signature to verify */
++  CK_ULONG          ulSignatureLen,  /* signature length */
++  CK_BYTE_PTR       pData,           /* gets signed data */
++  CK_ULONG_PTR      pulDataLen       /* gets signed data len */
++);
++#endif
++
++
++
++/* Dual-function cryptographic operations */
++
++/* C_DigestEncryptUpdate continues a multiple-part digesting
++ * and encryption operation. */
++CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,            /* session's handle */
++  CK_BYTE_PTR       pPart,               /* the plaintext data */
++  CK_ULONG          ulPartLen,           /* plaintext length */
++  CK_BYTE_PTR       pEncryptedPart,      /* gets ciphertext */
++  CK_ULONG_PTR      pulEncryptedPartLen  /* gets c-text length */
++);
++#endif
++
++
++/* C_DecryptDigestUpdate continues a multiple-part decryption and
++ * digesting operation. */
++CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,            /* session's handle */
++  CK_BYTE_PTR       pEncryptedPart,      /* ciphertext */
++  CK_ULONG          ulEncryptedPartLen,  /* ciphertext length */
++  CK_BYTE_PTR       pPart,               /* gets plaintext */
++  CK_ULONG_PTR      pulPartLen           /* gets plaintext len */
++);
++#endif
++
++
++/* C_SignEncryptUpdate continues a multiple-part signing and
++ * encryption operation. */
++CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,            /* session's handle */
++  CK_BYTE_PTR       pPart,               /* the plaintext data */
++  CK_ULONG          ulPartLen,           /* plaintext length */
++  CK_BYTE_PTR       pEncryptedPart,      /* gets ciphertext */
++  CK_ULONG_PTR      pulEncryptedPartLen  /* gets c-text length */
++);
++#endif
++
++
++/* C_DecryptVerifyUpdate continues a multiple-part decryption and
++ * verify operation. */
++CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,            /* session's handle */
++  CK_BYTE_PTR       pEncryptedPart,      /* ciphertext */
++  CK_ULONG          ulEncryptedPartLen,  /* ciphertext length */
++  CK_BYTE_PTR       pPart,               /* gets plaintext */
++  CK_ULONG_PTR      pulPartLen           /* gets p-text length */
++);
++#endif
++
++
++
++/* Key management */
++
++/* C_GenerateKey generates a secret key, creating a new key
++ * object. */
++CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE    hSession,    /* the session's handle */
++  CK_MECHANISM_PTR     pMechanism,  /* key generation mech. */
++  CK_ATTRIBUTE_PTR     pTemplate,   /* template for new key */
++  CK_ULONG             ulCount,     /* # of attrs in template */
++  CK_OBJECT_HANDLE_PTR phKey        /* gets handle of new key */
++);
++#endif
++
++
++/* C_GenerateKeyPair generates a public-key/private-key pair, 
++ * creating new key objects. */
++CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE    hSession,                    /* session
++                                                     * handle */
++  CK_MECHANISM_PTR     pMechanism,                  /* key-gen
++                                                     * mech. */
++  CK_ATTRIBUTE_PTR     pPublicKeyTemplate,          /* template
++                                                     * for pub.
++                                                     * key */
++  CK_ULONG             ulPublicKeyAttributeCount,   /* # pub.
++                                                     * attrs. */
++  CK_ATTRIBUTE_PTR     pPrivateKeyTemplate,         /* template
++                                                     * for priv.
++                                                     * key */
++  CK_ULONG             ulPrivateKeyAttributeCount,  /* # priv.
++                                                     * attrs. */
++  CK_OBJECT_HANDLE_PTR phPublicKey,                 /* gets pub.
++                                                     * key
++                                                     * handle */
++  CK_OBJECT_HANDLE_PTR phPrivateKey                 /* gets
++                                                     * priv. key
++                                                     * handle */
++);
++#endif
++
++
++/* C_WrapKey wraps (i.e., encrypts) a key. */
++CK_PKCS11_FUNCTION_INFO(C_WrapKey)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,        /* the session's handle */
++  CK_MECHANISM_PTR  pMechanism,      /* the wrapping mechanism */
++  CK_OBJECT_HANDLE  hWrappingKey,    /* wrapping key */
++  CK_OBJECT_HANDLE  hKey,            /* key to be wrapped */
++  CK_BYTE_PTR       pWrappedKey,     /* gets wrapped key */
++  CK_ULONG_PTR      pulWrappedKeyLen /* gets wrapped key size */
++);
++#endif
++
++
++/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
++ * key object. */
++CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE    hSession,          /* session's handle */
++  CK_MECHANISM_PTR     pMechanism,        /* unwrapping mech. */
++  CK_OBJECT_HANDLE     hUnwrappingKey,    /* unwrapping key */
++  CK_BYTE_PTR          pWrappedKey,       /* the wrapped key */
++  CK_ULONG             ulWrappedKeyLen,   /* wrapped key len */
++  CK_ATTRIBUTE_PTR     pTemplate,         /* new key template */
++  CK_ULONG             ulAttributeCount,  /* template length */
++  CK_OBJECT_HANDLE_PTR phKey              /* gets new handle */
++);
++#endif
++
++
++/* C_DeriveKey derives a key from a base key, creating a new key
++ * object. */
++CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE    hSession,          /* session's handle */
++  CK_MECHANISM_PTR     pMechanism,        /* key deriv. mech. */
++  CK_OBJECT_HANDLE     hBaseKey,          /* base key */
++  CK_ATTRIBUTE_PTR     pTemplate,         /* new key template */
++  CK_ULONG             ulAttributeCount,  /* template length */
++  CK_OBJECT_HANDLE_PTR phKey              /* gets new handle */
++);
++#endif
++
++
++
++/* Random number generation */
++
++/* C_SeedRandom mixes additional seed material into the token's
++ * random number generator. */
++CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,  /* the session's handle */
++  CK_BYTE_PTR       pSeed,     /* the seed material */
++  CK_ULONG          ulSeedLen  /* length of seed material */
++);
++#endif
++
++
++/* C_GenerateRandom generates random data. */
++CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession,    /* the session's handle */
++  CK_BYTE_PTR       RandomData,  /* receives the random data */
++  CK_ULONG          ulRandomLen  /* # of bytes to generate */
++);
++#endif
++
++
++
++/* Parallel function management */
++
++/* C_GetFunctionStatus is a legacy function; it obtains an
++ * updated status of a function running in parallel with an
++ * application. */
++CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession  /* the session's handle */
++);
++#endif
++
++
++/* C_CancelFunction is a legacy function; it cancels a function
++ * running in parallel. */
++CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_SESSION_HANDLE hSession  /* the session's handle */
++);
++#endif
++
++
++
++/* Functions added in for Cryptoki Version 2.01 or later */
++
++/* C_WaitForSlotEvent waits for a slot event (token insertion,
++ * removal, etc.) to occur. */
++CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
++#ifdef CK_NEED_ARG_LIST
++(
++  CK_FLAGS flags,        /* blocking/nonblocking flag */
++  CK_SLOT_ID_PTR pSlot,  /* location that receives the slot ID */
++  CK_VOID_PTR pRserved   /* reserved.  Should be NULL_PTR */
++);
++#endif
+diff --git a/lib/isc/include/pkcs11/pkcs11t.h b/lib/isc/include/pkcs11/pkcs11t.h
+new file mode 100644
+index 0000000..92a80bb
+--- /dev/null
++++ b/lib/isc/include/pkcs11/pkcs11t.h
+@@ -0,0 +1,1977 @@
++/* pkcs11t.h include file for PKCS #11. */
++/* $Revision: 1.2 $ */
++
++/* License to copy and use this software is granted provided that it is
++ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
++ * (Cryptoki)" in all material mentioning or referencing this software.
++
++ * License is also granted to make and use derivative works provided that
++ * such works are identified as "derived from the RSA Security Inc. PKCS #11
++ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
++ * referencing the derived work.
++
++ * RSA Security Inc. makes no representations concerning either the
++ * merchantability of this software or the suitability of this software for
++ * any particular purpose. It is provided "as is" without express or implied
++ * warranty of any kind.
++ */
++
++/* See top of pkcs11.h for information about the macros that
++ * must be defined and the structure-packing conventions that
++ * must be set before including this file. */
++
++#ifndef _PKCS11T_H_
++#define _PKCS11T_H_ 1
++
++#define CRYPTOKI_VERSION_MAJOR 2
++#define CRYPTOKI_VERSION_MINOR 30
++#define CRYPTOKI_VERSION_REVISION 0
++#define CRYPTOKI_VERSION_AMENDMENT 0
++
++#define CK_TRUE 1
++#define CK_FALSE 0
++
++#ifndef CK_DISABLE_TRUE_FALSE
++#ifndef FALSE
++#define FALSE CK_FALSE
++#endif
++
++#ifndef TRUE
++#define TRUE CK_TRUE
++#endif
++#endif
++
++/* an unsigned 8-bit value */
++typedef unsigned char     CK_BYTE;
++
++/* an unsigned 8-bit character */
++typedef CK_BYTE           CK_CHAR;
++
++/* an 8-bit UTF-8 character */
++typedef CK_BYTE           CK_UTF8CHAR;
++
++/* a BYTE-sized Boolean flag */
++typedef CK_BYTE           CK_BBOOL;
++
++/* an unsigned value, at least 32 bits long */
++typedef unsigned long int CK_ULONG;
++
++/* a signed value, the same size as a CK_ULONG */
++/* CK_LONG is new for v2.0 */
++typedef long int          CK_LONG;
++
++/* at least 32 bits; each bit is a Boolean flag */
++typedef CK_ULONG          CK_FLAGS;
++
++
++/* some special values for certain CK_ULONG variables */
++#define CK_UNAVAILABLE_INFORMATION (~0UL)
++#define CK_EFFECTIVELY_INFINITE    0
++
++
++typedef CK_BYTE     CK_PTR   CK_BYTE_PTR;
++typedef CK_CHAR     CK_PTR   CK_CHAR_PTR;
++typedef CK_UTF8CHAR CK_PTR   CK_UTF8CHAR_PTR;
++typedef CK_ULONG    CK_PTR   CK_ULONG_PTR;
++typedef void        CK_PTR   CK_VOID_PTR;
++
++/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */
++typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR;
++
++
++/* The following value is always invalid if used as a session */
++/* handle or object handle */
++#define CK_INVALID_HANDLE 0
++
++
++typedef struct CK_VERSION {
++  CK_BYTE       major;  /* integer portion of version number */
++  CK_BYTE       minor;  /* 1/100ths portion of version number */
++} CK_VERSION;
++
++typedef CK_VERSION CK_PTR CK_VERSION_PTR;
++
++
++typedef struct CK_INFO {
++  /* manufacturerID and libraryDecription have been changed from
++   * CK_CHAR to CK_UTF8CHAR for v2.10 */
++  CK_VERSION    cryptokiVersion;     /* Cryptoki interface ver */
++  CK_UTF8CHAR   manufacturerID[32];  /* blank padded */
++  CK_FLAGS      flags;               /* must be zero */
++
++  /* libraryDescription and libraryVersion are new for v2.0 */
++  CK_UTF8CHAR   libraryDescription[32];  /* blank padded */
++  CK_VERSION    libraryVersion;          /* version of library */
++} CK_INFO;
++
++typedef CK_INFO CK_PTR    CK_INFO_PTR;
++
++
++/* CK_NOTIFICATION enumerates the types of notifications that
++ * Cryptoki provides to an application */
++/* CK_NOTIFICATION has been changed from an enum to a CK_ULONG
++ * for v2.0 */
++typedef CK_ULONG CK_NOTIFICATION;
++#define CKN_SURRENDER       0
++
++/* The following notification is new for PKCS #11 v2.20 amendment 3 */
++#define CKN_OTP_CHANGED     1
++
++
++typedef CK_ULONG          CK_SLOT_ID;
++
++typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR;
++
++
++/* CK_SLOT_INFO provides information about a slot */
++typedef struct CK_SLOT_INFO {
++  /* slotDescription and manufacturerID have been changed from
++   * CK_CHAR to CK_UTF8CHAR for v2.10 */
++  CK_UTF8CHAR   slotDescription[64];  /* blank padded */
++  CK_UTF8CHAR   manufacturerID[32];   /* blank padded */
++  CK_FLAGS      flags;
++
++  /* hardwareVersion and firmwareVersion are new for v2.0 */
++  CK_VERSION    hardwareVersion;  /* version of hardware */
++  CK_VERSION    firmwareVersion;  /* version of firmware */
++} CK_SLOT_INFO;
++
++/* flags: bit flags that provide capabilities of the slot
++ *      Bit Flag              Mask        Meaning
++ */
++#define CKF_TOKEN_PRESENT     0x00000001  /* a token is there */
++#define CKF_REMOVABLE_DEVICE  0x00000002  /* removable devices*/
++#define CKF_HW_SLOT           0x00000004  /* hardware slot */
++
++typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR;
++
++
++/* CK_TOKEN_INFO provides information about a token */
++typedef struct CK_TOKEN_INFO {
++  /* label, manufacturerID, and model have been changed from
++   * CK_CHAR to CK_UTF8CHAR for v2.10 */
++  CK_UTF8CHAR   label[32];           /* blank padded */
++  CK_UTF8CHAR   manufacturerID[32];  /* blank padded */
++  CK_UTF8CHAR   model[16];           /* blank padded */
++  CK_CHAR       serialNumber[16];    /* blank padded */
++  CK_FLAGS      flags;               /* see below */
++
++  /* ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount,
++   * ulRwSessionCount, ulMaxPinLen, and ulMinPinLen have all been
++   * changed from CK_USHORT to CK_ULONG for v2.0 */
++  CK_ULONG      ulMaxSessionCount;     /* max open sessions */
++  CK_ULONG      ulSessionCount;        /* sess. now open */
++  CK_ULONG      ulMaxRwSessionCount;   /* max R/W sessions */
++  CK_ULONG      ulRwSessionCount;      /* R/W sess. now open */
++  CK_ULONG      ulMaxPinLen;           /* in bytes */
++  CK_ULONG      ulMinPinLen;           /* in bytes */
++  CK_ULONG      ulTotalPublicMemory;   /* in bytes */
++  CK_ULONG      ulFreePublicMemory;    /* in bytes */
++  CK_ULONG      ulTotalPrivateMemory;  /* in bytes */
++  CK_ULONG      ulFreePrivateMemory;   /* in bytes */
++
++  /* hardwareVersion, firmwareVersion, and time are new for
++   * v2.0 */
++  CK_VERSION    hardwareVersion;       /* version of hardware */
++  CK_VERSION    firmwareVersion;       /* version of firmware */
++  CK_CHAR       utcTime[16];           /* time */
++} CK_TOKEN_INFO;
++
++/* The flags parameter is defined as follows:
++ *      Bit Flag                    Mask        Meaning
++ */
++#define CKF_RNG                     0x00000001  /* has random #
++                                                 * generator */
++#define CKF_WRITE_PROTECTED         0x00000002  /* token is
++                                                 * write-
++                                                 * protected */
++#define CKF_LOGIN_REQUIRED          0x00000004  /* user must
++                                                 * login */
++#define CKF_USER_PIN_INITIALIZED    0x00000008  /* normal user's
++                                                 * PIN is set */
++
++/* CKF_RESTORE_KEY_NOT_NEEDED is new for v2.0.  If it is set,
++ * that means that *every* time the state of cryptographic
++ * operations of a session is successfully saved, all keys
++ * needed to continue those operations are stored in the state */
++#define CKF_RESTORE_KEY_NOT_NEEDED  0x00000020
++
++/* CKF_CLOCK_ON_TOKEN is new for v2.0.  If it is set, that means
++ * that the token has some sort of clock.  The time on that
++ * clock is returned in the token info structure */
++#define CKF_CLOCK_ON_TOKEN          0x00000040
++
++/* CKF_PROTECTED_AUTHENTICATION_PATH is new for v2.0.  If it is
++ * set, that means that there is some way for the user to login
++ * without sending a PIN through the Cryptoki library itself */
++#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100
++
++/* CKF_DUAL_CRYPTO_OPERATIONS is new for v2.0.  If it is true,
++ * that means that a single session with the token can perform
++ * dual simultaneous cryptographic operations (digest and
++ * encrypt; decrypt and digest; sign and encrypt; and decrypt
++ * and sign) */
++#define CKF_DUAL_CRYPTO_OPERATIONS  0x00000200
++
++/* CKF_TOKEN_INITIALIZED if new for v2.10. If it is true, the
++ * token has been initialized using C_InitializeToken or an
++ * equivalent mechanism outside the scope of PKCS #11.
++ * Calling C_InitializeToken when this flag is set will cause
++ * the token to be reinitialized. */
++#define CKF_TOKEN_INITIALIZED       0x00000400
++
++/* CKF_SECONDARY_AUTHENTICATION if new for v2.10. If it is
++ * true, the token supports secondary authentication for
++ * private key objects. This flag is deprecated in v2.11 and
++   onwards. */
++#define CKF_SECONDARY_AUTHENTICATION  0x00000800
++
++/* CKF_USER_PIN_COUNT_LOW if new for v2.10. If it is true, an
++ * incorrect user login PIN has been entered at least once
++ * since the last successful authentication. */
++#define CKF_USER_PIN_COUNT_LOW       0x00010000
++
++/* CKF_USER_PIN_FINAL_TRY if new for v2.10. If it is true,
++ * supplying an incorrect user PIN will it to become locked. */
++#define CKF_USER_PIN_FINAL_TRY       0x00020000
++
++/* CKF_USER_PIN_LOCKED if new for v2.10. If it is true, the
++ * user PIN has been locked. User login to the token is not
++ * possible. */
++#define CKF_USER_PIN_LOCKED          0x00040000
++
++/* CKF_USER_PIN_TO_BE_CHANGED if new for v2.10. If it is true,
++ * the user PIN value is the default value set by token
++ * initialization or manufacturing, or the PIN has been
++ * expired by the card. */
++#define CKF_USER_PIN_TO_BE_CHANGED   0x00080000
++
++/* CKF_SO_PIN_COUNT_LOW if new for v2.10. If it is true, an
++ * incorrect SO login PIN has been entered at least once since
++ * the last successful authentication. */
++#define CKF_SO_PIN_COUNT_LOW         0x00100000
++
++/* CKF_SO_PIN_FINAL_TRY if new for v2.10. If it is true,
++ * supplying an incorrect SO PIN will it to become locked. */
++#define CKF_SO_PIN_FINAL_TRY         0x00200000
++
++/* CKF_SO_PIN_LOCKED if new for v2.10. If it is true, the SO
++ * PIN has been locked. SO login to the token is not possible.
++ */
++#define CKF_SO_PIN_LOCKED            0x00400000
++
++/* CKF_SO_PIN_TO_BE_CHANGED if new for v2.10. If it is true,
++ * the SO PIN value is the default value set by token
++ * initialization or manufacturing, or the PIN has been
++ * expired by the card. */
++#define CKF_SO_PIN_TO_BE_CHANGED     0x00800000
++
++/* CKF_ERROR_STATE if new for v2.30. If it is true,
++ * the token failed a FIPS 140-2 self-test and
++ * entered an error state. */
++#define CKF_ERROR_STATE              0x01000000
++
++typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR;
++
++
++/* CK_SESSION_HANDLE is a Cryptoki-assigned value that
++ * identifies a session */
++typedef CK_ULONG          CK_SESSION_HANDLE;
++
++typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR;
++
++
++/* CK_USER_TYPE enumerates the types of Cryptoki users */
++/* CK_USER_TYPE has been changed from an enum to a CK_ULONG for
++ * v2.0 */
++typedef CK_ULONG          CK_USER_TYPE;
++/* Security Officer */
++#define CKU_SO    0
++/* Normal user */
++#define CKU_USER  1
++/* Context specific (added in v2.20) */
++#define CKU_CONTEXT_SPECIFIC   2
++
++/* CK_STATE enumerates the session states */
++/* CK_STATE has been changed from an enum to a CK_ULONG for
++ * v2.0 */
++typedef CK_ULONG          CK_STATE;
++#define CKS_RO_PUBLIC_SESSION  0
++#define CKS_RO_USER_FUNCTIONS  1
++#define CKS_RW_PUBLIC_SESSION  2
++#define CKS_RW_USER_FUNCTIONS  3
++#define CKS_RW_SO_FUNCTIONS    4
++
++
++/* CK_SESSION_INFO provides information about a session */
++typedef struct CK_SESSION_INFO {
++  CK_SLOT_ID    slotID;
++  CK_STATE      state;
++  CK_FLAGS      flags;          /* see below */
++
++  /* ulDeviceError was changed from CK_USHORT to CK_ULONG for
++   * v2.0 */
++  CK_ULONG      ulDeviceError;  /* device-dependent error code */
++} CK_SESSION_INFO;
++
++/* The flags are defined in the following table:
++ *      Bit Flag                Mask        Meaning
++ */
++#define CKF_RW_SESSION          0x00000002  /* session is r/w */
++#define CKF_SERIAL_SESSION      0x00000004  /* no parallel */
++
++typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR;
++
++
++/* CK_OBJECT_HANDLE is a token-specific identifier for an
++ * object  */
++typedef CK_ULONG          CK_OBJECT_HANDLE;
++
++typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR;
++
++
++/* CK_OBJECT_CLASS is a value that identifies the classes (or
++ * types) of objects that Cryptoki recognizes.  It is defined
++ * as follows: */
++/* CK_OBJECT_CLASS was changed from CK_USHORT to CK_ULONG for
++ * v2.0 */
++typedef CK_ULONG          CK_OBJECT_CLASS;
++
++/* The following classes of objects are defined: */
++/* CKO_HW_FEATURE is new for v2.10 */
++/* CKO_DOMAIN_PARAMETERS is new for v2.11 */
++/* CKO_MECHANISM is new for v2.20 */
++#define CKO_DATA              0x00000000
++#define CKO_CERTIFICATE       0x00000001
++#define CKO_PUBLIC_KEY        0x00000002
++#define CKO_PRIVATE_KEY       0x00000003
++#define CKO_SECRET_KEY        0x00000004
++#define CKO_HW_FEATURE        0x00000005
++#define CKO_DOMAIN_PARAMETERS 0x00000006
++#define CKO_MECHANISM         0x00000007
++
++/* CKO_OTP_KEY is new for PKCS #11 v2.20 amendment 1 */
++#define CKO_OTP_KEY           0x00000008
++
++#define CKO_VENDOR_DEFINED    0x80000000
++
++typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
++
++/* CK_HW_FEATURE_TYPE is new for v2.10. CK_HW_FEATURE_TYPE is a
++ * value that identifies the hardware feature type of an object
++ * with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */
++typedef CK_ULONG          CK_HW_FEATURE_TYPE;
++
++/* The following hardware feature types are defined */
++/* CKH_USER_INTERFACE is new for v2.20 */
++#define CKH_MONOTONIC_COUNTER  0x00000001
++#define CKH_CLOCK           0x00000002
++#define CKH_USER_INTERFACE  0x00000003
++#define CKH_VENDOR_DEFINED  0x80000000
++
++/* CK_KEY_TYPE is a value that identifies a key type */
++/* CK_KEY_TYPE was changed from CK_USHORT to CK_ULONG for v2.0 */
++typedef CK_ULONG          CK_KEY_TYPE;
++
++/* the following key types are defined: */
++#define CKK_RSA             0x00000000
++#define CKK_DSA             0x00000001
++#define CKK_DH              0x00000002
++
++/* CKK_ECDSA and CKK_KEA are new for v2.0 */
++/* CKK_ECDSA is deprecated in v2.11, CKK_EC is preferred. */
++#define CKK_ECDSA           0x00000003
++#define CKK_EC              0x00000003
++#define CKK_X9_42_DH        0x00000004
++#define CKK_KEA             0x00000005
++
++#define CKK_GENERIC_SECRET  0x00000010
++#define CKK_RC2             0x00000011
++#define CKK_RC4             0x00000012
++#define CKK_DES             0x00000013
++#define CKK_DES2            0x00000014
++#define CKK_DES3            0x00000015
++
++/* all these key types are new for v2.0 */
++#define CKK_CAST            0x00000016
++#define CKK_CAST3           0x00000017
++/* CKK_CAST5 is deprecated in v2.11, CKK_CAST128 is preferred. */
++#define CKK_CAST5           0x00000018
++#define CKK_CAST128         0x00000018
++#define CKK_RC5             0x00000019
++#define CKK_IDEA            0x0000001A
++#define CKK_SKIPJACK        0x0000001B
++#define CKK_BATON           0x0000001C
++#define CKK_JUNIPER         0x0000001D
++#define CKK_CDMF            0x0000001E
++#define CKK_AES             0x0000001F
++
++/* BlowFish and TwoFish are new for v2.20 */
++#define CKK_BLOWFISH        0x00000020
++#define CKK_TWOFISH         0x00000021
++
++/* SecurID, HOTP, and ACTI are new for PKCS #11 v2.20 amendment 1 */
++#define CKK_SECURID         0x00000022
++#define CKK_HOTP            0x00000023
++#define CKK_ACTI            0x00000024
++
++/* Camellia is new for PKCS #11 v2.20 amendment 3 */
++#define CKK_CAMELLIA                   0x00000025
++/* ARIA is new for PKCS #11 v2.20 amendment 3 */
++#define CKK_ARIA                       0x00000026
++
++/* From PKCS #11 v2.20 amendment 4 draft 2 */
++#define CKK_MD5_HMAC        0x00000027
++#define CKK_SHA_1_HMAC      0x00000028
++#define CKK_RIPEMD128_HMAC  0x00000029
++#define CKK_RIPEMD160_HMAC  0x0000002A
++#define CKK_SHA256_HMAC     0x0000002B
++#define CKK_SHA384_HMAC     0x0000002C
++#define CKK_SHA512_HMAC     0x0000002D
++#define CKK_SHA224_HMAC     0x0000002E
++
++/* From PKCS #11 v2.30 */
++#define CKK_SEED            0x0000002F
++#define CKK_GOSTR3410       0x00000030
++#define CKK_GOSTR3411       0x00000031
++#define CKK_GOST28147       0x00000032
++
++#define CKK_VENDOR_DEFINED  0x80000000
++
++
++/* CK_CERTIFICATE_TYPE is a value that identifies a certificate
++ * type */
++/* CK_CERTIFICATE_TYPE was changed from CK_USHORT to CK_ULONG
++ * for v2.0 */
++typedef CK_ULONG          CK_CERTIFICATE_TYPE;
++
++/* The following certificate types are defined: */
++/* CKC_X_509_ATTR_CERT is new for v2.10 */
++/* CKC_WTLS is new for v2.20 */
++#define CKC_X_509           0x00000000
++#define CKC_X_509_ATTR_CERT 0x00000001
++#define CKC_WTLS            0x00000002
++#define CKC_VENDOR_DEFINED  0x80000000
++
++
++/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute
++ * type */
++/* CK_ATTRIBUTE_TYPE was changed from CK_USHORT to CK_ULONG for
++ * v2.0 */
++typedef CK_ULONG          CK_ATTRIBUTE_TYPE;
++
++/* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which
++   consists of an array of values. */
++#define CKF_ARRAY_ATTRIBUTE    0x40000000
++
++/* The following OTP-related defines are new for PKCS #11 v2.20 amendment 1
++   and relates to the CKA_OTP_FORMAT attribute */
++#define CK_OTP_FORMAT_DECIMAL      0
++#define CK_OTP_FORMAT_HEXADECIMAL  1
++#define CK_OTP_FORMAT_ALPHANUMERIC 2
++#define CK_OTP_FORMAT_BINARY       3
++
++/* The following OTP-related defines are new for PKCS #11 v2.20 amendment 1
++   and relates to the CKA_OTP_..._REQUIREMENT attributes */
++#define CK_OTP_PARAM_IGNORED       0
++#define CK_OTP_PARAM_OPTIONAL      1
++#define CK_OTP_PARAM_MANDATORY     2
++
++/* The following attribute types are defined: */
++#define CKA_CLASS              0x00000000
++#define CKA_TOKEN              0x00000001
++#define CKA_PRIVATE            0x00000002
++#define CKA_LABEL              0x00000003
++#define CKA_APPLICATION        0x00000010
++#define CKA_VALUE              0x00000011
++
++/* CKA_OBJECT_ID is new for v2.10 */
++#define CKA_OBJECT_ID          0x00000012
++
++#define CKA_CERTIFICATE_TYPE   0x00000080
++#define CKA_ISSUER             0x00000081
++#define CKA_SERIAL_NUMBER      0x00000082
++
++/* CKA_AC_ISSUER, CKA_OWNER, and CKA_ATTR_TYPES are new
++ * for v2.10 */
++#define CKA_AC_ISSUER          0x00000083
++#define CKA_OWNER              0x00000084
++#define CKA_ATTR_TYPES         0x00000085
++
++/* CKA_TRUSTED is new for v2.11 */
++#define CKA_TRUSTED            0x00000086
++
++/* CKA_CERTIFICATE_CATEGORY ...
++ * CKA_CHECK_VALUE are new for v2.20 */
++#define CKA_CERTIFICATE_CATEGORY        0x00000087
++#define CKA_JAVA_MIDP_SECURITY_DOMAIN   0x00000088
++#define CKA_URL                         0x00000089
++#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY  0x0000008A
++#define CKA_HASH_OF_ISSUER_PUBLIC_KEY   0x0000008B
++/* One from v2.30? */
++#define CKA_NAME_HASH_ALGORITH          0x0000008C
++#define CKA_CHECK_VALUE                 0x00000090
++
++#define CKA_KEY_TYPE           0x00000100
++#define CKA_SUBJECT            0x00000101
++#define CKA_ID                 0x00000102
++#define CKA_SENSITIVE          0x00000103
++#define CKA_ENCRYPT            0x00000104
++#define CKA_DECRYPT            0x00000105
++#define CKA_WRAP               0x00000106
++#define CKA_UNWRAP             0x00000107
++#define CKA_SIGN               0x00000108
++#define CKA_SIGN_RECOVER       0x00000109
++#define CKA_VERIFY             0x0000010A
++#define CKA_VERIFY_RECOVER     0x0000010B
++#define CKA_DERIVE             0x0000010C
++#define CKA_START_DATE         0x00000110
++#define CKA_END_DATE           0x00000111
++#define CKA_MODULUS            0x00000120
++#define CKA_MODULUS_BITS       0x00000121
++#define CKA_PUBLIC_EXPONENT    0x00000122
++#define CKA_PRIVATE_EXPONENT   0x00000123
++#define CKA_PRIME_1            0x00000124
++#define CKA_PRIME_2            0x00000125
++#define CKA_EXPONENT_1         0x00000126
++#define CKA_EXPONENT_2         0x00000127
++#define CKA_COEFFICIENT        0x00000128
++#define CKA_PRIME              0x00000130
++#define CKA_SUBPRIME           0x00000131
++#define CKA_BASE               0x00000132
++
++/* CKA_PRIME_BITS and CKA_SUB_PRIME_BITS are new for v2.11 */
++#define CKA_PRIME_BITS         0x00000133
++#define CKA_SUBPRIME_BITS      0x00000134
++#define CKA_SUB_PRIME_BITS     CKA_SUBPRIME_BITS
++/* (To retain backwards-compatibility) */
++
++#define CKA_VALUE_BITS         0x00000160
++#define CKA_VALUE_LEN          0x00000161
++
++/* CKA_EXTRACTABLE, CKA_LOCAL, CKA_NEVER_EXTRACTABLE,
++ * CKA_ALWAYS_SENSITIVE, CKA_MODIFIABLE, CKA_ECDSA_PARAMS,
++ * and CKA_EC_POINT are new for v2.0 */
++#define CKA_EXTRACTABLE        0x00000162
++#define CKA_LOCAL              0x00000163
++#define CKA_NEVER_EXTRACTABLE  0x00000164
++#define CKA_ALWAYS_SENSITIVE   0x00000165
++
++/* CKA_KEY_GEN_MECHANISM is new for v2.11 */
++#define CKA_KEY_GEN_MECHANISM  0x00000166
++
++#define CKA_MODIFIABLE         0x00000170
++
++/* From v2.30? */
++#define CKA_COPYABLE           0x00000171
++
++/* CKA_ECDSA_PARAMS is deprecated in v2.11,
++ * CKA_EC_PARAMS is preferred. */
++#define CKA_ECDSA_PARAMS       0x00000180
++#define CKA_EC_PARAMS          0x00000180
++
++#define CKA_EC_POINT           0x00000181
++
++/* CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
++ * are new for v2.10. Deprecated in v2.11 and onwards. */
++#define CKA_SECONDARY_AUTH     0x00000200
++#define CKA_AUTH_PIN_FLAGS     0x00000201
++
++/* CKA_ALWAYS_AUTHENTICATE ...
++ * CKA_UNWRAP_TEMPLATE are new for v2.20 */
++#define CKA_ALWAYS_AUTHENTICATE  0x00000202
++
++#define CKA_WRAP_WITH_TRUSTED    0x00000210
++#define CKA_WRAP_TEMPLATE        (CKF_ARRAY_ATTRIBUTE|0x00000211)
++#define CKA_UNWRAP_TEMPLATE      (CKF_ARRAY_ATTRIBUTE|0x00000212)
++
++/* CKA_OTP... atttributes are new for PKCS #11 v2.20 amendment 3. */
++#define CKA_OTP_FORMAT                0x00000220
++#define CKA_OTP_LENGTH                0x00000221
++#define CKA_OTP_TIME_INTERVAL         0x00000222
++#define CKA_OTP_USER_FRIENDLY_MODE    0x00000223
++#define CKA_OTP_CHALLENGE_REQUIREMENT 0x00000224
++#define CKA_OTP_TIME_REQUIREMENT      0x00000225
++#define CKA_OTP_COUNTER_REQUIREMENT   0x00000226
++#define CKA_OTP_PIN_REQUIREMENT       0x00000227
++#define CKA_OTP_COUNTER               0x0000022E
++#define CKA_OTP_TIME                  0x0000022F
++#define CKA_OTP_USER_IDENTIFIER       0x0000022A
++#define CKA_OTP_SERVICE_IDENTIFIER    0x0000022B
++#define CKA_OTP_SERVICE_LOGO          0x0000022C
++#define CKA_OTP_SERVICE_LOGO_TYPE     0x0000022D
++
++/* CKA_GOST... */
++#define CKA_GOSTR3410_PARAMS          0x00000250
++#define CKA_GOSTR3411_PARAMS          0x00000251
++#define CKA_GOST28147_PARAMS          0x00000252
++
++/* CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, and CKA_HAS_RESET
++ * are new for v2.10 */
++#define CKA_HW_FEATURE_TYPE    0x00000300
++#define CKA_RESET_ON_INIT      0x00000301
++#define CKA_HAS_RESET          0x00000302
++
++/* The following attributes are new for v2.20 */
++#define CKA_PIXEL_X                     0x00000400
++#define CKA_PIXEL_Y                     0x00000401
++#define CKA_RESOLUTION                  0x00000402
++#define CKA_CHAR_ROWS                   0x00000403
++#define CKA_CHAR_COLUMNS                0x00000404
++#define CKA_COLOR                       0x00000405
++#define CKA_BITS_PER_PIXEL              0x00000406
++#define CKA_CHAR_SETS                   0x00000480
++#define CKA_ENCODING_METHODS            0x00000481
++#define CKA_MIME_TYPES                  0x00000482
++#define CKA_MECHANISM_TYPE              0x00000500
++#define CKA_REQUIRED_CMS_ATTRIBUTES     0x00000501
++#define CKA_DEFAULT_CMS_ATTRIBUTES      0x00000502
++#define CKA_SUPPORTED_CMS_ATTRIBUTES    0x00000503
++#define CKA_ALLOWED_MECHANISMS          (CKF_ARRAY_ATTRIBUTE|0x00000600)
++/* From v2.30? */
++#define CKA_WRAP_TEMPLATE               (CKF_ARRAY_ATTRIBUTE|0x00000211)
++#define CKA_UNWRAP_TEMPLATE             (CKF_ARRAY_ATTRIBUTE|0x00000212)
++#define CKA_DERIVE_TEMPLATE             (CKF_ARRAY_ATTRIBUTE|0x00000213)
++
++#define CKA_VENDOR_DEFINED     0x80000000
++
++/* CK_ATTRIBUTE is a structure that includes the type, length
++ * and value of an attribute */
++typedef struct CK_ATTRIBUTE {
++  CK_ATTRIBUTE_TYPE type;
++  CK_VOID_PTR       pValue;
++
++  /* ulValueLen went from CK_USHORT to CK_ULONG for v2.0 */
++  CK_ULONG          ulValueLen;  /* in bytes */
++} CK_ATTRIBUTE;
++
++typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR;
++
++
++/* CK_DATE is a structure that defines a date */
++typedef struct CK_DATE{
++  CK_CHAR       year[4];   /* the year ("1900" - "9999") */
++  CK_CHAR       month[2];  /* the month ("01" - "12") */
++  CK_CHAR       day[2];    /* the day   ("01" - "31") */
++} CK_DATE;
++
++
++/* CK_MECHANISM_TYPE is a value that identifies a mechanism
++ * type */
++/* CK_MECHANISM_TYPE was changed from CK_USHORT to CK_ULONG for
++ * v2.0 */
++typedef CK_ULONG          CK_MECHANISM_TYPE;
++
++/* the following mechanism types are defined: */
++#define CKM_RSA_PKCS_KEY_PAIR_GEN      0x00000000
++#define CKM_RSA_PKCS                   0x00000001
++#define CKM_RSA_9796                   0x00000002
++#define CKM_RSA_X_509                  0x00000003
++
++/* CKM_MD2_RSA_PKCS, CKM_MD5_RSA_PKCS, and CKM_SHA1_RSA_PKCS
++ * are new for v2.0.  They are mechanisms which hash and sign */
++#define CKM_MD2_RSA_PKCS               0x00000004
++#define CKM_MD5_RSA_PKCS               0x00000005
++#define CKM_SHA1_RSA_PKCS              0x00000006
++
++/* CKM_RIPEMD128_RSA_PKCS, CKM_RIPEMD160_RSA_PKCS, and
++ * CKM_RSA_PKCS_OAEP are new for v2.10 */
++#define CKM_RIPEMD128_RSA_PKCS         0x00000007
++#define CKM_RIPEMD160_RSA_PKCS         0x00000008
++#define CKM_RSA_PKCS_OAEP              0x00000009
++
++/* CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, CKM_SHA1_RSA_X9_31,
++ * CKM_RSA_PKCS_PSS, and CKM_SHA1_RSA_PKCS_PSS are new for v2.11 */
++#define CKM_RSA_X9_31_KEY_PAIR_GEN     0x0000000A
++#define CKM_RSA_X9_31                  0x0000000B
++#define CKM_SHA1_RSA_X9_31             0x0000000C
++#define CKM_RSA_PKCS_PSS               0x0000000D
++#define CKM_SHA1_RSA_PKCS_PSS          0x0000000E
++
++#define CKM_DSA_KEY_PAIR_GEN           0x00000010
++#define CKM_DSA                        0x00000011
++#define CKM_DSA_SHA1                   0x00000012
++/* Other DSAs */
++#define CKM_DSA_SHA224                 0x00000013
++#define CKM_DSA_SHA256                 0x00000014
++#define CKM_DSA_SHA384                 0x00000015
++#define CKM_DSA_SHA512                 0x00000016
++
++#define CKM_DH_PKCS_KEY_PAIR_GEN       0x00000020
++#define CKM_DH_PKCS_DERIVE             0x00000021
++
++/* CKM_X9_42_DH_KEY_PAIR_GEN, CKM_X9_42_DH_DERIVE,
++ * CKM_X9_42_DH_HYBRID_DERIVE, and CKM_X9_42_MQV_DERIVE are new for
++ * v2.11 */
++#define CKM_X9_42_DH_KEY_PAIR_GEN      0x00000030
++#define CKM_X9_42_DH_DERIVE            0x00000031
++#define CKM_X9_42_DH_HYBRID_DERIVE     0x00000032
++#define CKM_X9_42_MQV_DERIVE           0x00000033
++
++/* CKM_SHA256/384/512 are new for v2.20 */
++#define CKM_SHA256_RSA_PKCS            0x00000040
++#define CKM_SHA384_RSA_PKCS            0x00000041
++#define CKM_SHA512_RSA_PKCS            0x00000042
++#define CKM_SHA256_RSA_PKCS_PSS        0x00000043
++#define CKM_SHA384_RSA_PKCS_PSS        0x00000044
++#define CKM_SHA512_RSA_PKCS_PSS        0x00000045
++
++/* SHA-224 RSA mechanisms are new for PKCS #11 v2.20 amendment 3 */
++#define CKM_SHA224_RSA_PKCS            0x00000046
++#define CKM_SHA224_RSA_PKCS_PSS        0x00000047
++
++#define CKM_RC2_KEY_GEN                0x00000100
++#define CKM_RC2_ECB                    0x00000101
++#define CKM_RC2_CBC                    0x00000102
++#define CKM_RC2_MAC                    0x00000103
++
++/* CKM_RC2_MAC_GENERAL and CKM_RC2_CBC_PAD are new for v2.0 */
++#define CKM_RC2_MAC_GENERAL            0x00000104
++#define CKM_RC2_CBC_PAD                0x00000105
++
++#define CKM_RC4_KEY_GEN                0x00000110
++#define CKM_RC4                        0x00000111
++#define CKM_DES_KEY_GEN                0x00000120
++#define CKM_DES_ECB                    0x00000121
++#define CKM_DES_CBC                    0x00000122
++#define CKM_DES_MAC                    0x00000123
++
++/* CKM_DES_MAC_GENERAL and CKM_DES_CBC_PAD are new for v2.0 */
++#define CKM_DES_MAC_GENERAL            0x00000124
++#define CKM_DES_CBC_PAD                0x00000125
++
++#define CKM_DES2_KEY_GEN               0x00000130
++#define CKM_DES3_KEY_GEN               0x00000131
++#define CKM_DES3_ECB                   0x00000132
++#define CKM_DES3_CBC                   0x00000133
++#define CKM_DES3_MAC                   0x00000134
++
++/* CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_CDMF_KEY_GEN,
++ * CKM_CDMF_ECB, CKM_CDMF_CBC, CKM_CDMF_MAC,
++ * CKM_CDMF_MAC_GENERAL, and CKM_CDMF_CBC_PAD are new for v2.0,
++ * CKM_DES3_CMAC_GENERAL and CKM_DES3_CMAC are from v2.30? */
++#define CKM_DES3_MAC_GENERAL           0x00000135
++#define CKM_DES3_CBC_PAD               0x00000136
++#define CKM_DES3_CMAC_GENERAL          0x00000137
++#define CKM_DES3_CMAC                  0x00000138
++#define CKM_CDMF_KEY_GEN               0x00000140
++#define CKM_CDMF_ECB                   0x00000141
++#define CKM_CDMF_CBC                   0x00000142
++#define CKM_CDMF_MAC                   0x00000143
++#define CKM_CDMF_MAC_GENERAL           0x00000144
++#define CKM_CDMF_CBC_PAD               0x00000145
++
++/* the following four DES mechanisms are new for v2.20 */
++#define CKM_DES_OFB64                  0x00000150
++#define CKM_DES_OFB8                   0x00000151
++#define CKM_DES_CFB64                  0x00000152
++#define CKM_DES_CFB8                   0x00000153
++
++#define CKM_MD2                        0x00000200
++
++/* CKM_MD2_HMAC and CKM_MD2_HMAC_GENERAL are new for v2.0 */
++#define CKM_MD2_HMAC                   0x00000201
++#define CKM_MD2_HMAC_GENERAL           0x00000202
++
++#define CKM_MD5                        0x00000210
++
++/* CKM_MD5_HMAC and CKM_MD5_HMAC_GENERAL are new for v2.0 */
++#define CKM_MD5_HMAC                   0x00000211
++#define CKM_MD5_HMAC_GENERAL           0x00000212
++
++#define CKM_SHA_1                      0x00000220
++
++/* CKM_SHA_1_HMAC and CKM_SHA_1_HMAC_GENERAL are new for v2.0 */
++#define CKM_SHA_1_HMAC                 0x00000221
++#define CKM_SHA_1_HMAC_GENERAL         0x00000222
++
++/* CKM_RIPEMD128, CKM_RIPEMD128_HMAC,
++ * CKM_RIPEMD128_HMAC_GENERAL, CKM_RIPEMD160, CKM_RIPEMD160_HMAC,
++ * and CKM_RIPEMD160_HMAC_GENERAL are new for v2.10 */
++#define CKM_RIPEMD128                  0x00000230
++#define CKM_RIPEMD128_HMAC             0x00000231
++#define CKM_RIPEMD128_HMAC_GENERAL     0x00000232
++#define CKM_RIPEMD160                  0x00000240
++#define CKM_RIPEMD160_HMAC             0x00000241
++#define CKM_RIPEMD160_HMAC_GENERAL     0x00000242
++
++/* CKM_SHA256/384/512 are new for v2.20 */
++#define CKM_SHA256                     0x00000250
++#define CKM_SHA256_HMAC                0x00000251
++#define CKM_SHA256_HMAC_GENERAL        0x00000252
++
++/* SHA-224 is new for PKCS #11 v2.20 amendment 3 */
++#define CKM_SHA224                     0x00000255
++#define CKM_SHA224_HMAC                0x00000256
++#define CKM_SHA224_HMAC_GENERAL        0x00000257
++
++#define CKM_SHA384                     0x00000260
++#define CKM_SHA384_HMAC                0x00000261
++#define CKM_SHA384_HMAC_GENERAL        0x00000262
++#define CKM_SHA512                     0x00000270
++#define CKM_SHA512_HMAC                0x00000271
++#define CKM_SHA512_HMAC_GENERAL        0x00000272
++
++/* SecurID is new for PKCS #11 v2.20 amendment 1 */
++#define CKM_SECURID_KEY_GEN            0x00000280
++#define CKM_SECURID                    0x00000282
++
++/* HOTP is new for PKCS #11 v2.20 amendment 1 */
++#define CKM_HOTP_KEY_GEN    0x00000290
++#define CKM_HOTP            0x00000291
++
++/* ACTI is new for PKCS #11 v2.20 amendment 1 */
++#define CKM_ACTI            0x000002A0
++#define CKM_ACTI_KEY_GEN    0x000002A1
++
++/* All of the following mechanisms are new for v2.0 */
++/* Note that CAST128 and CAST5 are the same algorithm */
++#define CKM_CAST_KEY_GEN               0x00000300
++#define CKM_CAST_ECB                   0x00000301
++#define CKM_CAST_CBC                   0x00000302
++#define CKM_CAST_MAC                   0x00000303
++#define CKM_CAST_MAC_GENERAL           0x00000304
++#define CKM_CAST_CBC_PAD               0x00000305
++#define CKM_CAST3_KEY_GEN              0x00000310
++#define CKM_CAST3_ECB                  0x00000311
++#define CKM_CAST3_CBC                  0x00000312
++#define CKM_CAST3_MAC                  0x00000313
++#define CKM_CAST3_MAC_GENERAL          0x00000314
++#define CKM_CAST3_CBC_PAD              0x00000315
++#define CKM_CAST5_KEY_GEN              0x00000320
++#define CKM_CAST128_KEY_GEN            0x00000320
++#define CKM_CAST5_ECB                  0x00000321
++#define CKM_CAST128_ECB                0x00000321
++#define CKM_CAST5_CBC                  0x00000322
++#define CKM_CAST128_CBC                0x00000322
++#define CKM_CAST5_MAC                  0x00000323
++#define CKM_CAST128_MAC                0x00000323
++#define CKM_CAST5_MAC_GENERAL          0x00000324
++#define CKM_CAST128_MAC_GENERAL        0x00000324
++#define CKM_CAST5_CBC_PAD              0x00000325
++#define CKM_CAST128_CBC_PAD            0x00000325
++#define CKM_RC5_KEY_GEN                0x00000330
++#define CKM_RC5_ECB                    0x00000331
++#define CKM_RC5_CBC                    0x00000332
++#define CKM_RC5_MAC                    0x00000333
++#define CKM_RC5_MAC_GENERAL            0x00000334
++#define CKM_RC5_CBC_PAD                0x00000335
++#define CKM_IDEA_KEY_GEN               0x00000340
++#define CKM_IDEA_ECB                   0x00000341
++#define CKM_IDEA_CBC                   0x00000342
++#define CKM_IDEA_MAC                   0x00000343
++#define CKM_IDEA_MAC_GENERAL           0x00000344
++#define CKM_IDEA_CBC_PAD               0x00000345
++#define CKM_GENERIC_SECRET_KEY_GEN     0x00000350
++#define CKM_CONCATENATE_BASE_AND_KEY   0x00000360
++#define CKM_CONCATENATE_BASE_AND_DATA  0x00000362
++#define CKM_CONCATENATE_DATA_AND_BASE  0x00000363
++#define CKM_XOR_BASE_AND_DATA          0x00000364
++#define CKM_EXTRACT_KEY_FROM_KEY       0x00000365
++#define CKM_SSL3_PRE_MASTER_KEY_GEN    0x00000370
++#define CKM_SSL3_MASTER_KEY_DERIVE     0x00000371
++#define CKM_SSL3_KEY_AND_MAC_DERIVE    0x00000372
++
++/* CKM_SSL3_MASTER_KEY_DERIVE_DH, CKM_TLS_PRE_MASTER_KEY_GEN,
++ * CKM_TLS_MASTER_KEY_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE, and
++ * CKM_TLS_MASTER_KEY_DERIVE_DH are new for v2.11 */
++#define CKM_SSL3_MASTER_KEY_DERIVE_DH  0x00000373
++#define CKM_TLS_PRE_MASTER_KEY_GEN     0x00000374
++#define CKM_TLS_MASTER_KEY_DERIVE      0x00000375
++#define CKM_TLS_KEY_AND_MAC_DERIVE     0x00000376
++#define CKM_TLS_MASTER_KEY_DERIVE_DH   0x00000377
++
++/* CKM_TLS_PRF is new for v2.20 */
++#define CKM_TLS_PRF                    0x00000378
++
++#define CKM_SSL3_MD5_MAC               0x00000380
++#define CKM_SSL3_SHA1_MAC              0x00000381
++#define CKM_MD5_KEY_DERIVATION         0x00000390
++#define CKM_MD2_KEY_DERIVATION         0x00000391
++#define CKM_SHA1_KEY_DERIVATION        0x00000392
++
++/* CKM_SHA256/384/512 are new for v2.20 */
++#define CKM_SHA256_KEY_DERIVATION      0x00000393
++#define CKM_SHA384_KEY_DERIVATION      0x00000394
++#define CKM_SHA512_KEY_DERIVATION      0x00000395
++
++/* SHA-224 key derivation is new for PKCS #11 v2.20 amendment 3 */
++#define CKM_SHA224_KEY_DERIVATION      0x00000396
++
++#define CKM_PBE_MD2_DES_CBC            0x000003A0
++#define CKM_PBE_MD5_DES_CBC            0x000003A1
++#define CKM_PBE_MD5_CAST_CBC           0x000003A2
++#define CKM_PBE_MD5_CAST3_CBC          0x000003A3
++#define CKM_PBE_MD5_CAST5_CBC          0x000003A4
++#define CKM_PBE_MD5_CAST128_CBC        0x000003A4
++#define CKM_PBE_SHA1_CAST5_CBC         0x000003A5
++#define CKM_PBE_SHA1_CAST128_CBC       0x000003A5
++#define CKM_PBE_SHA1_RC4_128           0x000003A6
++#define CKM_PBE_SHA1_RC4_40            0x000003A7
++#define CKM_PBE_SHA1_DES3_EDE_CBC      0x000003A8
++#define CKM_PBE_SHA1_DES2_EDE_CBC      0x000003A9
++#define CKM_PBE_SHA1_RC2_128_CBC       0x000003AA
++#define CKM_PBE_SHA1_RC2_40_CBC        0x000003AB
++
++/* CKM_PKCS5_PBKD2 is new for v2.10 */
++#define CKM_PKCS5_PBKD2                0x000003B0
++
++#define CKM_PBA_SHA1_WITH_SHA1_HMAC    0x000003C0
++
++/* WTLS mechanisms are new for v2.20 */
++#define CKM_WTLS_PRE_MASTER_KEY_GEN         0x000003D0
++#define CKM_WTLS_MASTER_KEY_DERIVE          0x000003D1
++#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC   0x000003D2
++#define CKM_WTLS_PRF                        0x000003D3
++#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE  0x000003D4
++#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE  0x000003D5
++
++#define CKM_KEY_WRAP_LYNKS             0x00000400
++#define CKM_KEY_WRAP_SET_OAEP          0x00000401
++
++/* CKM_CMS_SIG is new for v2.20 */
++#define CKM_CMS_SIG                    0x00000500
++
++/* CKM_KIP mechanisms are new for PKCS #11 v2.20 amendment 2 */
++#define CKM_KIP_DERIVE                 0x00000510
++#define CKM_KIP_WRAP                   0x00000511
++#define CKM_KIP_MAC                    0x00000512
++
++/* Camellia is new for PKCS #11 v2.20 amendment 3 */
++#define CKM_CAMELLIA_KEY_GEN           0x00000550
++#define CKM_CAMELLIA_ECB               0x00000551
++#define CKM_CAMELLIA_CBC               0x00000552
++#define CKM_CAMELLIA_MAC               0x00000553
++#define CKM_CAMELLIA_MAC_GENERAL       0x00000554
++#define CKM_CAMELLIA_CBC_PAD           0x00000555
++#define CKM_CAMELLIA_ECB_ENCRYPT_DATA  0x00000556
++#define CKM_CAMELLIA_CBC_ENCRYPT_DATA  0x00000557
++#define CKM_CAMELLIA_CTR               0x00000558
++
++/* ARIA is new for PKCS #11 v2.20 amendment 3 */
++#define CKM_ARIA_KEY_GEN               0x00000560
++#define CKM_ARIA_ECB                   0x00000561
++#define CKM_ARIA_CBC                   0x00000562
++#define CKM_ARIA_MAC                   0x00000563
++#define CKM_ARIA_MAC_GENERAL           0x00000564
++#define CKM_ARIA_CBC_PAD               0x00000565
++#define CKM_ARIA_ECB_ENCRYPT_DATA      0x00000566
++#define CKM_ARIA_CBC_ENCRYPT_DATA      0x00000567
++
++/* SEED is new from PKCS #11 v2.30? */
++#define CKM_SEED_KEY_GEN               0x00000650
++#define CKM_SEED_ECB                   0x00000651
++#define CKM_SEED_CBC                   0x00000652
++#define CKM_SEED_MAC                   0x00000653
++#define CKM_SEED_MAC_GENERAL           0x00000654
++#define CKM_SEED_CBC_PAD               0x00000655
++#define CKM_SEED_ECB_ENCRYPT_DATA      0x00000656
++#define CKM_SEED_CBC_ENCRYPT_DATA      0x00000657
++
++/* Fortezza mechanisms */
++#define CKM_SKIPJACK_KEY_GEN           0x00001000
++#define CKM_SKIPJACK_ECB64             0x00001001
++#define CKM_SKIPJACK_CBC64             0x00001002
++#define CKM_SKIPJACK_OFB64             0x00001003
++#define CKM_SKIPJACK_CFB64             0x00001004
++#define CKM_SKIPJACK_CFB32             0x00001005
++#define CKM_SKIPJACK_CFB16             0x00001006
++#define CKM_SKIPJACK_CFB8              0x00001007
++#define CKM_SKIPJACK_WRAP              0x00001008
++#define CKM_SKIPJACK_PRIVATE_WRAP      0x00001009
++#define CKM_SKIPJACK_RELAYX            0x0000100a
++#define CKM_KEA_KEY_PAIR_GEN           0x00001010
++#define CKM_KEA_KEY_DERIVE             0x00001011
++#define CKM_FORTEZZA_TIMESTAMP         0x00001020
++#define CKM_BATON_KEY_GEN              0x00001030
++#define CKM_BATON_ECB128               0x00001031
++#define CKM_BATON_ECB96                0x00001032
++#define CKM_BATON_CBC128               0x00001033
++#define CKM_BATON_COUNTER              0x00001034
++#define CKM_BATON_SHUFFLE              0x00001035
++#define CKM_BATON_WRAP                 0x00001036
++
++/* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11,
++ * CKM_EC_KEY_PAIR_GEN is preferred */
++#define CKM_ECDSA_KEY_PAIR_GEN         0x00001040
++#define CKM_EC_KEY_PAIR_GEN            0x00001040
++
++#define CKM_ECDSA                      0x00001041
++#define CKM_ECDSA_SHA1                 0x00001042
++
++/* From v2.30? */
++#define CKM_ECDSA_SHA224               0x00001043
++#define CKM_ECDSA_SHA256               0x00001044
++#define CKM_ECDSA_SHA384               0x00001045
++#define CKM_ECDSA_SHA512               0x00001046
++
++/* CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, and CKM_ECMQV_DERIVE
++ * are new for v2.11 */
++#define CKM_ECDH1_DERIVE               0x00001050
++#define CKM_ECDH1_COFACTOR_DERIVE      0x00001051
++#define CKM_ECMQV_DERIVE               0x00001052
++
++#define CKM_JUNIPER_KEY_GEN            0x00001060
++#define CKM_JUNIPER_ECB128             0x00001061
++#define CKM_JUNIPER_CBC128             0x00001062
++#define CKM_JUNIPER_COUNTER            0x00001063
++#define CKM_JUNIPER_SHUFFLE            0x00001064
++#define CKM_JUNIPER_WRAP               0x00001065
++#define CKM_FASTHASH                   0x00001070
++
++/* CKM_AES_KEY_GEN, CKM_AES_ECB, CKM_AES_CBC, CKM_AES_MAC,
++ * CKM_AES_MAC_GENERAL, CKM_AES_CBC_PAD, CKM_DSA_PARAMETER_GEN,
++ * CKM_DH_PKCS_PARAMETER_GEN, and CKM_X9_42_DH_PARAMETER_GEN are
++ * new for v2.11 */
++#define CKM_AES_KEY_GEN                0x00001080
++#define CKM_AES_ECB                    0x00001081
++#define CKM_AES_CBC                    0x00001082
++#define CKM_AES_MAC                    0x00001083
++#define CKM_AES_MAC_GENERAL            0x00001084
++#define CKM_AES_CBC_PAD                0x00001085
++
++/* AES counter mode is new for PKCS #11 v2.20 amendment 3 */
++#define CKM_AES_CTR                    0x00001086
++
++/* Missing CKM_AES_GCM and co! */
++
++/* BlowFish and TwoFish are new for v2.20 */
++#define CKM_BLOWFISH_KEY_GEN           0x00001090
++#define CKM_BLOWFISH_CBC               0x00001091
++#define CKM_TWOFISH_KEY_GEN            0x00001092
++#define CKM_TWOFISH_CBC                0x00001093
++
++
++/* CKM_xxx_ENCRYPT_DATA mechanisms are new for v2.20 */
++#define CKM_DES_ECB_ENCRYPT_DATA       0x00001100
++#define CKM_DES_CBC_ENCRYPT_DATA       0x00001101
++#define CKM_DES3_ECB_ENCRYPT_DATA      0x00001102
++#define CKM_DES3_CBC_ENCRYPT_DATA      0x00001103
++#define CKM_AES_ECB_ENCRYPT_DATA       0x00001104
++#define CKM_AES_CBC_ENCRYPT_DATA       0x00001105
++
++/* GOST mechanism from v2.30? */
++#define CKM_GOSTR3410_KEY_PAIR_GEN     0x00001200
++#define CKM_GOSTR3410                  0x00001201
++#define CKM_GOSTR3410_WITH_GOSTR3411   0x00001202
++#define CKM_GOSTR3410_KEY_WRAP         0x00001203
++#define CKM_GOSTR3410_DERIVE           0x00001204
++#define CKM_GOSTR3411                  0x00001210
++#define CKM_GOSTR3411_HMAC             0x00001211
++#define CKM_GOST28147_KEY_GEN          0x00001220
++#define CKM_GOST28147_ECB              0x00001221
++#define CKM_GOST28147                  0x00001222
++#define CKM_GOST28147_MAC              0x00001223
++#define CKM_GOST28147_KEY_WRAP         0x00001224
++
++#define CKM_DSA_PARAMETER_GEN          0x00002000
++#define CKM_DH_PKCS_PARAMETER_GEN      0x00002001
++#define CKM_X9_42_DH_PARAMETER_GEN     0x00002002
++
++/* Missing AES_OFB and co, and RSA_PKCS 1_1 */
++
++#define CKM_VENDOR_DEFINED             0x80000000
++
++typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
++
++
++/* CK_MECHANISM is a structure that specifies a particular
++ * mechanism  */
++typedef struct CK_MECHANISM {
++  CK_MECHANISM_TYPE mechanism;
++  CK_VOID_PTR       pParameter;
++
++  /* ulParameterLen was changed from CK_USHORT to CK_ULONG for
++   * v2.0 */
++  CK_ULONG          ulParameterLen;  /* in bytes */
++} CK_MECHANISM;
++
++typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR;
++
++
++/* CK_MECHANISM_INFO provides information about a particular
++ * mechanism */
++typedef struct CK_MECHANISM_INFO {
++    CK_ULONG    ulMinKeySize;
++    CK_ULONG    ulMaxKeySize;
++    CK_FLAGS    flags;
++} CK_MECHANISM_INFO;
++
++/* The flags are defined as follows:
++ *      Bit Flag               Mask        Meaning */
++#define CKF_HW                 0x00000001  /* performed by HW */
++
++/* The flags CKF_ENCRYPT, CKF_DECRYPT, CKF_DIGEST, CKF_SIGN,
++ * CKG_SIGN_RECOVER, CKF_VERIFY, CKF_VERIFY_RECOVER,
++ * CKF_GENERATE, CKF_GENERATE_KEY_PAIR, CKF_WRAP, CKF_UNWRAP,
++ * and CKF_DERIVE are new for v2.0.  They specify whether or not
++ * a mechanism can be used for a particular task */
++#define CKF_ENCRYPT            0x00000100
++#define CKF_DECRYPT            0x00000200
++#define CKF_DIGEST             0x00000400
++#define CKF_SIGN               0x00000800
++#define CKF_SIGN_RECOVER       0x00001000
++#define CKF_VERIFY             0x00002000
++#define CKF_VERIFY_RECOVER     0x00004000
++#define CKF_GENERATE           0x00008000
++#define CKF_GENERATE_KEY_PAIR  0x00010000
++#define CKF_WRAP               0x00020000
++#define CKF_UNWRAP             0x00040000
++#define CKF_DERIVE             0x00080000
++
++/* CKF_EC_F_P, CKF_EC_F_2M, CKF_EC_ECPARAMETERS, CKF_EC_NAMEDCURVE,
++ * CKF_EC_UNCOMPRESS, and CKF_EC_COMPRESS are new for v2.11. They
++ * describe a token's EC capabilities not available in mechanism
++ * information. */
++#define CKF_EC_F_P             0x00100000
++#define CKF_EC_F_2M            0x00200000
++#define CKF_EC_ECPARAMETERS    0x00400000
++#define CKF_EC_NAMEDCURVE      0x00800000
++#define CKF_EC_UNCOMPRESS      0x01000000
++#define CKF_EC_COMPRESS        0x02000000
++
++#define CKF_EXTENSION          0x80000000 /* FALSE for this version */
++
++typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR;
++
++
++/* CK_RV is a value that identifies the return value of a
++ * Cryptoki function */
++/* CK_RV was changed from CK_USHORT to CK_ULONG for v2.0 */
++typedef CK_ULONG          CK_RV;
++
++#define CKR_OK                                0x00000000
++#define CKR_CANCEL                            0x00000001
++#define CKR_HOST_MEMORY                       0x00000002
++#define CKR_SLOT_ID_INVALID                   0x00000003
++
++/* CKR_FLAGS_INVALID was removed for v2.0 */
++
++/* CKR_GENERAL_ERROR and CKR_FUNCTION_FAILED are new for v2.0 */
++#define CKR_GENERAL_ERROR                     0x00000005
++#define CKR_FUNCTION_FAILED                   0x00000006
++
++/* CKR_ARGUMENTS_BAD, CKR_NO_EVENT, CKR_NEED_TO_CREATE_THREADS,
++ * and CKR_CANT_LOCK are new for v2.01 */
++#define CKR_ARGUMENTS_BAD                     0x00000007
++#define CKR_NO_EVENT                          0x00000008
++#define CKR_NEED_TO_CREATE_THREADS            0x00000009
++#define CKR_CANT_LOCK                         0x0000000A
++
++#define CKR_ATTRIBUTE_READ_ONLY               0x00000010
++#define CKR_ATTRIBUTE_SENSITIVE               0x00000011
++#define CKR_ATTRIBUTE_TYPE_INVALID            0x00000012
++#define CKR_ATTRIBUTE_VALUE_INVALID           0x00000013
++/* New CKR_COPY_PROHIBITED in v2.30? */
++#define CKR_COPY_PROHIBITED                   0x0000001A
++#define CKR_DATA_INVALID                      0x00000020
++#define CKR_DATA_LEN_RANGE                    0x00000021
++#define CKR_DEVICE_ERROR                      0x00000030
++#define CKR_DEVICE_MEMORY                     0x00000031
++#define CKR_DEVICE_REMOVED                    0x00000032
++#define CKR_ENCRYPTED_DATA_INVALID            0x00000040
++#define CKR_ENCRYPTED_DATA_LEN_RANGE          0x00000041
++#define CKR_FUNCTION_CANCELED                 0x00000050
++#define CKR_FUNCTION_NOT_PARALLEL             0x00000051
++
++/* CKR_FUNCTION_NOT_SUPPORTED is new for v2.0 */
++#define CKR_FUNCTION_NOT_SUPPORTED            0x00000054
++
++#define CKR_KEY_HANDLE_INVALID                0x00000060
++
++/* CKR_KEY_SENSITIVE was removed for v2.0 */
++
++#define CKR_KEY_SIZE_RANGE                    0x00000062
++#define CKR_KEY_TYPE_INCONSISTENT             0x00000063
++
++/* CKR_KEY_NOT_NEEDED, CKR_KEY_CHANGED, CKR_KEY_NEEDED,
++ * CKR_KEY_INDIGESTIBLE, CKR_KEY_FUNCTION_NOT_PERMITTED,
++ * CKR_KEY_NOT_WRAPPABLE, and CKR_KEY_UNEXTRACTABLE are new for
++ * v2.0 */
++#define CKR_KEY_NOT_NEEDED                    0x00000064
++#define CKR_KEY_CHANGED                       0x00000065
++#define CKR_KEY_NEEDED                        0x00000066
++#define CKR_KEY_INDIGESTIBLE                  0x00000067
++#define CKR_KEY_FUNCTION_NOT_PERMITTED        0x00000068
++#define CKR_KEY_NOT_WRAPPABLE                 0x00000069
++#define CKR_KEY_UNEXTRACTABLE                 0x0000006A
++
++#define CKR_MECHANISM_INVALID                 0x00000070
++#define CKR_MECHANISM_PARAM_INVALID           0x00000071
++
++/* CKR_OBJECT_CLASS_INCONSISTENT and CKR_OBJECT_CLASS_INVALID
++ * were removed for v2.0 */
++#define CKR_OBJECT_HANDLE_INVALID             0x00000082
++#define CKR_OPERATION_ACTIVE                  0x00000090
++#define CKR_OPERATION_NOT_INITIALIZED         0x00000091
++#define CKR_PIN_INCORRECT                     0x000000A0
++#define CKR_PIN_INVALID                       0x000000A1
++#define CKR_PIN_LEN_RANGE                     0x000000A2
++
++/* CKR_PIN_EXPIRED and CKR_PIN_LOCKED are new for v2.0 */
++#define CKR_PIN_EXPIRED                       0x000000A3
++#define CKR_PIN_LOCKED                        0x000000A4
++
++#define CKR_SESSION_CLOSED                    0x000000B0
++#define CKR_SESSION_COUNT                     0x000000B1
++#define CKR_SESSION_HANDLE_INVALID            0x000000B3
++#define CKR_SESSION_PARALLEL_NOT_SUPPORTED    0x000000B4
++#define CKR_SESSION_READ_ONLY                 0x000000B5
++#define CKR_SESSION_EXISTS                    0x000000B6
++
++/* CKR_SESSION_READ_ONLY_EXISTS and
++ * CKR_SESSION_READ_WRITE_SO_EXISTS are new for v2.0 */
++#define CKR_SESSION_READ_ONLY_EXISTS          0x000000B7
++#define CKR_SESSION_READ_WRITE_SO_EXISTS      0x000000B8
++
++#define CKR_SIGNATURE_INVALID                 0x000000C0
++#define CKR_SIGNATURE_LEN_RANGE               0x000000C1
++#define CKR_TEMPLATE_INCOMPLETE               0x000000D0
++#define CKR_TEMPLATE_INCONSISTENT             0x000000D1
++#define CKR_TOKEN_NOT_PRESENT                 0x000000E0
++#define CKR_TOKEN_NOT_RECOGNIZED              0x000000E1
++#define CKR_TOKEN_WRITE_PROTECTED             0x000000E2
++#define CKR_UNWRAPPING_KEY_HANDLE_INVALID     0x000000F0
++#define CKR_UNWRAPPING_KEY_SIZE_RANGE         0x000000F1
++#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT  0x000000F2
++
++/* private extra values */
++#define CKR_LIBRARY_ALREADY_INITIALIZED       0x000000FD
++#define CKR_LIBRARY_FAILED_TO_LOAD            0x000000FE
++#define CKR_SYMBOL_RESOLUTION_FAILED          0x000000FF
++
++#define CKR_USER_ALREADY_LOGGED_IN            0x00000100
++#define CKR_USER_NOT_LOGGED_IN                0x00000101
++#define CKR_USER_PIN_NOT_INITIALIZED          0x00000102
++#define CKR_USER_TYPE_INVALID                 0x00000103
++
++/* CKR_USER_ANOTHER_ALREADY_LOGGED_IN and CKR_USER_TOO_MANY_TYPES
++ * are new to v2.01 */
++#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN    0x00000104
++#define CKR_USER_TOO_MANY_TYPES               0x00000105
++
++#define CKR_WRAPPED_KEY_INVALID               0x00000110
++#define CKR_WRAPPED_KEY_LEN_RANGE             0x00000112
++#define CKR_WRAPPING_KEY_HANDLE_INVALID       0x00000113
++#define CKR_WRAPPING_KEY_SIZE_RANGE           0x00000114
++#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT    0x00000115
++#define CKR_RANDOM_SEED_NOT_SUPPORTED         0x00000120
++
++/* These are new to v2.0 */
++#define CKR_RANDOM_NO_RNG                     0x00000121
++
++/* These are new to v2.11 */
++#define CKR_DOMAIN_PARAMS_INVALID             0x00000130
++
++/* These are new to v2.0 */
++#define CKR_BUFFER_TOO_SMALL                  0x00000150
++#define CKR_SAVED_STATE_INVALID               0x00000160
++#define CKR_INFORMATION_SENSITIVE             0x00000170
++#define CKR_STATE_UNSAVEABLE                  0x00000180
++
++/* These are new to v2.01 */
++#define CKR_CRYPTOKI_NOT_INITIALIZED          0x00000190
++#define CKR_CRYPTOKI_ALREADY_INITIALIZED      0x00000191
++#define CKR_MUTEX_BAD                         0x000001A0
++#define CKR_MUTEX_NOT_LOCKED                  0x000001A1
++
++/* The following return values are new for PKCS #11 v2.20 amendment 3 */
++#define CKR_NEW_PIN_MODE                      0x000001B0
++#define CKR_NEXT_OTP                          0x000001B1
++
++/* New from v2.30? */
++#define CKR_EXCEEDED_MAX_ITERATIONS           0x000001B5
++#define CKR_FIPS_SELF_TEST_FAILED             0x000001B6
++#define CKR_LIBRARY_LOAD_FAILED               0x000001B7
++#define CKR_PIN_TOO_WEAK                      0x000001B8
++#define CKR_PUBLIC_KEY_INVALID                0x000001B9
++
++/* This is new to v2.20 */
++#define CKR_FUNCTION_REJECTED                 0x00000200
++
++#define CKR_VENDOR_DEFINED                    0x80000000
++
++
++/* CK_NOTIFY is an application callback that processes events */
++typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)(
++  CK_SESSION_HANDLE hSession,     /* the session's handle */
++  CK_NOTIFICATION   event,
++  CK_VOID_PTR       pApplication  /* passed to C_OpenSession */
++);
++
++
++/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec
++ * version and pointers of appropriate types to all the
++ * Cryptoki functions */
++/* CK_FUNCTION_LIST is new for v2.0 */
++typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST;
++
++typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR;
++
++typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR;
++
++
++/* CK_CREATEMUTEX is an application callback for creating a
++ * mutex object */
++typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)(
++  CK_VOID_PTR_PTR ppMutex  /* location to receive ptr to mutex */
++);
++
++
++/* CK_DESTROYMUTEX is an application callback for destroying a
++ * mutex object */
++typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)(
++  CK_VOID_PTR pMutex  /* pointer to mutex */
++);
++
++
++/* CK_LOCKMUTEX is an application callback for locking a mutex */
++typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)(
++  CK_VOID_PTR pMutex  /* pointer to mutex */
++);
++
++
++/* CK_UNLOCKMUTEX is an application callback for unlocking a
++ * mutex */
++typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)(
++  CK_VOID_PTR pMutex  /* pointer to mutex */
++);
++
++
++/* CK_C_INITIALIZE_ARGS provides the optional arguments to
++ * C_Initialize */
++typedef struct CK_C_INITIALIZE_ARGS {
++  CK_CREATEMUTEX CreateMutex;
++  CK_DESTROYMUTEX DestroyMutex;
++  CK_LOCKMUTEX LockMutex;
++  CK_UNLOCKMUTEX UnlockMutex;
++  CK_FLAGS flags;
++  CK_VOID_PTR pReserved;
++} CK_C_INITIALIZE_ARGS;
++
++/* flags: bit flags that provide capabilities of the slot
++ *      Bit Flag                           Mask       Meaning
++ */
++#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001
++#define CKF_OS_LOCKING_OK                  0x00000002
++
++typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR;
++
++
++/* additional flags for parameters to functions */
++
++/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */
++#define CKF_DONT_BLOCK     1
++
++/* CK_RSA_PKCS_OAEP_MGF_TYPE is new for v2.10.
++ * CK_RSA_PKCS_OAEP_MGF_TYPE  is used to indicate the Message
++ * Generation Function (MGF) applied to a message block when
++ * formatting a message block for the PKCS #1 OAEP encryption
++ * scheme. */
++typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
++
++typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
++
++/* The following MGFs are defined */
++/* CKG_MGF1_SHA256, CKG_MGF1_SHA384, and CKG_MGF1_SHA512
++ * are new for v2.20 */
++#define CKG_MGF1_SHA1         0x00000001
++#define CKG_MGF1_SHA256       0x00000002
++#define CKG_MGF1_SHA384       0x00000003
++#define CKG_MGF1_SHA512       0x00000004
++/* SHA-224 is new for PKCS #11 v2.20 amendment 3 */
++#define CKG_MGF1_SHA224       0x00000005
++
++/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is new for v2.10.
++ * CK_RSA_PKCS_OAEP_SOURCE_TYPE  is used to indicate the source
++ * of the encoding parameter when formatting a message block
++ * for the PKCS #1 OAEP encryption scheme. */
++typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
++
++typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR;
++
++/* The following encoding parameter sources are defined */
++#define CKZ_DATA_SPECIFIED    0x00000001
++
++/* CK_RSA_PKCS_OAEP_PARAMS is new for v2.10.
++ * CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the
++ * CKM_RSA_PKCS_OAEP mechanism. */
++typedef struct CK_RSA_PKCS_OAEP_PARAMS {
++        CK_MECHANISM_TYPE hashAlg;
++        CK_RSA_PKCS_MGF_TYPE mgf;
++        CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
++        CK_VOID_PTR pSourceData;
++        CK_ULONG ulSourceDataLen;
++} CK_RSA_PKCS_OAEP_PARAMS;
++
++typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR;
++
++/* CK_RSA_PKCS_PSS_PARAMS is new for v2.11.
++ * CK_RSA_PKCS_PSS_PARAMS provides the parameters to the
++ * CKM_RSA_PKCS_PSS mechanism(s). */
++typedef struct CK_RSA_PKCS_PSS_PARAMS {
++        CK_MECHANISM_TYPE    hashAlg;
++        CK_RSA_PKCS_MGF_TYPE mgf;
++        CK_ULONG             sLen;
++} CK_RSA_PKCS_PSS_PARAMS;
++
++typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR;
++
++/* CK_EC_KDF_TYPE is new for v2.11. */
++typedef CK_ULONG CK_EC_KDF_TYPE;
++
++/* The following EC Key Derivation Functions are defined */
++#define CKD_NULL                 0x00000001
++#define CKD_SHA1_KDF             0x00000002
++
++/* CK_ECDH1_DERIVE_PARAMS is new for v2.11.
++ * CK_ECDH1_DERIVE_PARAMS provides the parameters to the
++ * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms,
++ * where each party contributes one key pair.
++ */
++typedef struct CK_ECDH1_DERIVE_PARAMS {
++  CK_EC_KDF_TYPE kdf;
++  CK_ULONG ulSharedDataLen;
++  CK_BYTE_PTR pSharedData;
++  CK_ULONG ulPublicDataLen;
++  CK_BYTE_PTR pPublicData;
++} CK_ECDH1_DERIVE_PARAMS;
++
++typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR;
++
++
++/* CK_ECDH2_DERIVE_PARAMS is new for v2.11.
++ * CK_ECDH2_DERIVE_PARAMS provides the parameters to the
++ * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs. */
++typedef struct CK_ECDH2_DERIVE_PARAMS {
++  CK_EC_KDF_TYPE kdf;
++  CK_ULONG ulSharedDataLen;
++  CK_BYTE_PTR pSharedData;
++  CK_ULONG ulPublicDataLen;
++  CK_BYTE_PTR pPublicData;
++  CK_ULONG ulPrivateDataLen;
++  CK_OBJECT_HANDLE hPrivateData;
++  CK_ULONG ulPublicDataLen2;
++  CK_BYTE_PTR pPublicData2;
++} CK_ECDH2_DERIVE_PARAMS;
++
++typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR;
++
++typedef struct CK_ECMQV_DERIVE_PARAMS {
++  CK_EC_KDF_TYPE kdf;
++  CK_ULONG ulSharedDataLen;
++  CK_BYTE_PTR pSharedData;
++  CK_ULONG ulPublicDataLen;
++  CK_BYTE_PTR pPublicData;
++  CK_ULONG ulPrivateDataLen;
++  CK_OBJECT_HANDLE hPrivateData;
++  CK_ULONG ulPublicDataLen2;
++  CK_BYTE_PTR pPublicData2;
++  CK_OBJECT_HANDLE publicKey;
++} CK_ECMQV_DERIVE_PARAMS;
++
++typedef CK_ECMQV_DERIVE_PARAMS CK_PTR CK_ECMQV_DERIVE_PARAMS_PTR;
++
++/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the
++ * CKM_X9_42_DH_PARAMETER_GEN mechanisms (new for PKCS #11 v2.11) */
++typedef CK_ULONG CK_X9_42_DH_KDF_TYPE;
++typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR;
++
++/* The following X9.42 DH key derivation functions are defined
++   (besides CKD_NULL already defined : */
++#define CKD_SHA1_KDF_ASN1        0x00000003
++#define CKD_SHA1_KDF_CONCATENATE 0x00000004
++
++/* CK_X9_42_DH1_DERIVE_PARAMS is new for v2.11.
++ * CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the
++ * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party
++ * contributes one key pair */
++typedef struct CK_X9_42_DH1_DERIVE_PARAMS {
++  CK_X9_42_DH_KDF_TYPE kdf;
++  CK_ULONG ulOtherInfoLen;
++  CK_BYTE_PTR pOtherInfo;
++  CK_ULONG ulPublicDataLen;
++  CK_BYTE_PTR pPublicData;
++} CK_X9_42_DH1_DERIVE_PARAMS;
++
++typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR;
++
++/* CK_X9_42_DH2_DERIVE_PARAMS is new for v2.11.
++ * CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the
++ * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation
++ * mechanisms, where each party contributes two key pairs */
++typedef struct CK_X9_42_DH2_DERIVE_PARAMS {
++  CK_X9_42_DH_KDF_TYPE kdf;
++  CK_ULONG ulOtherInfoLen;
++  CK_BYTE_PTR pOtherInfo;
++  CK_ULONG ulPublicDataLen;
++  CK_BYTE_PTR pPublicData;
++  CK_ULONG ulPrivateDataLen;
++  CK_OBJECT_HANDLE hPrivateData;
++  CK_ULONG ulPublicDataLen2;
++  CK_BYTE_PTR pPublicData2;
++} CK_X9_42_DH2_DERIVE_PARAMS;
++
++typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR;
++
++typedef struct CK_X9_42_MQV_DERIVE_PARAMS {
++  CK_X9_42_DH_KDF_TYPE kdf;
++  CK_ULONG ulOtherInfoLen;
++  CK_BYTE_PTR pOtherInfo;
++  CK_ULONG ulPublicDataLen;
++  CK_BYTE_PTR pPublicData;
++  CK_ULONG ulPrivateDataLen;
++  CK_OBJECT_HANDLE hPrivateData;
++  CK_ULONG ulPublicDataLen2;
++  CK_BYTE_PTR pPublicData2;
++  CK_OBJECT_HANDLE publicKey;
++} CK_X9_42_MQV_DERIVE_PARAMS;
++
++typedef CK_X9_42_MQV_DERIVE_PARAMS CK_PTR CK_X9_42_MQV_DERIVE_PARAMS_PTR;
++
++/* CK_KEA_DERIVE_PARAMS provides the parameters to the
++ * CKM_KEA_DERIVE mechanism */
++/* CK_KEA_DERIVE_PARAMS is new for v2.0 */
++typedef struct CK_KEA_DERIVE_PARAMS {
++  CK_BBOOL      isSender;
++  CK_ULONG      ulRandomLen;
++  CK_BYTE_PTR   pRandomA;
++  CK_BYTE_PTR   pRandomB;
++  CK_ULONG      ulPublicDataLen;
++  CK_BYTE_PTR   pPublicData;
++} CK_KEA_DERIVE_PARAMS;
++
++typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR;
++
++
++/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and
++ * CKM_RC2_MAC mechanisms.  An instance of CK_RC2_PARAMS just
++ * holds the effective keysize */
++typedef CK_ULONG          CK_RC2_PARAMS;
++
++typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR;
++
++
++/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC
++ * mechanism */
++typedef struct CK_RC2_CBC_PARAMS {
++  /* ulEffectiveBits was changed from CK_USHORT to CK_ULONG for
++   * v2.0 */
++  CK_ULONG      ulEffectiveBits;  /* effective bits (1-1024) */
++
++  CK_BYTE       iv[8];            /* IV for CBC mode */
++} CK_RC2_CBC_PARAMS;
++
++typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR;
++
++
++/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the
++ * CKM_RC2_MAC_GENERAL mechanism */
++/* CK_RC2_MAC_GENERAL_PARAMS is new for v2.0 */
++typedef struct CK_RC2_MAC_GENERAL_PARAMS {
++  CK_ULONG      ulEffectiveBits;  /* effective bits (1-1024) */
++  CK_ULONG      ulMacLength;      /* Length of MAC in bytes */
++} CK_RC2_MAC_GENERAL_PARAMS;
++
++typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \
++  CK_RC2_MAC_GENERAL_PARAMS_PTR;
++
++
++/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and
++ * CKM_RC5_MAC mechanisms */
++/* CK_RC5_PARAMS is new for v2.0 */
++typedef struct CK_RC5_PARAMS {
++  CK_ULONG      ulWordsize;  /* wordsize in bits */
++  CK_ULONG      ulRounds;    /* number of rounds */
++} CK_RC5_PARAMS;
++
++typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR;
++
++
++/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC
++ * mechanism */
++/* CK_RC5_CBC_PARAMS is new for v2.0 */
++typedef struct CK_RC5_CBC_PARAMS {
++  CK_ULONG      ulWordsize;  /* wordsize in bits */
++  CK_ULONG      ulRounds;    /* number of rounds */
++  CK_BYTE_PTR   pIv;         /* pointer to IV */
++  CK_ULONG      ulIvLen;     /* length of IV in bytes */
++} CK_RC5_CBC_PARAMS;
++
++typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR;
++
++
++/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the
++ * CKM_RC5_MAC_GENERAL mechanism */
++/* CK_RC5_MAC_GENERAL_PARAMS is new for v2.0 */
++typedef struct CK_RC5_MAC_GENERAL_PARAMS {
++  CK_ULONG      ulWordsize;   /* wordsize in bits */
++  CK_ULONG      ulRounds;     /* number of rounds */
++  CK_ULONG      ulMacLength;  /* Length of MAC in bytes */
++} CK_RC5_MAC_GENERAL_PARAMS;
++
++typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \
++  CK_RC5_MAC_GENERAL_PARAMS_PTR;
++
++
++/* CK_MAC_GENERAL_PARAMS provides the parameters to most block
++ * ciphers' MAC_GENERAL mechanisms.  Its value is the length of
++ * the MAC */
++/* CK_MAC_GENERAL_PARAMS is new for v2.0 */
++typedef CK_ULONG          CK_MAC_GENERAL_PARAMS;
++
++typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR;
++
++/* CK_DES/AES_ECB/CBC_ENCRYPT_DATA_PARAMS are new for v2.20 */
++typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS {
++  CK_BYTE      iv[8];
++  CK_BYTE_PTR  pData;
++  CK_ULONG     length;
++} CK_DES_CBC_ENCRYPT_DATA_PARAMS;
++
++typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR;
++
++typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
++  CK_BYTE      iv[16];
++  CK_BYTE_PTR  pData;
++  CK_ULONG     length;
++} CK_AES_CBC_ENCRYPT_DATA_PARAMS;
++
++typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR;
++
++/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the
++ * CKM_SKIPJACK_PRIVATE_WRAP mechanism */
++/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS is new for v2.0 */
++typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS {
++  CK_ULONG      ulPasswordLen;
++  CK_BYTE_PTR   pPassword;
++  CK_ULONG      ulPublicDataLen;
++  CK_BYTE_PTR   pPublicData;
++  CK_ULONG      ulPAndGLen;
++  CK_ULONG      ulQLen;
++  CK_ULONG      ulRandomLen;
++  CK_BYTE_PTR   pRandomA;
++  CK_BYTE_PTR   pPrimeP;
++  CK_BYTE_PTR   pBaseG;
++  CK_BYTE_PTR   pSubprimeQ;
++} CK_SKIPJACK_PRIVATE_WRAP_PARAMS;
++
++typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \
++  CK_SKIPJACK_PRIVATE_WRAP_PTR;
++
++
++/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the
++ * CKM_SKIPJACK_RELAYX mechanism */
++/* CK_SKIPJACK_RELAYX_PARAMS is new for v2.0 */
++typedef struct CK_SKIPJACK_RELAYX_PARAMS {
++  CK_ULONG      ulOldWrappedXLen;
++  CK_BYTE_PTR   pOldWrappedX;
++  CK_ULONG      ulOldPasswordLen;
++  CK_BYTE_PTR   pOldPassword;
++  CK_ULONG      ulOldPublicDataLen;
++  CK_BYTE_PTR   pOldPublicData;
++  CK_ULONG      ulOldRandomLen;
++  CK_BYTE_PTR   pOldRandomA;
++  CK_ULONG      ulNewPasswordLen;
++  CK_BYTE_PTR   pNewPassword;
++  CK_ULONG      ulNewPublicDataLen;
++  CK_BYTE_PTR   pNewPublicData;
++  CK_ULONG      ulNewRandomLen;
++  CK_BYTE_PTR   pNewRandomA;
++} CK_SKIPJACK_RELAYX_PARAMS;
++
++typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \
++  CK_SKIPJACK_RELAYX_PARAMS_PTR;
++
++
++typedef struct CK_PBE_PARAMS {
++  CK_BYTE_PTR      pInitVector;
++  CK_UTF8CHAR_PTR  pPassword;
++  CK_ULONG         ulPasswordLen;
++  CK_BYTE_PTR      pSalt;
++  CK_ULONG         ulSaltLen;
++  CK_ULONG         ulIteration;
++} CK_PBE_PARAMS;
++
++typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR;
++
++
++/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the
++ * CKM_KEY_WRAP_SET_OAEP mechanism */
++/* CK_KEY_WRAP_SET_OAEP_PARAMS is new for v2.0 */
++typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS {
++  CK_BYTE       bBC;     /* block contents byte */
++  CK_BYTE_PTR   pX;      /* extra data */
++  CK_ULONG      ulXLen;  /* length of extra data in bytes */
++} CK_KEY_WRAP_SET_OAEP_PARAMS;
++
++typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR \
++  CK_KEY_WRAP_SET_OAEP_PARAMS_PTR;
++
++
++typedef struct CK_SSL3_RANDOM_DATA {
++  CK_BYTE_PTR  pClientRandom;
++  CK_ULONG     ulClientRandomLen;
++  CK_BYTE_PTR  pServerRandom;
++  CK_ULONG     ulServerRandomLen;
++} CK_SSL3_RANDOM_DATA;
++
++
++typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS {
++  CK_SSL3_RANDOM_DATA RandomInfo;
++  CK_VERSION_PTR pVersion;
++} CK_SSL3_MASTER_KEY_DERIVE_PARAMS;
++
++typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \
++  CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR;
++
++
++typedef struct CK_SSL3_KEY_MAT_OUT {
++  CK_OBJECT_HANDLE hClientMacSecret;
++  CK_OBJECT_HANDLE hServerMacSecret;
++  CK_OBJECT_HANDLE hClientKey;
++  CK_OBJECT_HANDLE hServerKey;
++  CK_BYTE_PTR      pIVClient;
++  CK_BYTE_PTR      pIVServer;
++} CK_SSL3_KEY_MAT_OUT;
++
++typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR;
++
++
++typedef struct CK_SSL3_KEY_MAT_PARAMS {
++  CK_ULONG                ulMacSizeInBits;
++  CK_ULONG                ulKeySizeInBits;
++  CK_ULONG                ulIVSizeInBits;
++  CK_BBOOL                bIsExport;
++  CK_SSL3_RANDOM_DATA     RandomInfo;
++  CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
++} CK_SSL3_KEY_MAT_PARAMS;
++
++typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR;
++
++/* CK_TLS_PRF_PARAMS is new for version 2.20 */
++typedef struct CK_TLS_PRF_PARAMS {
++  CK_BYTE_PTR  pSeed;
++  CK_ULONG     ulSeedLen;
++  CK_BYTE_PTR  pLabel;
++  CK_ULONG     ulLabelLen;
++  CK_BYTE_PTR  pOutput;
++  CK_ULONG_PTR pulOutputLen;
++} CK_TLS_PRF_PARAMS;
++
++typedef CK_TLS_PRF_PARAMS CK_PTR CK_TLS_PRF_PARAMS_PTR;
++
++/* WTLS is new for version 2.20 */
++typedef struct CK_WTLS_RANDOM_DATA {
++  CK_BYTE_PTR pClientRandom;
++  CK_ULONG    ulClientRandomLen;
++  CK_BYTE_PTR pServerRandom;
++  CK_ULONG    ulServerRandomLen;
++} CK_WTLS_RANDOM_DATA;
++
++typedef CK_WTLS_RANDOM_DATA CK_PTR CK_WTLS_RANDOM_DATA_PTR;
++
++typedef struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS {
++  CK_MECHANISM_TYPE   DigestMechanism;
++  CK_WTLS_RANDOM_DATA RandomInfo;
++  CK_BYTE_PTR         pVersion;
++} CK_WTLS_MASTER_KEY_DERIVE_PARAMS;
++
++typedef CK_WTLS_MASTER_KEY_DERIVE_PARAMS CK_PTR \
++  CK_WTLS_MASTER_KEY_DERIVE_PARAMS_PTR;
++
++typedef struct CK_WTLS_PRF_PARAMS {
++  CK_MECHANISM_TYPE DigestMechanism;
++  CK_BYTE_PTR       pSeed;
++  CK_ULONG          ulSeedLen;
++  CK_BYTE_PTR       pLabel;
++  CK_ULONG          ulLabelLen;
++  CK_BYTE_PTR       pOutput;
++  CK_ULONG_PTR      pulOutputLen;
++} CK_WTLS_PRF_PARAMS;
++
++typedef CK_WTLS_PRF_PARAMS CK_PTR CK_WTLS_PRF_PARAMS_PTR;
++
++typedef struct CK_WTLS_KEY_MAT_OUT {
++  CK_OBJECT_HANDLE hMacSecret;
++  CK_OBJECT_HANDLE hKey;
++  CK_BYTE_PTR      pIV;
++} CK_WTLS_KEY_MAT_OUT;
++
++typedef CK_WTLS_KEY_MAT_OUT CK_PTR CK_WTLS_KEY_MAT_OUT_PTR;
++
++typedef struct CK_WTLS_KEY_MAT_PARAMS {
++  CK_MECHANISM_TYPE       DigestMechanism;
++  CK_ULONG                ulMacSizeInBits;
++  CK_ULONG                ulKeySizeInBits;
++  CK_ULONG                ulIVSizeInBits;
++  CK_ULONG                ulSequenceNumber;
++  CK_BBOOL                bIsExport;
++  CK_WTLS_RANDOM_DATA     RandomInfo;
++  CK_WTLS_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
++} CK_WTLS_KEY_MAT_PARAMS;
++
++typedef CK_WTLS_KEY_MAT_PARAMS CK_PTR CK_WTLS_KEY_MAT_PARAMS_PTR;
++
++/* CMS is new for version 2.20 */
++typedef struct CK_CMS_SIG_PARAMS {
++  CK_OBJECT_HANDLE      certificateHandle;
++  CK_MECHANISM_PTR      pSigningMechanism;
++  CK_MECHANISM_PTR      pDigestMechanism;
++  CK_UTF8CHAR_PTR       pContentType;
++  CK_BYTE_PTR           pRequestedAttributes;
++  CK_ULONG              ulRequestedAttributesLen;
++  CK_BYTE_PTR           pRequiredAttributes;
++  CK_ULONG              ulRequiredAttributesLen;
++} CK_CMS_SIG_PARAMS;
++
++typedef CK_CMS_SIG_PARAMS CK_PTR CK_CMS_SIG_PARAMS_PTR;
++
++typedef struct CK_KEY_DERIVATION_STRING_DATA {
++  CK_BYTE_PTR pData;
++  CK_ULONG    ulLen;
++} CK_KEY_DERIVATION_STRING_DATA;
++
++typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \
++  CK_KEY_DERIVATION_STRING_DATA_PTR;
++
++
++/* The CK_EXTRACT_PARAMS is used for the
++ * CKM_EXTRACT_KEY_FROM_KEY mechanism.  It specifies which bit
++ * of the base key should be used as the first bit of the
++ * derived key */
++/* CK_EXTRACT_PARAMS is new for v2.0 */
++typedef CK_ULONG CK_EXTRACT_PARAMS;
++
++typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR;
++
++/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is new for v2.10.
++ * CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to
++ * indicate the Pseudo-Random Function (PRF) used to generate
++ * key bits using PKCS #5 PBKDF2. */
++typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE;
++
++typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR;
++
++/* The following PRFs are defined in PKCS #5 v2.0. */
++#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001
++
++
++/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is new for v2.10.
++ * CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the
++ * source of the salt value when deriving a key using PKCS #5
++ * PBKDF2. */
++typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE;
++
++typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR;
++
++/* The following salt value sources are defined in PKCS #5 v2.0. */
++#define CKZ_SALT_SPECIFIED        0x00000001
++
++/* CK_PKCS5_PBKD2_PARAMS is new for v2.10.
++ * CK_PKCS5_PBKD2_PARAMS is a structure that provides the
++ * parameters to the CKM_PKCS5_PBKD2 mechanism. */
++typedef struct CK_PKCS5_PBKD2_PARAMS {
++        CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE           saltSource;
++        CK_VOID_PTR                                pSaltSourceData;
++        CK_ULONG                                   ulSaltSourceDataLen;
++        CK_ULONG                                   iterations;
++        CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
++        CK_VOID_PTR                                pPrfData;
++        CK_ULONG                                   ulPrfDataLen;
++        CK_UTF8CHAR_PTR                            pPassword;
++        CK_ULONG_PTR                               ulPasswordLen;
++} CK_PKCS5_PBKD2_PARAMS;
++
++typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR;
++
++/* All CK_OTP structs are new for PKCS #11 v2.20 amendment 3 */
++
++typedef CK_ULONG CK_OTP_PARAM_TYPE;
++typedef CK_OTP_PARAM_TYPE CK_PARAM_TYPE; /* B/w compatibility */
++
++typedef struct CK_OTP_PARAM {
++    CK_OTP_PARAM_TYPE type;
++    CK_VOID_PTR pValue;
++    CK_ULONG ulValueLen;
++} CK_OTP_PARAM;
++
++typedef CK_OTP_PARAM CK_PTR CK_OTP_PARAM_PTR;
++
++typedef struct CK_OTP_PARAMS {
++    CK_OTP_PARAM_PTR pParams;
++    CK_ULONG ulCount;
++} CK_OTP_PARAMS;
++
++typedef CK_OTP_PARAMS CK_PTR CK_OTP_PARAMS_PTR;
++
++typedef struct CK_OTP_SIGNATURE_INFO {
++    CK_OTP_PARAM_PTR pParams;
++    CK_ULONG ulCount;
++} CK_OTP_SIGNATURE_INFO;
++
++typedef CK_OTP_SIGNATURE_INFO CK_PTR CK_OTP_SIGNATURE_INFO_PTR;
++
++/* The following OTP-related defines are new for PKCS #11 v2.20 amendment 1 */
++#define CK_OTP_VALUE          0
++#define CK_OTP_PIN            1
++#define CK_OTP_CHALLENGE      2
++#define CK_OTP_TIME           3
++#define CK_OTP_COUNTER        4
++#define CK_OTP_FLAGS          5
++#define CK_OTP_OUTPUT_LENGTH  6
++#define CK_OTP_OUTPUT_FORMAT  7
++
++/* The following OTP-related defines are new for PKCS #11 v2.20 amendment 1 */
++#define CKF_NEXT_OTP          0x00000001
++#define CKF_EXCLUDE_TIME      0x00000002
++#define CKF_EXCLUDE_COUNTER   0x00000004
++#define CKF_EXCLUDE_CHALLENGE 0x00000008
++#define CKF_EXCLUDE_PIN       0x00000010
++#define CKF_USER_FRIENDLY_OTP 0x00000020
++
++/* CK_KIP_PARAMS is new for PKCS #11 v2.20 amendment 2 */
++typedef struct CK_KIP_PARAMS {
++    CK_MECHANISM_PTR  pMechanism;
++    CK_OBJECT_HANDLE  hKey;
++    CK_BYTE_PTR       pSeed;
++    CK_ULONG          ulSeedLen;
++} CK_KIP_PARAMS;
++
++typedef CK_KIP_PARAMS CK_PTR CK_KIP_PARAMS_PTR;
++
++/* CK_AES_CTR_PARAMS is new for PKCS #11 v2.20 amendment 3 */
++typedef struct CK_AES_CTR_PARAMS {
++    CK_ULONG ulCounterBits;
++    CK_BYTE cb[16];
++} CK_AES_CTR_PARAMS;
++
++typedef CK_AES_CTR_PARAMS CK_PTR CK_AES_CTR_PARAMS_PTR;
++
++/* CK_CAMELLIA_CTR_PARAMS is new for PKCS #11 v2.20 amendment 3 */
++typedef struct CK_CAMELLIA_CTR_PARAMS {
++    CK_ULONG ulCounterBits;
++    CK_BYTE cb[16];
++} CK_CAMELLIA_CTR_PARAMS;
++
++typedef CK_CAMELLIA_CTR_PARAMS CK_PTR CK_CAMELLIA_CTR_PARAMS_PTR;
++
++/* CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS is new for PKCS #11 v2.20 amendment 3 */
++typedef struct CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS {
++    CK_BYTE      iv[16];
++    CK_BYTE_PTR  pData;
++    CK_ULONG     length;
++} CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS;
++
++typedef CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS_PTR;
++
++/* CK_ARIA_CBC_ENCRYPT_DATA_PARAMS is new for PKCS #11 v2.20 amendment 3 */
++typedef struct CK_ARIA_CBC_ENCRYPT_DATA_PARAMS {
++    CK_BYTE      iv[16];
++    CK_BYTE_PTR  pData;
++    CK_ULONG     length;
++} CK_ARIA_CBC_ENCRYPT_DATA_PARAMS;
++
++typedef CK_ARIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_ARIA_CBC_ENCRYPT_DATA_PARAMS_PTR;
++
++#endif
+diff --git a/lib/isc/md5.c b/lib/isc/md5.c
+index 7c6419b..2e3cf9a 100644
+--- a/lib/isc/md5.c
++++ b/lib/isc/md5.c
+@@ -41,6 +41,12 @@
+ #include <isc/platform.h>
+ #include <isc/string.h>
+ #include <isc/types.h>
++
++#if PKCS11CRYPTO
++#include <pk11/internal.h>
++#include <pk11/pk11.h>
++#endif
++
+ #include <isc/util.h>
+ 
+ #ifdef ISC_PLATFORM_OPENSSLHASH
+@@ -65,6 +71,50 @@ isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
+ 	EVP_DigestFinal(ctx, digest, NULL);
+ }
+ 
++#elif PKCS11CRYPTO
++
++void
++isc_md5_init(isc_md5_t *ctx) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_MD5, NULL, 0 };
++
++	RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
++				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
++	PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
++}
++
++void
++isc_md5_invalidate(isc_md5_t *ctx) {
++	CK_BYTE garbage[ISC_MD5_DIGESTLENGTH];
++	CK_ULONG len = ISC_MD5_DIGESTLENGTH;
++
++	if (ctx->handle == NULL)
++		return;
++	(void) pkcs_C_DigestFinal(ctx->session, garbage, &len);
++	memset(garbage, 0, sizeof(garbage));
++	pk11_return_session(ctx);
++}
++
++void
++isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len) {
++	CK_RV rv;
++	CK_BYTE_PTR pPart;
++
++	DE_CONST(buf, pPart);
++	PK11_FATALCHECK(pkcs_C_DigestUpdate,
++			(ctx->session, pPart, (CK_ULONG) len));
++}
++
++void
++isc_md5_final(isc_md5_t *ctx, unsigned char *digest) {
++	CK_RV rv;
++	CK_ULONG len = ISC_MD5_DIGESTLENGTH;
++
++	PK11_FATALCHECK(pkcs_C_DigestFinal,
++			(ctx->session, (CK_BYTE_PTR) digest, &len));
++	pk11_return_session(ctx);
++}
++
+ #else
+ 
+ static void
+diff --git a/lib/isc/pk11.c b/lib/isc/pk11.c
+new file mode 100644
+index 0000000..015bff2
+--- /dev/null
++++ b/lib/isc/pk11.c
+@@ -0,0 +1,1327 @@
++/*
++ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * Portions copyright (c) 2008 Nominet UK.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
++ * Use is subject to license terms.
++ */
++
++/*
++ * This product includes software developed by the OpenSSL Project for
++ * use in the OpenSSL Toolkit (http://www.openssl.org/).
++ *
++ * This project also referenced hw_pkcs11-0.9.7b.patch written by
++ * Afchine Madjlessi.
++ */
++/*
++ * ====================================================================
++ * Copyright (c) 2000-2001 The OpenSSL Project.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ *
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in
++ *    the documentation and/or other materials provided with the
++ *    distribution.
++ *
++ * 3. All advertising materials mentioning features or use of this
++ *    software must display the following acknowledgment:
++ *    "This product includes software developed by the OpenSSL Project
++ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
++ *
++ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
++ *    endorse or promote products derived from this software without
++ *    prior written permission. For written permission, please contact
++ *    licensing@OpenSSL.org.
++ *
++ * 5. Products derived from this software may not be called "OpenSSL"
++ *    nor may "OpenSSL" appear in their names without prior written
++ *    permission of the OpenSSL Project.
++ *
++ * 6. Redistributions of any form whatsoever must retain the following
++ *    acknowledgment:
++ *    "This product includes software developed by the OpenSSL Project
++ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
++ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
++ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
++ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
++ * OF THE POSSIBILITY OF SUCH DAMAGE.
++ * ====================================================================
++ *
++ * This product includes cryptographic software written by Eric Young
++ * (eay@cryptsoft.com).  This product includes software written by Tim
++ * Hudson (tjh@cryptsoft.com).
++ *
++ */
++
++/* $Id$ */
++
++#include <config.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++#include <isc/log.h>
++#include <isc/mem.h>
++#include <isc/once.h>
++#include <isc/platform.h>
++#include <isc/stdio.h>
++#include <isc/thread.h>
++#include <isc/util.h>
++
++#include <dst/result.h>
++
++#include <pk11/pk11.h>
++#include <pk11/internal.h>
++#include <pk11/result.h>
++
++#include <pkcs11/cryptoki.h>
++#include <pkcs11/pkcs11.h>
++
++#define PINLEN	32
++
++#ifndef PK11_NO_LOGERR
++#define PK11_NO_LOGERR 1
++#endif
++
++static isc_once_t once = ISC_ONCE_INIT;
++static isc_mem_t *pk11_mctx = NULL;
++static isc_int32_t allocsize = 0;
++static isc_boolean_t initialized = ISC_FALSE;
++
++typedef struct pk11_session pk11_session_t;
++typedef struct pk11_token pk11_token_t;
++typedef ISC_LIST(pk11_session_t) pk11_sessionlist_t;
++
++struct pk11_session {
++	unsigned int		magic;
++	CK_SESSION_HANDLE	session;
++	ISC_LINK(pk11_session_t) link;
++	pk11_token_t		*token;
++};
++
++struct pk11_token {
++	unsigned int		magic;
++	unsigned int		operations;
++	ISC_LINK(pk11_token_t)	link;
++	CK_SLOT_ID		slotid;
++	pk11_sessionlist_t	sessions;
++	isc_boolean_t		logged;
++	char			name[32];
++	char			manuf[32];
++	char			model[16];
++	char			serial[16];
++	char			pin[PINLEN];
++};
++static ISC_LIST(pk11_token_t) tokens;
++
++static pk11_token_t *rand_token;
++static pk11_token_t *best_rsa_token;
++static pk11_token_t *best_dsa_token;
++static pk11_token_t *best_dh_token;
++static pk11_token_t *digest_token;
++static pk11_token_t *best_ec_token;
++static pk11_token_t *best_gost_token;
++static pk11_token_t *aes_token;
++
++static isc_result_t free_all_sessions(void);
++static isc_result_t free_session_list(pk11_sessionlist_t *slist);
++static isc_result_t setup_session(pk11_session_t *sp,
++				  pk11_token_t *token,
++				  isc_boolean_t rw);
++static void choose_slots(void);
++static isc_result_t token_login(pk11_session_t *sp);
++static char *percent_decode(char *x, size_t *len);
++static isc_boolean_t pk11strcmp(const char *x, size_t lenx,
++				const char *y, size_t leny);
++static CK_ATTRIBUTE *push_attribute(pk11_object_t *obj,
++				    isc_mem_t *mctx,
++				    size_t len);
++
++static isc_mutex_t alloclock;
++static isc_mutex_t sessionlock;
++
++static pk11_sessionlist_t actives;
++
++static CK_C_INITIALIZE_ARGS pk11_init_args = {
++	NULL_PTR,               /* CreateMutex */
++	NULL_PTR,               /* DestroyMutex */
++	NULL_PTR,               /* LockMutex */
++	NULL_PTR,               /* UnlockMutex */
++	CKF_OS_LOCKING_OK,      /* flags */
++	NULL_PTR,               /* pReserved */
++};
++
++#ifndef PK11_LIB_LOCATION
++#define PK11_LIB_LOCATION	"unknown_provider"
++#endif
++
++#ifndef WIN32
++static const char *lib_name = PK11_LIB_LOCATION;
++#else
++static const char *lib_name = PK11_LIB_LOCATION ".dll";
++#endif
++
++void
++pk11_set_lib_name(const char *name) {
++	lib_name = name;
++}
++
++const char *
++pk11_get_lib_name(void) {
++	return (lib_name);
++}
++
++static void
++initialize(void) {
++	char *pk11_provider;
++
++	RUNTIME_CHECK(isc_mutex_init(&alloclock) == ISC_R_SUCCESS);
++	RUNTIME_CHECK(isc_mutex_init(&sessionlock) == ISC_R_SUCCESS);
++
++	pk11_provider = getenv("PKCS11_PROVIDER");
++	if (pk11_provider != NULL)
++		lib_name = pk11_provider;
++}
++
++void *
++pk11_mem_get(size_t size) {
++	void *ptr;
++
++	LOCK(&alloclock);
++	if (pk11_mctx != NULL)
++		ptr = isc_mem_get(pk11_mctx, size);
++	else {
++		ptr = malloc(size);
++		if (ptr != NULL)
++			allocsize += (int)size;
++	}
++	UNLOCK(&alloclock);
++
++	if (ptr != NULL)
++		memset(ptr, 0, size);
++	return (ptr);
++}
++
++void
++pk11_mem_put(void *ptr, size_t size) {
++	if (ptr != NULL)
++		memset(ptr, 0, size);
++	LOCK(&alloclock);
++	if (pk11_mctx != NULL)
++		isc_mem_put(pk11_mctx, ptr, size);
++	else {
++		if (ptr != NULL)
++			allocsize -= (int)size;
++		free(ptr);
++	}
++	UNLOCK(&alloclock);
++}
++
++isc_result_t
++pk11_initialize(isc_mem_t *mctx, const char *engine) {
++	isc_result_t result;
++	CK_RV rv;
++
++	RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
++
++	LOCK(&alloclock);
++	if ((mctx != NULL) && (pk11_mctx == NULL) && (allocsize == 0))
++		isc_mem_attach(mctx, &pk11_mctx);
++	if (initialized) {
++		UNLOCK(&alloclock);
++		return (ISC_R_SUCCESS);
++	} else {
++		LOCK(&sessionlock);
++		initialized = ISC_TRUE;
++		UNLOCK(&alloclock);
++	}
++
++	ISC_LIST_INIT(tokens);
++	ISC_LIST_INIT(actives);
++
++	if (engine != NULL)
++		lib_name = engine;
++
++	/* Initialize the CRYPTOKI library */
++	rv = pkcs_C_Initialize((CK_VOID_PTR) &pk11_init_args);
++
++	if (rv == 0xfe) {
++		result = PK11_R_NOPROVIDER;
++		goto unlock;
++	}
++	if (rv != CKR_OK) {
++		result = PK11_R_INITFAILED;
++		goto unlock;
++	}
++
++	choose_slots();
++#ifdef PKCS11CRYPTO
++	if (rand_token == NULL) {
++		result = PK11_R_NORANDOMSERVICE;
++		goto unlock;
++	}
++	if (digest_token == NULL) {
++		result = PK11_R_NODIGESTSERVICE;
++		goto unlock;
++	}
++#if defined(ISC_PLATFORM_USESIT) && defined(AES_SIT)
++	if (aes_token == NULL) {
++		result = PK11_R_NOAESSERVICE;
++		goto unlock;
++	}
++#endif
++#endif /* PKCS11CRYPTO */
++	result = ISC_R_SUCCESS;
++ unlock:
++	UNLOCK(&sessionlock);
++	return (result);
++}
++
++isc_result_t
++pk11_finalize(void) {
++	pk11_token_t *token, *next;
++	isc_result_t ret;
++
++	ret = free_all_sessions();
++	(void) pkcs_C_Finalize(NULL_PTR);
++	token = ISC_LIST_HEAD(tokens);
++	while (token != NULL) {
++		next = ISC_LIST_NEXT(token, link);
++		ISC_LIST_UNLINK(tokens, token, link);
++		if (token == rand_token)
++			rand_token = NULL;
++		if (token == best_rsa_token)
++			best_rsa_token = NULL;
++		if (token == best_dsa_token)
++			best_dsa_token = NULL;
++		if (token == best_dh_token)
++			best_dh_token = NULL;
++		if (token == digest_token)
++			digest_token = NULL;
++		if (token == best_ec_token)
++			best_ec_token = NULL;
++		if (token == best_gost_token)
++			best_gost_token = NULL;
++		if (token == aes_token)
++			aes_token = NULL;
++		pk11_mem_put(token, sizeof(*token));
++		token = next;
++	}
++	if (pk11_mctx != NULL)
++		isc_mem_detach(&pk11_mctx);
++	initialized = ISC_FALSE;
++	return (ret);
++}
++
++isc_result_t
++pk11_rand_bytes(unsigned char *buf, int num) {
++	isc_result_t ret;
++	CK_RV rv;
++	pk11_context_t ctx;
++
++	ret = pk11_get_session(&ctx, OP_RAND, ISC_FALSE, ISC_FALSE,
++			       ISC_FALSE, NULL, 0);
++	if ((ret != ISC_R_SUCCESS) &&
++	    (ret != PK11_R_NODIGESTSERVICE) &&
++	    (ret != PK11_R_NOAESSERVICE))
++		return (ret);
++	RUNTIME_CHECK(ctx.session != CK_INVALID_HANDLE);
++	rv = pkcs_C_GenerateRandom(ctx.session,
++				   (CK_BYTE_PTR) buf, (CK_ULONG) num);
++	pk11_return_session(&ctx);
++	if (rv == CKR_OK)
++		return (ISC_R_SUCCESS);
++	else
++		return (DST_R_CRYPTOFAILURE);
++}
++
++#define SEEDSIZE	1024
++
++static CK_BYTE seed[SEEDSIZE];
++
++void
++pk11_rand_seed_fromfile(const char *randomfile) {
++	pk11_context_t ctx;
++	FILE *stream = NULL;
++	size_t cc = 0;
++	isc_result_t ret;
++
++	ret = pk11_get_session(&ctx, OP_RAND, ISC_FALSE, ISC_FALSE,
++			       ISC_FALSE, NULL, 0);
++	if ((ret != ISC_R_SUCCESS) &&
++	    (ret != PK11_R_NODIGESTSERVICE) &&
++	    (ret != PK11_R_NOAESSERVICE))
++		return;
++	RUNTIME_CHECK(ctx.session != CK_INVALID_HANDLE);
++	ret = isc_stdio_open(randomfile, "r", &stream);
++	if (ret != ISC_R_SUCCESS)
++		goto cleanup;
++	ret = isc_stdio_read(seed, 1, SEEDSIZE, stream, &cc);
++	if (ret!= ISC_R_SUCCESS)
++		goto cleanup;
++	ret = isc_stdio_close(stream);
++	stream = NULL;
++	if (ret!= ISC_R_SUCCESS)
++		goto cleanup;
++	(void) pkcs_C_SeedRandom(ctx.session, seed, (CK_ULONG) cc);
++
++    cleanup:
++	if (stream != NULL)
++		(void) isc_stdio_close(stream);
++	pk11_return_session(&ctx);
++}
++
++isc_result_t
++pk11_get_session(pk11_context_t *ctx, pk11_optype_t optype,
++		 isc_boolean_t need_services, isc_boolean_t rw,
++		 isc_boolean_t logon, const char *pin, CK_SLOT_ID slot)
++{
++	pk11_token_t *token = NULL;
++	pk11_sessionlist_t *freelist;
++	pk11_session_t *sp;
++	isc_result_t ret;
++#ifdef PKCS11CRYPTO
++	isc_result_t service_ret = ISC_R_SUCCESS;
++#else
++	UNUSED(need_services);
++#endif
++
++	memset(ctx, 0, sizeof(pk11_context_t));
++	ctx->handle = NULL;
++	ctx->session = CK_INVALID_HANDLE;
++
++	ret = pk11_initialize(NULL, NULL);
++#ifdef PKCS11CRYPTO
++	if (ret == PK11_R_NORANDOMSERVICE ||
++	    ret == PK11_R_NODIGESTSERVICE ||
++	    ret == PK11_R_NOAESSERVICE) {
++		if (need_services)
++			return (ret);
++		service_ret = ret;
++	}
++	else
++#endif /* PKCS11CRYPTO */
++	if (ret != ISC_R_SUCCESS)
++		return (ret);
++
++	LOCK(&sessionlock);
++	/* wait for initialization to finish */
++	UNLOCK(&sessionlock);
++
++	switch(optype) {
++#ifdef PKCS11CRYPTO
++	case OP_RAND:
++		token = rand_token;
++		break;
++	case OP_DIGEST:
++		token = digest_token;
++		break;
++	case OP_AES:
++		token = aes_token;
++		break;
++	case OP_ANY:
++		for (token = ISC_LIST_HEAD(tokens);
++		     token != NULL;
++		     token = ISC_LIST_NEXT(token, link))
++			if (token->slotid == slot)
++				break;
++		break;
++#endif
++	default:
++		for (token = ISC_LIST_HEAD(tokens);
++		     token != NULL;
++		     token = ISC_LIST_NEXT(token, link))
++			if (token->slotid == slot)
++				break;
++#ifdef PKCS11CRYPTO
++		if ((token == NULL) ||
++		    ((token->operations & (1 << optype)) == 0))
++			return (ISC_R_NOTFOUND);
++#endif
++		break;
++	}
++	if (token == NULL)
++		return (ISC_R_NOTFOUND);
++
++	/* Override the token's PIN */
++	if (logon && pin != NULL && *pin != '\0') {
++		memset(token->pin, 0, PINLEN);
++		strncpy(token->pin, pin, PINLEN);
++	}
++
++	freelist = &token->sessions;
++
++	LOCK(&sessionlock);
++	sp = ISC_LIST_HEAD(*freelist);
++	if (sp != NULL) {
++		ISC_LIST_UNLINK(*freelist, sp, link);
++		ISC_LIST_APPEND(actives, sp, link);
++		UNLOCK(&sessionlock);
++		if (logon)
++			ret = token_login(sp);
++		ctx->handle = sp;
++		ctx->session = sp->session;
++		return (ret);
++	}
++	UNLOCK(&sessionlock);
++
++	sp = pk11_mem_get(sizeof(*sp));
++	if (sp == NULL)
++		return (ISC_R_NOMEMORY);
++	sp->magic = SES_MAGIC;
++	sp->token = token;
++	sp->session = CK_INVALID_HANDLE;
++	ISC_LINK_INIT(sp, link);
++	ret = setup_session(sp, token, rw);
++	if ((ret == ISC_R_SUCCESS) && logon)
++		ret = token_login(sp);
++	LOCK(&sessionlock);
++	ISC_LIST_APPEND(actives, sp, link);
++	UNLOCK(&sessionlock);
++	ctx->handle = sp;
++	ctx->session = sp->session;
++#ifdef PKCS11CRYPTO
++	if (ret == ISC_R_SUCCESS)
++		ret = service_ret;
++#endif
++	return (ret);
++}
++
++void
++pk11_return_session(pk11_context_t *ctx) {
++	pk11_session_t *sp = (pk11_session_t *) ctx->handle;
++
++	if (sp == NULL)
++		return;
++	ctx->handle = NULL;
++	ctx->session = CK_INVALID_HANDLE;
++
++	LOCK(&sessionlock);
++	ISC_LIST_UNLINK(actives, sp, link);
++	UNLOCK(&sessionlock);
++	if (sp->session == CK_INVALID_HANDLE) {
++		pk11_mem_put(sp, sizeof(*sp));
++		return;
++	}
++
++	LOCK(&sessionlock);
++	ISC_LIST_APPEND(sp->token->sessions, sp, link);
++	UNLOCK(&sessionlock);
++}
++
++static isc_result_t
++free_all_sessions(void) {
++	pk11_token_t *token;
++	isc_result_t ret = ISC_R_SUCCESS;
++	isc_result_t oret;
++
++	for (token = ISC_LIST_HEAD(tokens);
++	     token != NULL;
++	     token = ISC_LIST_NEXT(token, link)) {
++		oret = free_session_list(&token->sessions);
++		if (oret != ISC_R_SUCCESS)
++			ret = oret;
++	}
++	if (!ISC_LIST_EMPTY(actives)) {
++		ret = ISC_R_ADDRINUSE;
++		oret = free_session_list(&actives);
++		if (oret != ISC_R_SUCCESS)
++			ret = oret;
++	}
++	return (ret);
++}
++
++static isc_result_t
++free_session_list(pk11_sessionlist_t *slist) {
++	pk11_session_t *sp;
++	CK_RV rv;
++	isc_result_t ret;
++
++	ret = ISC_R_SUCCESS;
++	LOCK(&sessionlock);
++	while (!ISC_LIST_EMPTY(*slist)) {
++		sp = ISC_LIST_HEAD(*slist);
++		UNLOCK(&sessionlock);
++		if (sp->session != CK_INVALID_HANDLE) {
++			rv = pkcs_C_CloseSession(sp->session);
++			if (rv != CKR_OK)
++				ret = DST_R_CRYPTOFAILURE;
++		}
++		LOCK(&sessionlock);
++		ISC_LIST_UNLINK(*slist, sp, link);
++		pk11_mem_put(sp, sizeof(*sp));
++	}
++	UNLOCK(&sessionlock);
++
++	return (ret);
++}
++
++static isc_result_t
++setup_session(pk11_session_t *sp, pk11_token_t *token,
++	      isc_boolean_t rw)
++{
++	CK_RV rv;
++	CK_FLAGS flags = CKF_SERIAL_SESSION;
++
++	if (rw)
++		flags += CKF_RW_SESSION;
++
++	rv = pkcs_C_OpenSession(token->slotid, flags, NULL_PTR,
++				NULL_PTR, &sp->session);
++	if (rv != CKR_OK)
++		return (DST_R_CRYPTOFAILURE);
++	return (ISC_R_SUCCESS);
++}
++
++static isc_result_t
++token_login(pk11_session_t *sp) {
++	CK_RV rv;
++	pk11_token_t *token = sp->token;
++	isc_result_t ret = ISC_R_SUCCESS;
++
++	LOCK(&sessionlock);
++	if (!token->logged) {
++		rv = pkcs_C_Login(sp->session, CKU_USER,
++				  (CK_UTF8CHAR_PTR) token->pin,
++				  (CK_ULONG) strlen(token->pin));
++		if (rv != CKR_OK) {
++			ret = ISC_R_NOPERM;
++#if PK11_NO_LOGERR
++			pk11_error_fatalcheck(__FILE__, __LINE__,
++					      "pkcs_C_Login", rv);
++#endif
++		} else
++			token->logged = ISC_TRUE;
++	}
++	UNLOCK(&sessionlock);
++	return (ret);
++}
++
++static void
++choose_slots(void) {
++	CK_MECHANISM_INFO mechInfo;
++	CK_TOKEN_INFO tokenInfo;
++	CK_RV rv;
++	CK_SLOT_ID slot;
++	CK_SLOT_ID_PTR slotList;
++	CK_ULONG slotCount;
++	pk11_token_t *token;
++	unsigned int i;
++
++	slotCount = 0;
++	PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, NULL_PTR, &slotCount));
++	/* it's not an error if we didn't find any providers */
++	if (slotCount == 0)
++		return;
++	slotList = pk11_mem_get(sizeof(CK_SLOT_ID_PTR) * slotCount);
++	RUNTIME_CHECK(slotList != NULL);
++	PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, slotList, &slotCount));
++
++	for (i = 0; i < slotCount; i++) {
++		slot = slotList[i];
++
++		rv = pkcs_C_GetTokenInfo(slot, &tokenInfo);
++		if (rv != CKR_OK)
++			continue;
++		token = pk11_mem_get(sizeof(*token));
++		RUNTIME_CHECK(token != NULL);
++		token->magic = TOK_MAGIC;
++		token->slotid = slot;
++		ISC_LINK_INIT(token, link);
++		ISC_LIST_INIT(token->sessions);
++		memmove(token->name, tokenInfo.label, 32);
++		memmove(token->manuf, tokenInfo.manufacturerID, 32);
++		memmove(token->model, tokenInfo.model, 16);
++		memmove(token->serial, tokenInfo.serialNumber, 16);
++		ISC_LIST_APPEND(tokens, token, link);
++		if ((tokenInfo.flags & CKF_RNG) == 0)
++			goto try_rsa;
++		token->operations |= 1 << OP_RAND;
++		if (rand_token == NULL)
++			rand_token = token;
++
++	try_rsa:
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
++					     &mechInfo);
++		if ((rv != CKR_OK) ||
++		    ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0))
++			goto try_dsa;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5_RSA_PKCS,
++					     &mechInfo);
++		if ((rv != CKR_OK) ||
++		    ((mechInfo.flags & CKF_SIGN) == 0) ||
++		    ((mechInfo.flags & CKF_VERIFY) == 0))
++			goto try_dsa;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA1_RSA_PKCS,
++					     &mechInfo);
++		if ((rv != CKR_OK) ||
++		    ((mechInfo.flags & CKF_SIGN) == 0) ||
++		    ((mechInfo.flags & CKF_VERIFY) == 0))
++			goto try_dsa;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256_RSA_PKCS,
++					     &mechInfo);
++		if ((rv != CKR_OK) ||
++		    ((mechInfo.flags & CKF_SIGN) == 0) ||
++		    ((mechInfo.flags & CKF_VERIFY) == 0))
++			goto try_dsa;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512_RSA_PKCS,
++					     &mechInfo);
++		if ((rv != CKR_OK) ||
++		    ((mechInfo.flags & CKF_SIGN) == 0) ||
++		    ((mechInfo.flags & CKF_VERIFY) == 0))
++			goto try_dsa;
++		token->operations |= 1 << OP_RSA;
++		if (best_rsa_token == NULL)
++			best_rsa_token = token;
++
++	try_dsa:
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_PARAMETER_GEN,
++					     &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_GENERATE) == 0))
++			goto try_dh;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_KEY_PAIR_GEN,
++					     &mechInfo);
++		if ((rv != CKR_OK) ||
++		    ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0))
++			goto try_dh;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_SHA1, &mechInfo);
++		if ((rv != CKR_OK) ||
++		    ((mechInfo.flags & CKF_SIGN) == 0) ||
++		    ((mechInfo.flags & CKF_VERIFY) == 0))
++			goto try_dh;
++		token->operations |= 1 << OP_DSA;
++		if (best_dsa_token == NULL)
++			best_dsa_token = token;
++
++	try_dh:
++#ifdef notdef
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_DH_PKCS_PARAMETER_GEN,
++					     &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_GENERATE) == 0))
++			goto try_digest;
++#endif
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_DH_PKCS_KEY_PAIR_GEN,
++					     &mechInfo);
++		if ((rv != CKR_OK) ||
++		    ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0))
++			goto try_digest;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_DH_PKCS_DERIVE,
++					     &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DERIVE) == 0))
++			goto try_digest;
++		token->operations |= 1 << OP_DH;
++		if (best_dh_token == NULL)
++			best_dh_token = token;
++
++	try_digest:
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5, &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
++			continue;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA_1, &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
++			continue;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA224, &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
++			continue;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256, &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
++			continue;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA384, &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
++			continue;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512, &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
++			continue;
++#ifdef PKCS11CRYPTOWITHHMAC
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5_HMAC, &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
++			continue;
++#endif
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA_1_HMAC, &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
++			continue;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA224_HMAC, &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
++			continue;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256_HMAC, &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
++			continue;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA384_HMAC, &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
++			continue;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512_HMAC, &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0))
++			continue;
++		token->operations |= 1 << OP_DIGEST;
++		if (digest_token == NULL)
++			digest_token = token;
++
++		/* ECDSA requires digest */
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_EC_KEY_PAIR_GEN,
++					     &mechInfo);
++		if ((rv != CKR_OK) ||
++		    ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0))
++			goto try_gost;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_ECDSA, &mechInfo);
++		if ((rv != CKR_OK) ||
++		    ((mechInfo.flags & CKF_SIGN) == 0) ||
++		    ((mechInfo.flags & CKF_VERIFY) == 0))
++			goto try_gost;
++		token->operations |= 1 << OP_EC;
++		if (best_ec_token == NULL)
++			best_ec_token = token;
++
++	try_gost:
++		/* does GOST require digest too? */
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_GOSTR3411, &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0))
++			goto try_aes;
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_GOSTR3410_KEY_PAIR_GEN,
++					     &mechInfo);
++		if ((rv != CKR_OK) ||
++		    ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0))
++			goto try_aes;
++		rv = pkcs_C_GetMechanismInfo(slot,
++					     CKM_GOSTR3410_WITH_GOSTR3411,
++					     &mechInfo);
++		if ((rv != CKR_OK) ||
++		    ((mechInfo.flags & CKF_SIGN) == 0) ||
++		    ((mechInfo.flags & CKF_VERIFY) == 0))
++			goto try_aes;
++		token->operations |= 1 << OP_GOST;
++		if (best_gost_token == NULL)
++			best_gost_token = token;
++
++	try_aes:
++		rv = pkcs_C_GetMechanismInfo(slot, CKM_AES_ECB, &mechInfo);
++		if ((rv != CKR_OK) || ((mechInfo.flags & CKF_ENCRYPT) == 0))
++			continue;
++		token->operations |= 1 << OP_AES;
++		if (aes_token == NULL)
++			aes_token = token;
++	}
++
++	if (slotList != NULL)
++		pk11_mem_put(slotList, sizeof(CK_SLOT_ID_PTR) * slotCount);
++}
++
++CK_SLOT_ID
++pk11_get_best_token(pk11_optype_t optype) {
++	pk11_token_t *token = NULL;
++
++	switch (optype) {
++	case OP_RAND:
++		token = rand_token;
++		break;
++	case OP_RSA:
++		token = best_rsa_token;
++		break;
++	case OP_DSA:
++		token = best_dsa_token;
++		break;
++	case OP_DH:
++		token = best_dh_token;
++		break;
++	case OP_DIGEST:
++		token = digest_token;
++		break;
++	case OP_EC:
++		token = best_ec_token;
++		break;
++	case OP_GOST:
++		token = best_gost_token;
++		break;
++	case OP_AES:
++		token = aes_token;
++		break;
++	default:
++		break;
++	}
++	if (token == NULL)
++		return (0);
++	return (token->slotid);
++}
++
++unsigned int
++pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt) {
++	unsigned int bitcnt, i;
++	CK_BYTE top;
++
++	if (bytecnt == 0)
++		return (0);
++	bitcnt = bytecnt * 8;
++	for (i = 0; i < bytecnt; i++) {
++		top = data[i];
++		if (top == 0) {
++			bitcnt -= 8;
++			continue;
++		}
++		if (top & 0x80)
++			return (bitcnt);
++		if (top & 0x40)
++			return (bitcnt - 1);
++		if (top & 0x20)
++			return (bitcnt - 2);
++		if (top & 0x10)
++			return (bitcnt - 3);
++		if (top & 0x08)
++			return (bitcnt - 4);
++		if (top & 0x04)
++			return (bitcnt - 5);
++		if (top & 0x02)
++			return (bitcnt - 6);
++		if (top & 0x01)
++			return (bitcnt - 7);
++		break;
++	}
++	INSIST(0);
++}
++
++CK_ATTRIBUTE *
++pk11_attribute_first(const pk11_object_t *obj) {
++	return (obj->repr);
++}
++
++CK_ATTRIBUTE *
++pk11_attribute_next(const pk11_object_t *obj, CK_ATTRIBUTE *attr) {
++	CK_ATTRIBUTE *next;
++
++	next = attr + 1;
++	if ((next - obj->repr) >= obj->attrcnt)
++		return (NULL);
++	return (next);
++}
++
++CK_ATTRIBUTE *
++pk11_attribute_bytype(const pk11_object_t *obj, CK_ATTRIBUTE_TYPE type) {
++	CK_ATTRIBUTE *attr;
++
++	for(attr = pk11_attribute_first(obj);
++	    attr != NULL;
++	    attr = pk11_attribute_next(obj, attr))
++		if (attr->type == type)
++			return (attr);
++	return (NULL);
++}
++
++static char *
++percent_decode(char *x, size_t *len) {
++	char *p, *c;
++	unsigned char v;
++
++	INSIST(len != NULL);
++
++	for (p = c = x; p[0] != '\0'; p++, c++) {
++		switch (p[0]) {
++		case '%':
++			v = 0;
++			switch (p[1]) {
++			case '0':
++			case '1':
++			case '2':
++			case '3':
++			case '4':
++			case '5':
++			case '6':
++			case '7':
++			case '8':
++			case '9':
++				v = (p[1] - '0') << 4;
++				break;
++			case 'A':
++			case 'B':
++			case 'C':
++			case 'D':
++			case 'E':
++			case 'F':
++				v = (p[1] - 'A' + 10) << 4;
++				break;
++			case 'a':
++			case 'b':
++			case 'c':
++			case 'd':
++			case 'e':
++			case 'f':
++				v = (p[1] - 'a' + 10) << 4;
++				break;
++			default:
++				return (NULL);
++			}
++			switch (p[2]) {
++			case '0':
++			case '1':
++			case '2':
++			case '3':
++			case '4':
++			case '5':
++			case '6':
++			case '7':
++			case '8':
++			case '9':
++				v |= (p[2] - '0') & 0x0f;
++				break;
++			case 'A':
++			case 'B':
++			case 'C':
++			case 'D':
++			case 'E':
++			case 'F':
++				v = (p[2] - 'A' + 10) & 0x0f;
++				break;
++			case 'a':
++			case 'b':
++			case 'c':
++			case 'd':
++			case 'e':
++			case 'f':
++				v = (p[2] - 'a' + 10) & 0x0f;
++				break;
++			default:
++				return (NULL);
++			}
++			p += 2;
++			*c = (char) v;
++			(*len)++;
++			break;
++		default:
++			*c = *p;
++			(*len)++;
++		}
++	}
++	return (x);
++}
++
++static isc_boolean_t
++pk11strcmp(const char *x, size_t lenx, const char *y, size_t leny) {
++	char buf[32];
++
++	INSIST((leny == 32) || (leny == 16));
++
++	memset(buf, ' ', 32);
++	if (lenx > leny)
++		lenx = leny;
++	memmove(buf, x, lenx);
++	return (ISC_TF(memcmp(buf, y, leny) == 0));
++}
++
++static CK_ATTRIBUTE *
++push_attribute(pk11_object_t *obj, isc_mem_t *mctx, size_t len) {
++	CK_ATTRIBUTE *old = obj->repr;
++	CK_ATTRIBUTE *attr;
++	CK_BYTE cnt = obj->attrcnt;
++
++	obj->repr = isc_mem_get(mctx, (cnt + 1) * sizeof(*attr));
++	if (obj->repr == NULL) {
++		obj->repr = old;
++		return (NULL);
++	}
++	memset(obj->repr, 0, (cnt + 1) * sizeof(*attr));
++	memmove(obj->repr, old, cnt * sizeof(*attr));
++	attr = obj->repr + cnt;
++	attr->ulValueLen = (CK_ULONG) len;
++	attr->pValue = isc_mem_get(mctx, len);
++	if (attr->pValue == NULL) {
++		memset(obj->repr, 0, (cnt + 1) * sizeof(*attr));
++		isc_mem_put(mctx, obj->repr, (cnt + 1) * sizeof(*attr));
++		obj->repr = old;
++		return (NULL);
++	}
++	memset(attr->pValue, 0, len);
++	if (old != NULL) {
++		memset(old, 0, cnt * sizeof(*attr));
++		isc_mem_put(mctx, old, cnt * sizeof(*attr));
++	}
++	obj->attrcnt++;
++	return (attr);
++}
++
++#define DST_RET(a)	{ ret = a; goto err; }
++
++isc_result_t
++pk11_parse_uri(pk11_object_t *obj, const char *label,
++	       isc_mem_t *mctx, pk11_optype_t optype)
++{
++	CK_ATTRIBUTE *attr;
++	pk11_token_t *token = NULL;
++	char *uri, *p, *a, *na, *v;
++	size_t len, l;
++	FILE *stream = NULL;
++	char pin[PINLEN];
++	isc_boolean_t gotpin = ISC_FALSE;
++	isc_result_t ret;
++
++	/* get values to work on */
++	len = strlen(label) + 1;
++	uri = isc_mem_get(mctx, len);
++	if (uri == NULL)
++		return (ISC_R_NOMEMORY);
++	memmove(uri, label, len);
++
++	/* get the URI scheme */
++	p = strchr(uri, ':');
++	if (p == NULL)
++		DST_RET(PK11_R_NOPROVIDER);
++	*p++ = '\0';
++	if (strcmp(uri, "pkcs11") != 0)
++		DST_RET(PK11_R_NOPROVIDER);
++
++	/* get attributes */
++	for (na = p; na != NULL;) {
++		a = na;
++		p = strchr(a, ';');
++		if (p == NULL) {
++			/* last attribute */
++			na = NULL;
++		} else {
++			*p++ = '\0';
++			na = p;
++		}
++		p = strchr(a, '=');
++		if (p != NULL) {
++			*p++ = '\0';
++			v = p;
++		} else
++			v = a;
++		l = 0;
++		v = percent_decode(v, &l);
++		if (v == NULL)
++			DST_RET(PK11_R_NOPROVIDER);
++		if ((a == v) || (strcmp(a, "object") == 0)) {
++			/* object: CKA_LABEL */
++			attr = pk11_attribute_bytype(obj, CKA_LABEL);
++			if (attr != NULL)
++				DST_RET(PK11_R_NOPROVIDER);
++			attr = push_attribute(obj, mctx, l);
++			if (attr == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			attr->type = CKA_LABEL;
++			memmove(attr->pValue, v, l);
++		} else if (strcmp(a, "token") == 0) {
++			/* token: CK_TOKEN_INFO label */
++			if (token == NULL)
++				for (token = ISC_LIST_HEAD(tokens);
++				     token != NULL;
++				     token = ISC_LIST_NEXT(token, link))
++					if (pk11strcmp(v, l, token->name, 32))
++						break;
++		} else if (strcmp(a, "manufacturer") == 0) {
++			/* manufacturer: CK_TOKEN_INFO manufacturerID */
++			if (token == NULL)
++				for (token = ISC_LIST_HEAD(tokens);
++				     token != NULL;
++				     token = ISC_LIST_NEXT(token, link))
++					if (pk11strcmp(v, l, token->manuf, 32))
++						break;
++		} else if (strcmp(a, "serial") == 0) {
++			/* serial: CK_TOKEN_INFO serialNumber */
++			if (token == NULL)
++				for (token = ISC_LIST_HEAD(tokens);
++				     token != NULL;
++				     token = ISC_LIST_NEXT(token, link))
++					if (pk11strcmp(v, l, token->serial, 16))
++						break;
++		} else if (strcmp(a, "model") == 0) {
++			/* model: CK_TOKEN_INFO model */
++			if (token == NULL)
++				for (token = ISC_LIST_HEAD(tokens);
++				     token != NULL;
++				     token = ISC_LIST_NEXT(token, link))
++					if (pk11strcmp(v, l, token->model, 16))
++						break;
++		} else if (strcmp(a, "library-manufacturer") == 0) {
++			/* ignored */
++		} else if (strcmp(a, "library-description") == 0) {
++			/* ignored */
++		} else if (strcmp(a, "library-version") == 0) {
++			/* ignored */
++		} else if (strcmp(a, "object-type") == 0) {
++			/* object-type: CKA_CLASS */
++			/* only private makes sense */
++			if (strcmp(v, "private") != 0)
++				DST_RET(PK11_R_NOPROVIDER);
++		} else if (strcmp(a, "id") == 0) {
++			/* id: CKA_ID */
++			attr = pk11_attribute_bytype(obj, CKA_ID);
++			if (attr != NULL)
++				DST_RET(PK11_R_NOPROVIDER);
++			attr = push_attribute(obj, mctx, l);
++			if (attr == NULL)
++				DST_RET(ISC_R_NOMEMORY);
++			attr->type = CKA_ID;
++			memmove(attr->pValue, v, l);
++		} else if (strcmp(a, "pin-source") == 0) {
++			/* pin-source: PIN */
++			ret = isc_stdio_open(v, "r", &stream);
++			if (ret != ISC_R_SUCCESS)
++				goto err;
++			memset(pin, 0, PINLEN);
++			ret = isc_stdio_read(pin, 1, PINLEN - 1, stream, NULL);
++			if ((ret != ISC_R_SUCCESS) && (ret != ISC_R_EOF))
++				goto err;
++			ret = isc_stdio_close(stream);
++			stream = NULL;
++			if (ret != ISC_R_SUCCESS)
++				goto err;
++			gotpin = ISC_TRUE;
++		} else
++			DST_RET(PK11_R_NOPROVIDER);
++	}
++
++	if ((pk11_attribute_bytype(obj, CKA_LABEL) == NULL) &&
++	    (pk11_attribute_bytype(obj, CKA_ID) == NULL))
++		DST_RET(ISC_R_NOTFOUND);
++
++	if (token == NULL) {
++		if (optype == OP_RSA)
++			token = best_rsa_token;
++		else if (optype == OP_DSA)
++			token = best_dsa_token;
++		else if (optype == OP_DH)
++			token = best_dh_token;
++		else if (optype == OP_EC)
++			token = best_ec_token;
++	}
++	if (token == NULL)
++		DST_RET(ISC_R_NOTFOUND);
++	obj->slot = token->slotid;
++	if (gotpin) {
++		memmove(token->pin, pin, PINLEN);
++		obj->reqlogon = ISC_TRUE;
++	}
++
++	ret = ISC_R_SUCCESS;
++
++  err:
++	if (stream != NULL)
++		(void) isc_stdio_close(stream);
++	isc_mem_put(mctx, uri, len);
++	return (ret);
++}
++
++void
++pk11_error_fatalcheck(const char *file, int line,
++		      const char *funcname, CK_RV rv)
++{
++	isc_error_fatal(file, line, "%s: Error = 0x%.8lX\n", funcname, rv);
++}
++
++void
++pk11_dump_tokens(void)
++{
++	pk11_token_t *token;
++	isc_boolean_t first;
++
++	printf("DEFAULTS\n");
++	printf("\trand_token=%p\n", rand_token);
++	printf("\tbest_rsa_token=%p\n", best_rsa_token);
++	printf("\tbest_dsa_token=%p\n", best_dsa_token);
++	printf("\tbest_dh_token=%p\n", best_dh_token);
++	printf("\tdigest_token=%p\n", digest_token);
++	printf("\tbest_ec_token=%p\n", best_ec_token);
++	printf("\tbest_gost_token=%p\n", best_gost_token);
++	printf("\taes_token=%p\n", aes_token);
++
++	for (token = ISC_LIST_HEAD(tokens);
++	     token != NULL;
++	     token = ISC_LIST_NEXT(token, link)) {
++		printf("\nTOKEN\n");
++		printf("\taddress=%p\n", token);
++		printf("\tslotID=%lu\n", token->slotid);
++		printf("\tlabel=%.32s\n", token->name);
++		printf("\tmanufacturerID=%.32s\n", token->manuf);
++		printf("\tmodel=%.16s\n", token->model);
++		printf("\tserialNumber=%.16s\n", token->serial);
++		printf("\tsupported operations=0x%x (", token->operations);
++		first = ISC_TRUE;
++		if (token->operations & (1 << OP_RAND)) {
++			if (!first)
++				printf(",");
++			first = ISC_FALSE;
++			printf("RAND");
++		}
++		if (token->operations & (1 << OP_RSA)) {
++			if (!first)
++				printf(",");
++			first = ISC_FALSE;
++			printf("RSA");
++		}
++		if (token->operations & (1 << OP_DSA)) {
++			if (!first)
++				printf(",");
++			first = ISC_FALSE;
++			printf("DSA");
++		}
++		if (token->operations & (1 << OP_DH)) {
++			if (!first)
++				printf(",");
++			first = ISC_FALSE;
++			printf("DH");
++		}
++		if (token->operations & (1 << OP_DIGEST)) {
++			if (!first)
++				printf(",");
++			first = ISC_FALSE;
++			printf("DIGEST");
++		}
++		if (token->operations & (1 << OP_EC)) {
++			if (!first)
++				printf(",");
++			first = ISC_FALSE;
++			printf("EC");
++		}
++		printf(")\n");
++	}
++}
+diff --git a/lib/isc/pk11_result.c b/lib/isc/pk11_result.c
+new file mode 100644
+index 0000000..0ada753
+--- /dev/null
++++ b/lib/isc/pk11_result.c
+@@ -0,0 +1,85 @@
++/*
++ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++#include <config.h>
++#include <stddef.h>
++
++#include <isc/once.h>
++#include <isc/msgcat.h>
++#include <isc/util.h>
++
++#include <pk11/result.h>
++
++LIBISC_EXTERNAL_DATA isc_msgcat_t *		pk11_msgcat = NULL;
++
++static isc_once_t		msgcat_once = ISC_ONCE_INIT;
++
++static const char *text[PK11_R_NRESULTS] = {
++	"PKCS#11 initialization failed",		/*%< 0 */
++	"no PKCS#11 provider",				/*%< 1 */
++	"PKCS#11 provider has no random service",	/*%< 2 */
++	"PKCS#11 provider has no digest service",	/*%< 3 */
++	"PKCS#11 provider has no AES service",		/*%< 4 */
++};
++
++#define PK11_RESULT_RESULTSET			2
++
++static isc_once_t		once = ISC_ONCE_INIT;
++
++static void
++open_msgcat(void) {
++	isc_msgcat_open("libpk11.cat", &pk11_msgcat);
++}
++
++void
++pk11_initmsgcat(void) {
++
++	/*
++	 * Initialize the PKCS#11 support's message catalog,
++	 * pk11_msgcat, if it has not already been initialized.
++	 */
++
++	RUNTIME_CHECK(isc_once_do(&msgcat_once, open_msgcat) == ISC_R_SUCCESS);
++}
++
++static void
++initialize_action(void) {
++	isc_result_t result;
++
++	result = isc_result_register(ISC_RESULTCLASS_PK11, PK11_R_NRESULTS,
++				     text, pk11_msgcat, PK11_RESULT_RESULTSET);
++	if (result != ISC_R_SUCCESS)
++		UNEXPECTED_ERROR(__FILE__, __LINE__,
++				 "isc_result_register() failed: %u", result);
++}
++
++static void
++initialize(void) {
++	pk11_initmsgcat();
++	RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
++}
++
++const char *
++pk11_result_totext(isc_result_t result) {
++	initialize();
++
++	return (isc_result_totext(result));
++}
++
++void
++pk11_result_register(void) {
++	initialize();
++}
+diff --git a/lib/isc/sha1.c b/lib/isc/sha1.c
+index cce9603..caa721e 100644
+--- a/lib/isc/sha1.c
++++ b/lib/isc/sha1.c
+@@ -44,8 +44,12 @@
+ #include <isc/types.h>
+ #include <isc/util.h>
+ 
+-#ifdef ISC_PLATFORM_OPENSSLHASH
++#if PKCS11CRYPTO
++#include <pk11/internal.h>
++#include <pk11/pk11.h>
++#endif
+ 
++#ifdef ISC_PLATFORM_OPENSSLHASH
+ void
+ isc_sha1_init(isc_sha1_t *context)
+ {
+@@ -77,6 +81,50 @@ isc_sha1_final(isc_sha1_t *context, unsigned char *digest) {
+ 	EVP_DigestFinal(context, digest, NULL);
+ }
+ 
++#elif PKCS11CRYPTO
++
++void
++isc_sha1_init(isc_sha1_t *ctx) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_SHA_1, NULL, 0 };
++
++	RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE,
++				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
++	PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
++}
++
++void
++isc_sha1_invalidate(isc_sha1_t *ctx) {
++	CK_BYTE garbage[ISC_SHA1_DIGESTLENGTH];
++	CK_ULONG len = ISC_SHA1_DIGESTLENGTH;
++
++	if (ctx->handle == NULL)
++		return;
++	(void) pkcs_C_DigestFinal(ctx->session, garbage, &len);
++	memset(garbage, 0, sizeof(garbage));
++	pk11_return_session(ctx);
++}
++
++void
++isc_sha1_update(isc_sha1_t *ctx, const unsigned char *buf, unsigned int len) {
++	CK_RV rv;
++	CK_BYTE_PTR pPart;
++
++	DE_CONST(buf, pPart);
++	PK11_FATALCHECK(pkcs_C_DigestUpdate,
++			(ctx->session, pPart, (CK_ULONG) len));
++}
++
++void
++isc_sha1_final(isc_sha1_t *ctx, unsigned char *digest) {
++	CK_RV rv;
++	CK_ULONG len = ISC_SHA1_DIGESTLENGTH;
++
++	PK11_FATALCHECK(pkcs_C_DigestFinal,
++			(ctx->session, (CK_BYTE_PTR) digest, &len));
++	pk11_return_session(ctx);
++}
++
+ #else
+ 
+ #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+diff --git a/lib/isc/sha2.c b/lib/isc/sha2.c
+index db2e349..d7e0cf6 100644
+--- a/lib/isc/sha2.c
++++ b/lib/isc/sha2.c
+@@ -63,6 +63,11 @@
+ #include <isc/string.h>
+ #include <isc/util.h>
+ 
++#if PKCS11CRYPTO
++#include <pk11/internal.h>
++#include <pk11/pk11.h>
++#endif
++
+ #ifdef ISC_PLATFORM_OPENSSLHASH
+ 
+ void
+@@ -219,6 +224,272 @@ isc_sha384_final(isc_uint8_t digest[], isc_sha384_t *context) {
+ 	}
+ }
+ 
++#elif PKCS11CRYPTO
++
++void
++isc_sha224_init(isc_sha224_t *context) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_SHA224, NULL, 0 };
++
++	if (context == (isc_sha224_t *)0) {
++		return;
++	}
++	RUNTIME_CHECK(pk11_get_session(context, OP_DIGEST, ISC_TRUE, ISC_FALSE,
++				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
++	PK11_FATALCHECK(pkcs_C_DigestInit, (context->session, &mech));
++}
++
++void
++isc_sha224_invalidate(isc_sha224_t *context) {
++	CK_BYTE garbage[ISC_SHA224_DIGESTLENGTH];
++	CK_ULONG len = ISC_SHA224_DIGESTLENGTH;
++
++	if (context->handle == NULL)
++		return;
++	(void) pkcs_C_DigestFinal(context->session, garbage, &len);
++	memset(garbage, 0, sizeof(garbage));
++	pk11_return_session(context);
++}
++
++void
++isc_sha224_update(isc_sha224_t *context, const isc_uint8_t* data, size_t len) {
++	CK_RV rv;
++	CK_BYTE_PTR pPart;
++
++	if (len == 0U) {
++		/* Calling with no data is valid - we do nothing */
++		return;
++	}
++
++	/* Sanity check: */
++	REQUIRE(context != (isc_sha224_t *)0 && data != (isc_uint8_t*)0);
++
++	DE_CONST(data, pPart);
++	PK11_FATALCHECK(pkcs_C_DigestUpdate,
++			(context->session, pPart, (CK_ULONG) len));
++}
++
++void
++isc_sha224_final(isc_uint8_t digest[], isc_sha224_t *context) {
++	CK_RV rv;
++	CK_ULONG len = ISC_SHA224_DIGESTLENGTH;
++
++	/* Sanity check: */
++	REQUIRE(context != (isc_sha224_t *)0);
++
++	/* If no digest buffer is passed, we don't bother doing this: */
++	if (digest != (isc_uint8_t*)0) {
++		PK11_FATALCHECK(pkcs_C_DigestFinal,
++				(context->session,
++				 (CK_BYTE_PTR) digest,
++				 &len));
++	} else {
++		CK_BYTE garbage[ISC_SHA224_DIGESTLENGTH];
++
++		(void) pkcs_C_DigestFinal(context->session, garbage, &len);
++		memset(garbage, 0, sizeof(garbage));
++	}
++	pk11_return_session(context);
++}
++
++void
++isc_sha256_init(isc_sha256_t *context) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_SHA256, NULL, 0 };
++
++	if (context == (isc_sha256_t *)0) {
++		return;
++	}
++	RUNTIME_CHECK(pk11_get_session(context, OP_DIGEST, ISC_TRUE, ISC_FALSE,
++				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
++	PK11_FATALCHECK(pkcs_C_DigestInit, (context->session, &mech));
++}
++
++void
++isc_sha256_invalidate(isc_sha256_t *context) {
++	CK_BYTE garbage[ISC_SHA256_DIGESTLENGTH];
++	CK_ULONG len = ISC_SHA256_DIGESTLENGTH;
++
++	if (context->handle == NULL)
++		return;
++	(void) pkcs_C_DigestFinal(context->session, garbage, &len);
++	memset(garbage, 0, sizeof(garbage));
++	pk11_return_session(context);
++}
++
++void
++isc_sha256_update(isc_sha256_t *context, const isc_uint8_t* data, size_t len) {
++	CK_RV rv;
++	CK_BYTE_PTR pPart;
++
++	if (len == 0U) {
++		/* Calling with no data is valid - we do nothing */
++		return;
++	}
++
++	/* Sanity check: */
++	REQUIRE(context != (isc_sha256_t *)0 && data != (isc_uint8_t*)0);
++
++	DE_CONST(data, pPart);
++	PK11_FATALCHECK(pkcs_C_DigestUpdate,
++			(context->session, pPart, (CK_ULONG) len));
++}
++
++void
++isc_sha256_final(isc_uint8_t digest[], isc_sha256_t *context) {
++	CK_RV rv;
++	CK_ULONG len = ISC_SHA256_DIGESTLENGTH;
++
++	/* Sanity check: */
++	REQUIRE(context != (isc_sha256_t *)0);
++
++	/* If no digest buffer is passed, we don't bother doing this: */
++	if (digest != (isc_uint8_t*)0) {
++		PK11_FATALCHECK(pkcs_C_DigestFinal,
++				(context->session,
++				 (CK_BYTE_PTR) digest,
++				 &len));
++	} else {
++		CK_BYTE garbage[ISC_SHA256_DIGESTLENGTH];
++
++		(void) pkcs_C_DigestFinal(context->session, garbage, &len);
++		memset(garbage, 0, sizeof(garbage));
++	}
++	pk11_return_session(context);
++}
++
++void
++isc_sha512_init(isc_sha512_t *context) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_SHA512, NULL, 0 };
++
++	if (context == (isc_sha512_t *)0) {
++		return;
++	}
++	RUNTIME_CHECK(pk11_get_session(context, OP_DIGEST, ISC_TRUE, ISC_FALSE,
++				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
++	PK11_FATALCHECK(pkcs_C_DigestInit, (context->session, &mech));
++}
++
++void
++isc_sha512_invalidate(isc_sha512_t *context) {
++	CK_BYTE garbage[ISC_SHA512_DIGESTLENGTH];
++	CK_ULONG len = ISC_SHA512_DIGESTLENGTH;
++
++	if (context->handle == NULL)
++		return;
++	(void) pkcs_C_DigestFinal(context->session, garbage, &len);
++	memset(garbage, 0, sizeof(garbage));
++	pk11_return_session(context);
++}
++
++void
++isc_sha512_update(isc_sha512_t *context, const isc_uint8_t* data, size_t len) {
++	CK_RV rv;
++	CK_BYTE_PTR pPart;
++
++	if (len == 0U) {
++		/* Calling with no data is valid - we do nothing */
++		return;
++	}
++
++	/* Sanity check: */
++	REQUIRE(context != (isc_sha512_t *)0 && data != (isc_uint8_t*)0);
++
++	DE_CONST(data, pPart);
++	PK11_FATALCHECK(pkcs_C_DigestUpdate,
++			(context->session, pPart, (CK_ULONG) len));
++}
++
++void
++isc_sha512_final(isc_uint8_t digest[], isc_sha512_t *context) {
++	CK_RV rv;
++	CK_ULONG len = ISC_SHA512_DIGESTLENGTH;
++
++	/* Sanity check: */
++	REQUIRE(context != (isc_sha512_t *)0);
++
++	/* If no digest buffer is passed, we don't bother doing this: */
++	if (digest != (isc_uint8_t*)0) {
++		PK11_FATALCHECK(pkcs_C_DigestFinal,
++				(context->session,
++				 (CK_BYTE_PTR) digest,
++				 &len));
++	} else {
++		CK_BYTE garbage[ISC_SHA512_DIGESTLENGTH];
++
++		(void) pkcs_C_DigestFinal(context->session, garbage, &len);
++		memset(garbage, 0, sizeof(garbage));
++	}
++	pk11_return_session(context);
++}
++
++void
++isc_sha384_init(isc_sha384_t *context) {
++	CK_RV rv;
++	CK_MECHANISM mech = { CKM_SHA384, NULL, 0 };
++
++	if (context == (isc_sha384_t *)0) {
++		return;
++	}
++	RUNTIME_CHECK(pk11_get_session(context, OP_DIGEST, ISC_TRUE, ISC_FALSE,
++				       ISC_FALSE, NULL, 0) == ISC_R_SUCCESS);
++	PK11_FATALCHECK(pkcs_C_DigestInit, (context->session, &mech));
++}
++
++void
++isc_sha384_invalidate(isc_sha384_t *context) {
++	CK_BYTE garbage[ISC_SHA384_DIGESTLENGTH];
++	CK_ULONG len = ISC_SHA384_DIGESTLENGTH;
++
++	if (context->handle == NULL)
++		return;
++	(void) pkcs_C_DigestFinal(context->session, garbage, &len);
++	memset(garbage, 0, sizeof(garbage));
++	pk11_return_session(context);
++}
++
++void
++isc_sha384_update(isc_sha384_t *context, const isc_uint8_t* data, size_t len) {
++	CK_RV rv;
++	CK_BYTE_PTR pPart;
++
++	if (len == 0U) {
++		/* Calling with no data is valid - we do nothing */
++		return;
++	}
++
++	/* Sanity check: */
++	REQUIRE(context != (isc_sha384_t *)0 && data != (isc_uint8_t*)0);
++
++	DE_CONST(data, pPart);
++	PK11_FATALCHECK(pkcs_C_DigestUpdate,
++			(context->session, pPart, (CK_ULONG) len));
++}
++
++void
++isc_sha384_final(isc_uint8_t digest[], isc_sha384_t *context) {
++	CK_RV rv;
++	CK_ULONG len = ISC_SHA384_DIGESTLENGTH;
++
++	/* Sanity check: */
++	REQUIRE(context != (isc_sha384_t *)0);
++
++	/* If no digest buffer is passed, we don't bother doing this: */
++	if (digest != (isc_uint8_t*)0) {
++		PK11_FATALCHECK(pkcs_C_DigestFinal,
++				(context->session,
++				 (CK_BYTE_PTR) digest,
++				 &len));
++	} else {
++		CK_BYTE garbage[ISC_SHA384_DIGESTLENGTH];
++
++		(void) pkcs_C_DigestFinal(context->session, garbage, &len);
++		memset(garbage, 0, sizeof(garbage));
++	}
++	pk11_return_session(context);
++}
++
+ #else
+ 
+ /*
+@@ -1312,6 +1583,8 @@ isc_sha224_end(isc_sha224_t *context, char buffer[]) {
+ 	} else {
+ #ifdef ISC_PLATFORM_OPENSSLHASH
+ 		EVP_MD_CTX_cleanup(context);
++#elif PKCS11CRYPTO
++		pk11_return_session(context);
+ #else
+ 		memset(context, 0, sizeof(*context));
+ #endif
+@@ -1351,6 +1624,8 @@ isc_sha256_end(isc_sha256_t *context, char buffer[]) {
+ 	} else {
+ #ifdef ISC_PLATFORM_OPENSSLHASH
+ 		EVP_MD_CTX_cleanup(context);
++#elif PKCS11CRYPTO
++		pk11_return_session(context);
+ #else
+ 		memset(context, 0, sizeof(*context));
+ #endif
+@@ -1390,6 +1665,8 @@ isc_sha512_end(isc_sha512_t *context, char buffer[]) {
+ 	} else {
+ #ifdef ISC_PLATFORM_OPENSSLHASH
+ 		EVP_MD_CTX_cleanup(context);
++#elif PKCS11CRYPTO
++		pk11_return_session(context);
+ #else
+ 		memset(context, 0, sizeof(*context));
+ #endif
+@@ -1429,6 +1706,8 @@ isc_sha384_end(isc_sha384_t *context, char buffer[]) {
+ 	} else {
+ #ifdef ISC_PLATFORM_OPENSSLHASH
+ 		EVP_MD_CTX_cleanup(context);
++#elif PKCS11CRYPTO
++		pk11_return_session(context);
+ #else
+ 		memset(context, 0, sizeof(*context));
+ #endif
+diff --git a/lib/isc/unix/Makefile.in b/lib/isc/unix/Makefile.in
+index c1411cb..0595fa2 100644
+--- a/lib/isc/unix/Makefile.in
++++ b/lib/isc/unix/Makefile.in
+@@ -29,14 +29,14 @@ CDEFINES =
+ CWARNINGS =
+ 
+ # Alphabetically
+-OBJS =		@ISC_IPV6_O@ \
++OBJS =		@ISC_IPV6_O@ @ISC_PK11_API_O@ \
+ 		app.@O@ dir.@O@ entropy.@O@ errno2result.@O@ file.@O@ \
+ 		fsaccess.@O@ interfaceiter.@O@ keyboard.@O@ net.@O@ \
+ 		os.@O@ resource.@O@ socket.@O@ stdio.@O@ stdtime.@O@ \
+ 		strerror.@O@ syslog.@O@ time.@O@
+ 
+ # Alphabetically
+-SRCS =		@ISC_IPV6_C@ \
++SRCS =		@ISC_IPV6_C@ @ISC_PK11_API_C@ \
+ 		app.c dir.c entropy.c errno2result.c file.c \
+ 		fsaccess.c interfaceiter.c keyboard.c net.c \
+ 		os.c resource.c socket.c stdio.c stdtime.c \
+diff --git a/lib/isc/unix/include/Makefile.in b/lib/isc/unix/include/Makefile.in
+index 46c243e..354e6c8 100644
+--- a/lib/isc/unix/include/Makefile.in
++++ b/lib/isc/unix/include/Makefile.in
+@@ -19,7 +19,7 @@ srcdir =	@srcdir@
+ VPATH =		@srcdir@
+ top_srcdir =	@top_srcdir@
+ 
+-SUBDIRS =	isc
++SUBDIRS =	isc pkcs11
+ TARGETS =
+ 
+ @BIND9_MAKE_RULES@
+diff --git a/lib/isc/unix/include/pkcs11/Makefile.in b/lib/isc/unix/include/pkcs11/Makefile.in
+new file mode 100644
+index 0000000..8b175f4
+--- /dev/null
++++ b/lib/isc/unix/include/pkcs11/Makefile.in
+@@ -0,0 +1,33 @@
++# Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
++#
++# Permission to use, copy, modify, and/or distribute this software for any
++# purpose with or without fee is hereby granted, provided that the above
++# copyright notice and this permission notice appear in all copies.
++#
++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++# PERFORMANCE OF THIS SOFTWARE.
++
++# $Id: Makefile.in,v 1.4 2007/06/19 23:47:23 tbox Exp $
++
++srcdir =	@srcdir@
++VPATH =		@srcdir@
++top_srcdir =	@top_srcdir@
++
++HEADERS =	cryptoki.h
++SUBDIRS =
++TARGETS =
++
++@BIND9_MAKE_RULES@
++
++installdirs:
++	$(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/pkcs11
++
++install:: installdirs
++	for i in ${HEADERS}; do \
++		${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/pkcs11 ; \
++	done
+diff --git a/lib/isc/unix/include/pkcs11/cryptoki.h b/lib/isc/unix/include/pkcs11/cryptoki.h
+new file mode 100644
+index 0000000..7dc48b0
+--- /dev/null
++++ b/lib/isc/unix/include/pkcs11/cryptoki.h
+@@ -0,0 +1,66 @@
++/* cryptoki.h include file for PKCS #11. */
++/*
++ * Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++ * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++/* $Revision: 1.3 $ */
++
++/*
++ * Portions Copyright RSA Security Inc.
++ *
++ * License to copy and use this software is granted provided that it is
++ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
++ * (Cryptoki)" in all material mentioning or referencing this software.
++
++ * License is also granted to make and use derivative works provided that
++ * such works are identified as "derived from the RSA Security Inc. PKCS #11
++ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or 
++ * referencing the derived work.
++
++ * RSA Security Inc. makes no representations concerning either the 
++ * merchantability of this software or the suitability of this software for
++ * any particular purpose. It is provided "as is" without express or implied
++ * warranty of any kind.
++ */
++
++/* This is a sample file containing the top level include directives
++ * for building Unix Cryptoki libraries and applications.
++ */
++
++#ifndef ___CRYPTOKI_H_INC___
++#define ___CRYPTOKI_H_INC___
++
++#define CK_PTR *
++
++#define CK_DEFINE_FUNCTION(returnType, name) \
++  returnType name
++
++#define CK_DECLARE_FUNCTION(returnType, name) \
++  returnType name
++
++#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
++  returnType (* name)
++
++#define CK_CALLBACK_FUNCTION(returnType, name) \
++  returnType (* name)
++
++/* NULL is in unistd.h */
++#include <unistd.h>
++#define NULL_PTR NULL
++
++#undef CK_PKCS11_FUNCTION_INFO
++
++#include <pkcs11/pkcs11.h>
++
++#endif /* ___CRYPTOKI_H_INC___ */
+diff --git a/lib/isc/unix/pk11_api.c b/lib/isc/unix/pk11_api.c
+new file mode 100644
+index 0000000..9ccb959
+--- /dev/null
++++ b/lib/isc/unix/pk11_api.c
+@@ -0,0 +1,673 @@
++/*
++ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
++ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/* $Id$ */
++
++/*! \file */
++
++#include <config.h>
++
++#include <string.h>
++#include <dlfcn.h>
++
++#include <isc/log.h>
++#include <isc/mem.h>
++#include <isc/once.h>
++#include <isc/stdio.h>
++#include <isc/thread.h>
++#include <isc/util.h>
++
++#include <pkcs11/cryptoki.h>
++#include <pkcs11/pkcs11.h>
++
++#define KEEP_PKCS11_NAMES
++#include <pk11/pk11.h>
++#include <pk11/internal.h>
++
++static void *hPK11 = NULL;
++
++CK_RV
++pkcs_C_Initialize(CK_VOID_PTR pReserved) {
++	CK_C_Initialize sym;
++
++	if (hPK11 != NULL)
++		return (CKR_LIBRARY_ALREADY_INITIALIZED);
++
++	hPK11 = dlopen(pk11_get_lib_name(), RTLD_NOW);
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	sym = (CK_C_Initialize)dlsym(hPK11, "C_Initialize");
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(pReserved);
++}
++
++CK_RV
++pkcs_C_Finalize(CK_VOID_PTR pReserved) {
++	CK_C_Finalize sym;
++	CK_RV rv;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	sym = (CK_C_Finalize)dlsym(hPK11, "C_Finalize");
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	rv = (*sym)(pReserved);
++	if ((rv == CKR_OK) && (dlclose(hPK11) != 0))
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	hPK11 = NULL;
++	return (rv);
++}
++
++CK_RV
++pkcs_C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList,
++		   CK_ULONG_PTR pulCount)
++{
++	static CK_C_GetSlotList sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_GetSlotList)dlsym(hPK11, "C_GetSlotList");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(tokenPresent, pSlotList, pulCount);
++}
++
++CK_RV
++pkcs_C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) {
++	static CK_C_GetTokenInfo sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_GetTokenInfo)dlsym(hPK11, "C_GetTokenInfo");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(slotID, pInfo);
++}
++
++CK_RV
++pkcs_C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
++			CK_MECHANISM_INFO_PTR pInfo)
++{
++	static CK_C_GetMechanismInfo sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_GetMechanismInfo)dlsym(hPK11,
++						   "C_GetMechanismInfo");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(slotID, type, pInfo);
++}
++
++CK_RV
++pkcs_C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags,
++		   CK_VOID_PTR pApplication,
++		   CK_RV  (*Notify) (CK_SESSION_HANDLE hSession,
++				     CK_NOTIFICATION event,
++				     CK_VOID_PTR pApplication),
++		   CK_SESSION_HANDLE_PTR phSession)
++{
++	static CK_C_OpenSession sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		hPK11 = dlopen(pk11_get_lib_name(), RTLD_NOW);
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_OpenSession)dlsym(hPK11, "C_OpenSession");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(slotID, flags, pApplication, Notify, phSession);
++}
++
++CK_RV
++pkcs_C_CloseSession(CK_SESSION_HANDLE hSession) {
++	static CK_C_CloseSession sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_CloseSession)dlsym(hPK11, "C_CloseSession");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession);
++}
++
++CK_RV
++pkcs_C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
++	     CK_CHAR_PTR pPin, CK_ULONG usPinLen)
++{
++	static CK_C_Login sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_Login)dlsym(hPK11, "C_Login");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, userType, pPin, usPinLen);
++}
++
++CK_RV
++pkcs_C_Logout(CK_SESSION_HANDLE hSession) {
++	static CK_C_Logout sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_Logout)dlsym(hPK11, "C_Logout");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession);
++}
++
++CK_RV
++pkcs_C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
++		    CK_ULONG usCount, CK_OBJECT_HANDLE_PTR phObject)
++{
++	static CK_C_CreateObject sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_CreateObject)dlsym(hPK11, "C_CreateObject");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pTemplate, usCount, phObject);
++}
++
++CK_RV
++pkcs_C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) {
++	static CK_C_DestroyObject sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_DestroyObject)dlsym(hPK11, "C_DestroyObject");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, hObject);
++}
++
++CK_RV
++pkcs_C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
++			 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG usCount)
++{
++	static CK_C_GetAttributeValue sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_GetAttributeValue)dlsym(hPK11,
++						    "C_GetAttributeValue");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, hObject, pTemplate, usCount);
++}
++
++CK_RV
++pkcs_C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
++			 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG usCount)
++{
++	static CK_C_SetAttributeValue sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_SetAttributeValue)dlsym(hPK11,
++						    "C_SetAttributeValue");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, hObject, pTemplate, usCount);
++}
++
++CK_RV
++pkcs_C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
++		       CK_ULONG usCount)
++{
++	static CK_C_FindObjectsInit sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_FindObjectsInit)dlsym(hPK11, "C_FindObjectsInit");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pTemplate, usCount);
++}
++
++CK_RV
++pkcs_C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject,
++		   CK_ULONG usMaxObjectCount, CK_ULONG_PTR pusObjectCount)
++{
++	static CK_C_FindObjects sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_FindObjects)dlsym(hPK11, "C_FindObjects");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, phObject, usMaxObjectCount, pusObjectCount);
++}
++
++CK_RV
++pkcs_C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
++{
++	static CK_C_FindObjectsFinal sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_FindObjectsFinal)dlsym(hPK11,
++						   "C_FindObjectsFinal");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession);
++}
++
++CK_RV
++pkcs_C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
++		   CK_OBJECT_HANDLE hKey)
++{
++	static CK_C_EncryptInit sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_EncryptInit)dlsym(hPK11, "C_EncryptInit");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pMechanism, hKey);
++}
++
++CK_RV
++pkcs_C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
++	       CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData,
++	       CK_ULONG_PTR pulEncryptedDataLen)
++{
++	static CK_C_Encrypt sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_Encrypt)dlsym(hPK11, "C_Encrypt");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pData, ulDataLen,
++		      pEncryptedData, pulEncryptedDataLen);
++}
++
++CK_RV
++pkcs_C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) {
++	static CK_C_DigestInit sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_DigestInit)dlsym(hPK11, "C_DigestInit");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pMechanism);
++}
++
++CK_RV
++pkcs_C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
++		    CK_ULONG ulPartLen)
++{
++	static CK_C_DigestUpdate sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_DigestUpdate)dlsym(hPK11, "C_DigestUpdate");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pPart, ulPartLen);
++}
++
++CK_RV
++pkcs_C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest,
++		   CK_ULONG_PTR pulDigestLen)
++{
++	static CK_C_DigestFinal sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_DigestFinal)dlsym(hPK11, "C_DigestFinal");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pDigest, pulDigestLen);
++}
++
++CK_RV
++pkcs_C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
++		CK_OBJECT_HANDLE hKey)
++{
++	static CK_C_SignInit sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_SignInit)dlsym(hPK11, "C_SignInit");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pMechanism, hKey);
++}
++
++CK_RV
++pkcs_C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
++	    CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
++	    CK_ULONG_PTR pulSignatureLen)
++{
++	static CK_C_Sign sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_Sign)dlsym(hPK11, "C_Sign");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pData, ulDataLen, pSignature, pulSignatureLen);
++}
++
++CK_RV
++pkcs_C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
++		  CK_ULONG ulPartLen)
++{
++	static CK_C_SignUpdate sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_SignUpdate)dlsym(hPK11, "C_SignUpdate");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pPart, ulPartLen);
++}
++
++CK_RV
++pkcs_C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
++		 CK_ULONG_PTR pulSignatureLen)
++{
++	static CK_C_SignFinal sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_SignFinal)dlsym(hPK11, "C_SignFinal");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pSignature, pulSignatureLen);
++}
++
++CK_RV
++pkcs_C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
++		  CK_OBJECT_HANDLE hKey)
++{
++	static CK_C_VerifyInit sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_VerifyInit)dlsym(hPK11, "C_VerifyInit");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pMechanism, hKey);
++}
++
++CK_RV
++pkcs_C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
++	      CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
++	      CK_ULONG ulSignatureLen)
++{
++	static CK_C_Verify sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_Verify)dlsym(hPK11, "C_Verify");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pData, ulDataLen, pSignature, ulSignatureLen);
++}
++
++CK_RV
++pkcs_C_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
++		    CK_ULONG ulPartLen)
++{
++	static CK_C_VerifyUpdate sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_VerifyUpdate)dlsym(hPK11, "C_VerifyUpdate");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pPart, ulPartLen);
++}
++
++CK_RV
++pkcs_C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
++		   CK_ULONG ulSignatureLen)
++{
++	static CK_C_VerifyFinal sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_VerifyFinal)dlsym(hPK11, "C_VerifyFinal");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pSignature, ulSignatureLen);
++}
++
++CK_RV
++pkcs_C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
++		   CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
++		   CK_OBJECT_HANDLE_PTR phKey)
++{
++	static CK_C_GenerateKey sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_GenerateKey)dlsym(hPK11, "C_GenerateKey");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pMechanism, pTemplate, ulCount, phKey);
++}
++
++CK_RV
++pkcs_C_GenerateKeyPair(CK_SESSION_HANDLE hSession,
++		       CK_MECHANISM_PTR pMechanism,
++		       CK_ATTRIBUTE_PTR pPublicKeyTemplate,
++		       CK_ULONG usPublicKeyAttributeCount,
++		       CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
++		       CK_ULONG usPrivateKeyAttributeCount,
++		       CK_OBJECT_HANDLE_PTR phPrivateKey,
++		       CK_OBJECT_HANDLE_PTR phPublicKey)
++{
++	static CK_C_GenerateKeyPair sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_GenerateKeyPair)dlsym(hPK11, "C_GenerateKeyPair");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession,
++		      pMechanism,
++		      pPublicKeyTemplate,
++		      usPublicKeyAttributeCount,
++		      pPrivateKeyTemplate,
++		      usPrivateKeyAttributeCount,
++		      phPrivateKey,
++		      phPublicKey);
++}
++
++CK_RV
++pkcs_C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
++		 CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
++		 CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
++{
++	static CK_C_DeriveKey sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_DeriveKey)dlsym(hPK11, "C_DeriveKey");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession,
++		      pMechanism,
++		      hBaseKey,
++		      pTemplate,
++		      ulAttributeCount,
++		      phKey);
++}
++
++CK_RV
++pkcs_C_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed,
++		  CK_ULONG ulSeedLen)
++{
++	static CK_C_SeedRandom sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_SeedRandom)dlsym(hPK11, "C_SeedRandom");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, pSeed, ulSeedLen);
++}
++
++CK_RV
++pkcs_C_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR RandomData,
++		      CK_ULONG ulRandomLen)
++{
++	static CK_C_GenerateRandom sym = NULL;
++	static void *pPK11 = NULL;
++
++	if (hPK11 == NULL)
++		return (CKR_LIBRARY_FAILED_TO_LOAD);
++	if ((sym == NULL) || (hPK11 != pPK11)) {
++		pPK11 = hPK11;
++		sym = (CK_C_GenerateRandom)dlsym(hPK11, "C_GenerateRandom");
++	}
++	if (sym == NULL)
++		return (CKR_SYMBOL_RESOLUTION_FAILED);
++	return (*sym)(hSession, RandomData, ulRandomLen);
++}
+-- 
+2.1.0
+
diff --git a/SOURCES/bind97-dist-pkcs11.patch b/SOURCES/bind97-dist-pkcs11.patch
deleted file mode 100644
index cf8c9f0..0000000
--- a/SOURCES/bind97-dist-pkcs11.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-diff -up bind-9.7.0b1/configure.in.dist-pkcs11 bind-9.7.0b1/configure.in
---- bind-9.7.0b1/configure.in.dist-pkcs11	2009-11-03 11:37:25.481430279 +0100
-+++ bind-9.7.0b1/configure.in	2009-11-03 11:41:04.573930858 +0100
-@@ -721,15 +721,16 @@ AC_ARG_WITH(pkcs11,
- case "$use_pkcs11" in
- 	no|'')
- 		AC_MSG_RESULT(disabled)
--		USE_PKCS11=''
- 		PKCS11_TOOLS=''
- 		;;
- 	yes|*)
- 		AC_MSG_RESULT(using OpenSSL with PKCS11 support)
--		USE_PKCS11='-DUSE_PKCS11'
- 		PKCS11_TOOLS=pkcs11
- 		;;
- esac
-+# We don't want to automatically load engine because it needs to have openct,
-+# opencryptoki and friends installed.
-+USE_PKCS11=''
- AC_SUBST(USE_PKCS11)
- AC_SUBST(PKCS11_TOOLS)
- 
diff --git a/SOURCES/bind99-CVE-2015-5722.patch b/SOURCES/bind99-CVE-2015-5722.patch
new file mode 100644
index 0000000..bb240ac
--- /dev/null
+++ b/SOURCES/bind99-CVE-2015-5722.patch
@@ -0,0 +1,449 @@
+diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c
+index 7a56c79..3ac01a8 100644
+--- a/lib/dns/hmac_link.c
++++ b/lib/dns/hmac_link.c
+@@ -76,7 +76,7 @@ hmacmd5_createctx(dst_key_t *key, dst_context_t *dctx) {
+ 	hmacmd5ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacmd5_t));
+ 	if (hmacmd5ctx == NULL)
+ 		return (ISC_R_NOMEMORY);
+-	isc_hmacmd5_init(hmacmd5ctx, hkey->key, ISC_SHA1_BLOCK_LENGTH);
++	isc_hmacmd5_init(hmacmd5ctx, hkey->key, ISC_MD5_BLOCK_LENGTH);
+ 	dctx->ctxdata.hmacmd5ctx = hmacmd5ctx;
+ 	return (ISC_R_SUCCESS);
+ }
+@@ -139,7 +139,7 @@ hmacmd5_compare(const dst_key_t *key1, const dst_key_t *key2) {
+ 	else if (hkey1 == NULL || hkey2 == NULL)
+ 		return (ISC_FALSE);
+ 
+-	if (isc_safe_memcmp(hkey1->key, hkey2->key, ISC_SHA1_BLOCK_LENGTH))
++	if (isc_safe_memcmp(hkey1->key, hkey2->key, ISC_MD5_BLOCK_LENGTH))
+ 		return (ISC_TRUE);
+ 	else
+ 		return (ISC_FALSE);
+@@ -150,17 +150,17 @@ hmacmd5_generate(dst_key_t *key, int pseudorandom_ok, void (*callback)(int)) {
+ 	isc_buffer_t b;
+ 	isc_result_t ret;
+ 	unsigned int bytes;
+-	unsigned char data[ISC_SHA1_BLOCK_LENGTH];
++	unsigned char data[ISC_MD5_BLOCK_LENGTH];
+ 
+ 	UNUSED(callback);
+ 
+ 	bytes = (key->key_size + 7) / 8;
+-	if (bytes > ISC_SHA1_BLOCK_LENGTH) {
+-		bytes = ISC_SHA1_BLOCK_LENGTH;
+-		key->key_size = ISC_SHA1_BLOCK_LENGTH * 8;
++	if (bytes > ISC_MD5_BLOCK_LENGTH) {
++		bytes = ISC_MD5_BLOCK_LENGTH;
++		key->key_size = ISC_MD5_BLOCK_LENGTH * 8;
+ 	}
+ 
+-	memset(data, 0, ISC_SHA1_BLOCK_LENGTH);
++	memset(data, 0, ISC_MD5_BLOCK_LENGTH);
+ 	ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0));
+ 
+ 	if (ret != ISC_R_SUCCESS)
+@@ -169,7 +169,7 @@ hmacmd5_generate(dst_key_t *key, int pseudorandom_ok, void (*callback)(int)) {
+ 	isc_buffer_init(&b, data, bytes);
+ 	isc_buffer_add(&b, bytes);
+ 	ret = hmacmd5_fromdns(key, &b);
+-	memset(data, 0, ISC_SHA1_BLOCK_LENGTH);
++	memset(data, 0, ISC_MD5_BLOCK_LENGTH);
+ 
+ 	return (ret);
+ }
+@@ -223,7 +223,7 @@ hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 
+ 	memset(hkey->key, 0, sizeof(hkey->key));
+ 
+-	if (r.length > ISC_SHA1_BLOCK_LENGTH) {
++	if (r.length > ISC_MD5_BLOCK_LENGTH) {
+ 		isc_md5_init(&md5ctx);
+ 		isc_md5_update(&md5ctx, r.base, r.length);
+ 		isc_md5_final(&md5ctx, hkey->key);
+@@ -237,6 +237,8 @@ hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 	key->key_size = keylen * 8;
+ 	key->keydata.hmacmd5 = hkey;
+ 
++	isc_buffer_forward(data, r.length);
++
+ 	return (ISC_R_SUCCESS);
+ }
+ 
+@@ -518,6 +520,8 @@ hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 	key->key_size = keylen * 8;
+ 	key->keydata.hmacsha1 = hkey;
+ 
++	isc_buffer_forward(data, r.length);
++
+ 	return (ISC_R_SUCCESS);
+ }
+ 
+@@ -804,6 +808,8 @@ hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 	key->key_size = keylen * 8;
+ 	key->keydata.hmacsha224 = hkey;
+ 
++	isc_buffer_forward(data, r.length);
++
+ 	return (ISC_R_SUCCESS);
+ }
+ 
+@@ -1090,6 +1096,8 @@ hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 	key->key_size = keylen * 8;
+ 	key->keydata.hmacsha256 = hkey;
+ 
++	isc_buffer_forward(data, r.length);
++
+ 	return (ISC_R_SUCCESS);
+ }
+ 
+@@ -1376,6 +1384,8 @@ hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 	key->key_size = keylen * 8;
+ 	key->keydata.hmacsha384 = hkey;
+ 
++	isc_buffer_forward(data, r.length);
++
+ 	return (ISC_R_SUCCESS);
+ }
+ 
+@@ -1662,6 +1672,8 @@ hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 	key->key_size = keylen * 8;
+ 	key->keydata.hmacsha512 = hkey;
+ 
++	isc_buffer_forward(data, r.length);
++
+ 	return (ISC_R_SUCCESS);
+ }
+ 
+diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h
+index bdbd269..37853aa 100644
+--- a/lib/dns/include/dst/dst.h
++++ b/lib/dns/include/dst/dst.h
+@@ -69,6 +69,7 @@ typedef struct dst_context 	dst_context_t;
+ #define DST_ALG_HMACSHA256	163	/* XXXMPA */
+ #define DST_ALG_HMACSHA384	164	/* XXXMPA */
+ #define DST_ALG_HMACSHA512	165	/* XXXMPA */
++#define DST_ALG_INDIRECT	252
+ #define DST_ALG_PRIVATE		254
+ #define DST_ALG_EXPAND		255
+ #define DST_MAX_ALGS		255
+diff --git a/lib/dns/ncache.c b/lib/dns/ncache.c
+index bcb3d05..3114954 100644
+--- a/lib/dns/ncache.c
++++ b/lib/dns/ncache.c
+@@ -614,13 +614,11 @@ dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
+ 		dns_name_fromregion(&tname, &remaining);
+ 		INSIST(remaining.length >= tname.length);
+ 		isc_buffer_forward(&source, tname.length);
+-		remaining.length -= tname.length;
+-		remaining.base += tname.length;
++		isc_region_consume(&remaining, tname.length);
+ 
+ 		INSIST(remaining.length >= 2);
+ 		type = isc_buffer_getuint16(&source);
+-		remaining.length -= 2;
+-		remaining.base += 2;
++		isc_region_consume(&remaining, 2);
+ 
+ 		if (type != dns_rdatatype_rrsig ||
+ 		    !dns_name_equal(&tname, name)) {
+@@ -632,8 +630,7 @@ dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
+ 		INSIST(remaining.length >= 1);
+ 		trust = isc_buffer_getuint8(&source);
+ 		INSIST(trust <= dns_trust_ultimate);
+-		remaining.length -= 1;
+-		remaining.base += 1;
++		isc_region_consume(&remaining, 1);
+ 
+ 		raw = remaining.base;
+ 		count = raw[0] * 256 + raw[1];
+diff --git a/lib/dns/openssldh_link.c b/lib/dns/openssldh_link.c
+index 55752da..f0cee8d 100644
+--- a/lib/dns/openssldh_link.c
++++ b/lib/dns/openssldh_link.c
+@@ -266,8 +266,10 @@ openssldh_destroy(dst_key_t *key) {
+ 
+ static void
+ uint16_toregion(isc_uint16_t val, isc_region_t *region) {
+-	*region->base++ = (val & 0xff00) >> 8;
+-	*region->base++ = (val & 0x00ff);
++	*region->base = (val & 0xff00) >> 8;
++	isc_region_consume(region, 1);
++	*region->base = (val & 0x00ff);
++	isc_region_consume(region, 1);
+ }
+ 
+ static isc_uint16_t
+@@ -278,7 +280,8 @@ uint16_fromregion(isc_region_t *region) {
+ 	val = ((unsigned int)(cp[0])) << 8;
+ 	val |= ((unsigned int)(cp[1]));
+ 
+-	region->base += 2;
++	isc_region_consume(region, 2);
++
+ 	return (val);
+ }
+ 
+@@ -319,16 +322,16 @@ openssldh_todns(const dst_key_t *key, isc_buffer_t *data) {
+ 	}
+ 	else
+ 		BN_bn2bin(dh->p, r.base);
+-	r.base += plen;
++	isc_region_consume(&r, plen);
+ 
+ 	uint16_toregion(glen, &r);
+ 	if (glen > 0)
+ 		BN_bn2bin(dh->g, r.base);
+-	r.base += glen;
++	isc_region_consume(&r, glen);
+ 
+ 	uint16_toregion(publen, &r);
+ 	BN_bn2bin(dh->pub_key, r.base);
+-	r.base += publen;
++	isc_region_consume(&r, publen);
+ 
+ 	isc_buffer_add(data, dnslen);
+ 
+@@ -369,10 +372,12 @@ openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 		return (DST_R_INVALIDPUBLICKEY);
+ 	}
+ 	if (plen == 1 || plen == 2) {
+-		if (plen == 1)
+-			special = *r.base++;
+-		else
++		if (plen == 1) {
++			special = *r.base;
++			isc_region_consume(&r, 1);
++		} else {
+ 			special = uint16_fromregion(&r);
++		}
+ 		switch (special) {
+ 			case 1:
+ 				dh->p = &bn768;
+@@ -387,10 +392,9 @@ openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 				DH_free(dh);
+ 				return (DST_R_INVALIDPUBLICKEY);
+ 		}
+-	}
+-	else {
++	} else {
+ 		dh->p = BN_bin2bn(r.base, plen, NULL);
+-		r.base += plen;
++		isc_region_consume(&r, plen);
+ 	}
+ 
+ 	/*
+@@ -421,15 +425,14 @@ openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 				return (DST_R_INVALIDPUBLICKEY);
+ 			}
+ 		}
+-	}
+-	else {
++	} else {
+ 		if (glen == 0) {
+ 			DH_free(dh);
+ 			return (DST_R_INVALIDPUBLICKEY);
+ 		}
+ 		dh->g = BN_bin2bn(r.base, glen, NULL);
+ 	}
+-	r.base += glen;
++	isc_region_consume(&r, glen);
+ 
+ 	if (r.length < 2) {
+ 		DH_free(dh);
+@@ -441,7 +444,7 @@ openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 		return (DST_R_INVALIDPUBLICKEY);
+ 	}
+ 	dh->pub_key = BN_bin2bn(r.base, publen, NULL);
+-	r.base += publen;
++	isc_region_consume(&r, publen);
+ 
+ 	key->key_size = BN_num_bits(dh->p);
+ 
+diff --git a/lib/dns/openssldsa_link.c b/lib/dns/openssldsa_link.c
+index fd6e91e..8e16557 100644
+--- a/lib/dns/openssldsa_link.c
++++ b/lib/dns/openssldsa_link.c
+@@ -137,6 +135,7 @@ openssldsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
+ 	DSA *dsa = key->keydata.dsa;
+ 	isc_region_t r;
+ 	DSA_SIG *dsasig;
++	unsigned int klen;
+ #if USE_EVP
+ 	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
+ 	EVP_PKEY *pkey;
+@@ -209,11 +209,17 @@ openssldsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
+ 					       "DSA_do_sign",
+ 					       DST_R_SIGNFAILURE));
+ #endif
+-	*r.base++ = (key->key_size - 512)/64;
++
++	klen = (key->key_size - 512)/64;
++	if (klen > 255)
++		return (ISC_R_FAILURE);
++	*r.base = klen;
++	isc_region_consume(&r, 1);
++
+ 	BN_bn2bin_fixed(dsasig->r, r.base, ISC_SHA1_DIGESTLENGTH);
+-	r.base += ISC_SHA1_DIGESTLENGTH;
++	isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH);
+ 	BN_bn2bin_fixed(dsasig->s, r.base, ISC_SHA1_DIGESTLENGTH);
+-	r.base += ISC_SHA1_DIGESTLENGTH;
++	isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH);
+ 	DSA_SIG_free(dsasig);
+ 	isc_buffer_add(sig, ISC_SHA1_DIGESTLENGTH * 2 + 1);
+ 
+@@ -446,15 +452,16 @@ openssldsa_todns(const dst_key_t *key, isc_buffer_t *data) {
+ 	if (r.length < (unsigned int) dnslen)
+ 		return (ISC_R_NOSPACE);
+ 
+-	*r.base++ = t;
++	*r.base = t;
++	isc_region_consume(&r, 1);
+ 	BN_bn2bin_fixed(dsa->q, r.base, ISC_SHA1_DIGESTLENGTH);
+-	r.base += ISC_SHA1_DIGESTLENGTH;
++	isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH);
+ 	BN_bn2bin_fixed(dsa->p, r.base, key->key_size/8);
+-	r.base += p_bytes;
++	isc_region_consume(&r, p_bytes);
+ 	BN_bn2bin_fixed(dsa->g, r.base, key->key_size/8);
+-	r.base += p_bytes;
++	isc_region_consume(&r, p_bytes);
+ 	BN_bn2bin_fixed(dsa->pub_key, r.base, key->key_size/8);
+-	r.base += p_bytes;
++	isc_region_consume(&r, p_bytes);
+ 
+ 	isc_buffer_add(data, dnslen);
+ 
+@@ -479,29 +486,30 @@ openssldsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 		return (ISC_R_NOMEMORY);
+ 	dsa->flags &= ~DSA_FLAG_CACHE_MONT_P;
+ 
+-	t = (unsigned int) *r.base++;
++	t = (unsigned int) *r.base;
++	isc_region_consume(&r, 1);
+ 	if (t > 8) {
+ 		DSA_free(dsa);
+ 		return (DST_R_INVALIDPUBLICKEY);
+ 	}
+ 	p_bytes = 64 + 8 * t;
+ 
+-	if (r.length < 1 + ISC_SHA1_DIGESTLENGTH + 3 * p_bytes) {
++	if (r.length < ISC_SHA1_DIGESTLENGTH + 3 * p_bytes) {
+ 		DSA_free(dsa);
+ 		return (DST_R_INVALIDPUBLICKEY);
+ 	}
+ 
+ 	dsa->q = BN_bin2bn(r.base, ISC_SHA1_DIGESTLENGTH, NULL);
+-	r.base += ISC_SHA1_DIGESTLENGTH;
++	isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH);
+ 
+ 	dsa->p = BN_bin2bn(r.base, p_bytes, NULL);
+-	r.base += p_bytes;
++	isc_region_consume(&r, p_bytes);
+ 
+ 	dsa->g = BN_bin2bn(r.base, p_bytes, NULL);
+-	r.base += p_bytes;
++	isc_region_consume(&r, p_bytes);
+ 
+ 	dsa->pub_key = BN_bin2bn(r.base, p_bytes, NULL);
+-	r.base += p_bytes;
++	isc_region_consume(&r, p_bytes);
+ 
+ 	key->key_size = p_bytes * 8;
+ 
+diff --git a/lib/dns/opensslecdsa_link.c b/lib/dns/opensslecdsa_link.c
+index c64cc55..40c612b 100644
+--- a/lib/dns/opensslecdsa_link.c
++++ b/lib/dns/opensslecdsa_link.c
+@@ -159,9 +157,9 @@ opensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
+ 					       "ECDSA_do_sign",
+ 					       DST_R_SIGNFAILURE));
+ 	BN_bn2bin_fixed(ecdsasig->r, r.base, siglen / 2);
+-	r.base += siglen / 2;
++	isc_region_consume(&r, siglen / 2);
+ 	BN_bn2bin_fixed(ecdsasig->s, r.base, siglen / 2);
+-	r.base += siglen / 2;
++	isc_region_consume(&r, siglen / 2);
+ 	ECDSA_SIG_free(ecdsasig);
+ 	isc_buffer_add(sig, siglen);
+ 	ret = ISC_R_SUCCESS;
+diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c
+index 1edeb8d..53c6d4b 100644
+--- a/lib/dns/opensslrsa_link.c
++++ b/lib/dns/opensslrsa_link.c
+@@ -965,6 +965,7 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 	RSA *rsa;
+ 	isc_region_t r;
+ 	unsigned int e_bytes;
++	unsigned int length;
+ #if USE_EVP
+ 	EVP_PKEY *pkey;
+ #endif
+@@ -972,6 +973,7 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 	isc_buffer_remainingregion(data, &r);
+ 	if (r.length == 0)
+ 		return (ISC_R_SUCCESS);
++	length = r.length;
+ 
+ 	rsa = RSA_new();
+ 	if (rsa == NULL)
+@@ -982,17 +984,18 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 		RSA_free(rsa);
+ 		return (DST_R_INVALIDPUBLICKEY);
+ 	}
+-	e_bytes = *r.base++;
+-	r.length--;
++	e_bytes = *r.base;
++	isc_region_consume(&r, 1);
+ 
+ 	if (e_bytes == 0) {
+ 		if (r.length < 2) {
+ 			RSA_free(rsa);
+ 			return (DST_R_INVALIDPUBLICKEY);
+ 		}
+-		e_bytes = ((*r.base++) << 8);
+-		e_bytes += *r.base++;
+-		r.length -= 2;
++		e_bytes = (*r.base) << 8;
++		isc_region_consume(&r, 1);
++		e_bytes += *r.base;
++		isc_region_consume(&r, 1);
+ 	}
+ 
+ 	if (r.length < e_bytes) {
+@@ -1000,14 +1003,13 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
+ 		return (DST_R_INVALIDPUBLICKEY);
+ 	}
+ 	rsa->e = BN_bin2bn(r.base, e_bytes, NULL);
+-	r.base += e_bytes;
+-	r.length -= e_bytes;
++	isc_region_consume(&r, e_bytes);
+ 
+ 	rsa->n = BN_bin2bn(r.base, r.length, NULL);
+ 
+ 	key->key_size = BN_num_bits(rsa->n);
+ 
+-	isc_buffer_forward(data, r.length);
++	isc_buffer_forward(data, length);
+ 
+ #if USE_EVP
+ 	pkey = EVP_PKEY_new();
+diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
+index 2004b0b..c7971b1 100644
+--- a/lib/dns/resolver.c
++++ b/lib/dns/resolver.c
+@@ -8959,6 +8959,12 @@ dns_resolver_algorithm_supported(dns_resolver_t *resolver, dns_name_t *name,
+ 
+ 	REQUIRE(VALID_RESOLVER(resolver));
+ 
++	/*
++	 * DH is unsupported for DNSKEYs, see RFC 4034 sec. A.1.
++	 */
++	if ((alg == DST_ALG_DH) || (alg == DST_ALG_INDIRECT))
++		return (ISC_FALSE);
++
+ #if USE_ALGLOCK
+ 	RWLOCK(&resolver->alglock, isc_rwlocktype_read);
+ #endif
+ 
diff --git a/SOURCES/bind99-coverity-fixes.patch b/SOURCES/bind99-coverity-fixes.patch
new file mode 100644
index 0000000..0e60017
--- /dev/null
+++ b/SOURCES/bind99-coverity-fixes.patch
@@ -0,0 +1,307 @@
+From 127701d9d32e568f09c775e722286e9c0b8c72ec Mon Sep 17 00:00:00 2001
+From: Tomas Hozza <thozza@redhat.com>
+Date: Fri, 22 May 2015 16:56:25 +0200
+Subject: [PATCH] Fix coverity issues
+
+http://cov01.lab.eng.brq.redhat.com/covscanhub/waiving/9377/
+Signed-off-by: Tomas Hozza <thozza@redhat.com>
+---
+ bin/named/server.c |  8 +++-----
+ lib/dns/dispatch.c |  5 +++--
+ lib/dns/dst_api.c  |  6 ++++++
+ lib/dns/gen.c      | 16 +++++++++++++++-
+ lib/dns/name.c     |  8 ++------
+ lib/dns/nsec3.c    |  4 ++--
+ lib/dns/rcode.c    |  4 +++-
+ lib/isc/netaddr.c  |  1 +
+ lib/isc/pk11.c     | 21 ++++++++++++++-------
+ 9 files changed, 49 insertions(+), 24 deletions(-)
+
+diff --git a/bin/named/server.c b/bin/named/server.c
+index 227c646..5e94660 100644
+--- a/bin/named/server.c
++++ b/bin/named/server.c
+@@ -8018,9 +8018,11 @@ ns_server_sync(ns_server_t *server, char *args, isc_buffer_t *text) {
+ 	dns_zone_t *zone = NULL;
+ 	char classstr[DNS_RDATACLASS_FORMATSIZE];
+ 	char zonename[DNS_NAME_FORMATSIZE];
+-	const char *vname, *sep, *msg = NULL, *arg;
++	const char *vname, *sep, *arg;
+ 	isc_boolean_t cleanup = ISC_FALSE;
+ 
++	UNUSED(text);
++
+ 	(void) next_token(&args, " \t");
+ 
+ 	arg = next_token(&args, " \t");
+@@ -8061,10 +8063,6 @@ ns_server_sync(ns_server_t *server, char *args, isc_buffer_t *text) {
+ 	result = synczone(zone, &cleanup);
+ 	isc_task_endexclusive(server->task);
+ 
+-	if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text))
+-		isc_buffer_putmem(text, (const unsigned char *)msg,
+-				  strlen(msg) + 1);
+-
+ 	view = dns_zone_getview(zone);
+ 	if (strcmp(view->name, "_default") == 0 ||
+ 	    strcmp(view->name, "_bind") == 0)
+diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c
+index 5063914..c93651d 100644
+--- a/lib/dns/dispatch.c
++++ b/lib/dns/dispatch.c
+@@ -2278,9 +2278,10 @@ dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr,
+ 
+ 	/* Create or adjust socket pool */
+ 	if (mgr->spool != NULL) {
+-		if (maxrequests < DNS_DISPATCH_POOLSOCKS * 2)
++		if (maxrequests < DNS_DISPATCH_POOLSOCKS * 2) {
+ 		  isc_mempool_setmaxalloc(mgr->spool, DNS_DISPATCH_POOLSOCKS * 2);
+ 		  isc_mempool_setfreemax(mgr->spool, DNS_DISPATCH_POOLSOCKS * 2);
++		}
+ 		UNLOCK(&mgr->buffer_lock);
+ 		return (ISC_R_SUCCESS);
+ 	}
+@@ -3765,7 +3766,7 @@ dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr,
+ 		goto fail_alloc;
+ 
+ 	dset->dispatches = isc_mem_get(mctx, sizeof(dns_dispatch_t *) * n);
+-	if (dset == NULL) {
++	if (dset->dispatches == NULL) {
+ 		result = ISC_R_NOMEMORY;
+ 		goto fail_lock;
+ 	}
+diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c
+index d96473f..e71f202 100644
+--- a/lib/dns/dst_api.c
++++ b/lib/dns/dst_api.c
+@@ -1882,6 +1882,9 @@ dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) {
+ #ifdef BIND9
+ 	unsigned int flags = dst_entropy_flags;
+ 
++	if (dst_entropy_pool == NULL)
++		return (ISC_R_FAILURE);
++
+ 	if (len == 0)
+ 		return (ISC_R_SUCCESS);
+ 
+@@ -1914,6 +1917,9 @@ dst__entropy_status(void) {
+ 	unsigned char buf[32];
+ 	static isc_boolean_t first = ISC_TRUE;
+ 
++	if (dst_entropy_pool == NULL)
++		return (0);
++
+ 	if (first) {
+ 		/* Someone believes RAND_status() initializes the PRNG */
+ 		flags &= ~ISC_ENTROPY_GOODONLY;
+diff --git a/lib/dns/gen.c b/lib/dns/gen.c
+index 6b533dd..548f892 100644
+--- a/lib/dns/gen.c
++++ b/lib/dns/gen.c
+@@ -335,10 +335,14 @@ insert_into_typenames(int type, const char *typename, const char *attr) {
+ 			typename);
+ 		exit(1);
+ 	}
++
+ 	strncpy(ttn->typename, typename, sizeof(ttn->typename));
+-	ttn->type = type;
++	ttn->typename[sizeof(ttn->typename) - 1] = '\0';
+ 
+ 	strncpy(ttn->macroname, ttn->typename, sizeof(ttn->macroname));
++	ttn->macroname[sizeof(ttn->macroname) - 1] = '\0';
++
++	ttn->type = type;
+ 	c = strlen(ttn->macroname);
+ 	while (c > 0) {
+ 		if (ttn->macroname[c - 1] == '-')
+@@ -364,7 +368,10 @@ insert_into_typenames(int type, const char *typename, const char *attr) {
+ 			attr, typename);
+ 		exit(1);
+ 	}
++
+ 	strncpy(ttn->attr, attr, sizeof(ttn->attr));
++	ttn->attr[sizeof(ttn->attr) - 1] = '\0';
++
+ 	ttn->sorted = 0;
+ 	if (maxtype < type)
+ 		maxtype = type;
+@@ -393,11 +400,17 @@ add(int rdclass, const char *classname, int type, const char *typename,
+ 	newtt->next = NULL;
+ 	newtt->rdclass = rdclass;
+ 	newtt->type = type;
++
+ 	strncpy(newtt->classname, classname, sizeof(newtt->classname));
++	newtt->classname[sizeof(newtt->classname) - 1] = '\0';
++
+ 	strncpy(newtt->typename, typename, sizeof(newtt->typename));
++	newtt->typename[sizeof(newtt->typename) - 1] = '\0';
++
+ 	if (strncmp(dirname, "./", 2) == 0)
+ 		dirname += 2;
+ 	strncpy(newtt->dirname, dirname, sizeof(newtt->dirname));
++	newtt->dirname[sizeof(newtt->dirname) - 1] = '\0';
+ 
+ 	tt = types;
+ 	oldtt = NULL;
+@@ -436,6 +449,7 @@ add(int rdclass, const char *classname, int type, const char *typename,
+ 	}
+ 	newcc->rdclass = rdclass;
+ 	strncpy(newcc->classname, classname, sizeof(newcc->classname));
++	newcc->classname[sizeof(newcc->classname) - 1] = '\0';
+ 	cc = classes;
+ 	oldcc = NULL;
+ 
+diff --git a/lib/dns/name.c b/lib/dns/name.c
+index 4fcabb1..93173ee 100644
+--- a/lib/dns/name.c
++++ b/lib/dns/name.c
+@@ -1859,7 +1859,6 @@ dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
+ 				    0)
+ 					return (DNS_R_DISALLOWED);
+ 				new_current = c & 0x3F;
+-				n = 1;
+ 				state = fw_newcurrent;
+ 			} else
+ 				return (DNS_R_BADLABELTYPE);
+@@ -1867,8 +1866,6 @@ dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
+ 		case fw_ordinary:
+ 			if (downcase)
+ 				c = maptolower[c];
+-			/* FALLTHROUGH */
+-		case fw_copy:
+ 			*ndata++ = c;
+ 			n--;
+ 			if (n == 0)
+@@ -1877,9 +1874,6 @@ dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
+ 		case fw_newcurrent:
+ 			new_current *= 256;
+ 			new_current += c;
+-			n--;
+-			if (n != 0)
+-				break;
+ 			if (new_current >= biggest_pointer)
+ 				return (DNS_R_BADPOINTER);
+ 			biggest_pointer = new_current;
+@@ -2398,6 +2392,8 @@ dns_name_tostring(dns_name_t *name, char **target, isc_mem_t *mctx) {
+ 
+ 	isc_buffer_usedregion(&buf, &reg);
+ 	p = isc_mem_allocate(mctx, reg.length + 1);
++	if (p == NULL)
++		return (ISC_R_NOMEMORY);
+ 	memcpy(p, (char *) reg.base, (int) reg.length);
+ 	p[reg.length] = '\0';
+ 
+diff --git a/lib/dns/nsec3.c b/lib/dns/nsec3.c
+index 935f515..86fad33 100644
+--- a/lib/dns/nsec3.c
++++ b/lib/dns/nsec3.c
+@@ -842,8 +842,8 @@ dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version,
+ 		dns_db_detachnode(db, &newnode);
+ 	} while (1);
+ 
+-	if (result == ISC_R_NOMORE)
+-		result = ISC_R_SUCCESS;
++	/* result cannot be ISC_R_NOMORE here */
++	INSIST(result != ISC_R_NOMORE);
+ 
+  failure:
+ 	if (dbit != NULL)
+diff --git a/lib/dns/rcode.c b/lib/dns/rcode.c
+index 0b7fe8c..091b3c7 100644
+--- a/lib/dns/rcode.c
++++ b/lib/dns/rcode.c
+@@ -216,7 +216,9 @@ maybe_numeric(unsigned int *valuep, isc_textregion_t *source,
+ 	 * isc_parse_uint32().  isc_parse_uint32() requires
+ 	 * null termination, so we must make a copy.
+ 	 */
+-	strncpy(buffer, source->base, NUMBERSIZE);
++	strncpy(buffer, source->base, sizeof(buffer));
++	buffer[sizeof(buffer) - 1] = '\0';
++
+ 	INSIST(buffer[source->length] == '\0');
+ 
+ 	result = isc_parse_uint32(&n, buffer, 10);
+diff --git a/lib/isc/netaddr.c b/lib/isc/netaddr.c
+index 5cce1bc..6706542 100644
+--- a/lib/isc/netaddr.c
++++ b/lib/isc/netaddr.c
+@@ -235,6 +235,7 @@ isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) {
+ 	nbytes = prefixlen / 8;
+ 	nbits = prefixlen % 8;
+ 	if (nbits != 0) {
++		INSIST(nbytes < ipbytes);
+ 		if ((p[nbytes] & (0xff>>nbits)) != 0U)
+ 			return (ISC_R_FAILURE);
+ 		nbytes++;
+diff --git a/lib/isc/pk11.c b/lib/isc/pk11.c
+index 015bff2..de4479b 100644
+--- a/lib/isc/pk11.c
++++ b/lib/isc/pk11.c
+@@ -130,7 +130,10 @@
+ #include <pkcs11/cryptoki.h>
+ #include <pkcs11/pkcs11.h>
+ 
+-#define PINLEN	32
++/* was 32 octets, Petr Spacek suggested 1024, SoftHSMv2 uses 256... */
++#ifndef PINLEN
++#define PINLEN	256
++#endif
+ 
+ #ifndef PK11_NO_LOGERR
+ #define PK11_NO_LOGERR 1
+@@ -163,7 +166,7 @@ struct pk11_token {
+ 	char			manuf[32];
+ 	char			model[16];
+ 	char			serial[16];
+-	char			pin[PINLEN];
++	char			pin[PINLEN + 1];
+ };
+ static ISC_LIST(pk11_token_t) tokens;
+ 
+@@ -498,7 +501,9 @@ pk11_get_session(pk11_context_t *ctx, pk11_optype_t optype,
+ 
+ 	/* Override the token's PIN */
+ 	if (logon && pin != NULL && *pin != '\0') {
+-		memset(token->pin, 0, PINLEN);
++		if (strlen(pin) > PINLEN)
++			return ISC_R_RANGE;
++		memset(token->pin, 0, PINLEN + 1);
+ 		strncpy(token->pin, pin, PINLEN);
+ 	}
+ 
+@@ -1099,7 +1104,7 @@ pk11_parse_uri(pk11_object_t *obj, const char *label,
+ 	char *uri, *p, *a, *na, *v;
+ 	size_t len, l;
+ 	FILE *stream = NULL;
+-	char pin[PINLEN];
++	char pin[PINLEN + 1];
+ 	isc_boolean_t gotpin = ISC_FALSE;
+ 	isc_result_t ret;
+ 
+@@ -1207,10 +1212,12 @@ pk11_parse_uri(pk11_object_t *obj, const char *label,
+ 			ret = isc_stdio_open(v, "r", &stream);
+ 			if (ret != ISC_R_SUCCESS)
+ 				goto err;
+-			memset(pin, 0, PINLEN);
+-			ret = isc_stdio_read(pin, 1, PINLEN - 1, stream, NULL);
++			memset(pin, 0, PINLEN + 1);
++			ret = isc_stdio_read(pin, 1, PINLEN + 1, stream, &l);
+ 			if ((ret != ISC_R_SUCCESS) && (ret != ISC_R_EOF))
+ 				goto err;
++			if (l > PINLEN)
++				DST_RET(ISC_R_RANGE);
+ 			ret = isc_stdio_close(stream);
+ 			stream = NULL;
+ 			if (ret != ISC_R_SUCCESS)
+@@ -1238,7 +1245,7 @@ pk11_parse_uri(pk11_object_t *obj, const char *label,
+ 		DST_RET(ISC_R_NOTFOUND);
+ 	obj->slot = token->slotid;
+ 	if (gotpin) {
+-		memmove(token->pin, pin, PINLEN);
++		memmove(token->pin, pin, PINLEN + 1);
+ 		obj->reqlogon = ISC_TRUE;
+ 	}
+ 
+-- 
+2.1.0
+
diff --git a/SOURCES/bind99-rh1214827.patch b/SOURCES/bind99-rh1214827.patch
new file mode 100644
index 0000000..19c35ac
--- /dev/null
+++ b/SOURCES/bind99-rh1214827.patch
@@ -0,0 +1,408 @@
+From c8cd2cd7f21ce56f93532a6d5f26239e60657acb Mon Sep 17 00:00:00 2001
+From: Tomas Hozza <thozza@redhat.com>
+Date: Thu, 25 Jun 2015 14:53:31 +0200
+Subject: [PATCH] nsupdate: Don't extract REAML from ticket, but leave it up to
+ GSSAPI
+
+The current implementation of nsupdate does not work correctly with
+GSSAPI in cross realm trust scenarios. The realm is currently
+extracted from local kerberos ticket instead of letting GSSAPI to
+figure out the realm based on the remote nameserver hostname.
+
+RFC 4752 section 3.1 states that the client should use
+GSS_C_NT_HOSTBASED_SERVICE when calling gss_import_name().
+
+nsupdate now leaves the realm detection up to GSSAPI, if the realm is
+not specified explicitly using the 'realm' option. If the option is
+used, the old behavior is preserved.
+
+Signed-off-by: Tomas Hozza <thozza@redhat.com>
+---
+ bin/nsupdate/nsupdate.1       |  3 +-
+ bin/nsupdate/nsupdate.c       | 72 ++++++++-----------------------------------
+ bin/nsupdate/nsupdate.docbook |  2 +-
+ bin/nsupdate/nsupdate.html    |  2 +-
+ bin/tests/dst/gsstest.c       |  4 +--
+ lib/dns/gssapictx.c           | 16 +++++++---
+ lib/dns/include/dns/tkey.h    | 24 +++++++++------
+ lib/dns/include/dst/gssapi.h  |  8 +++--
+ lib/dns/tkey.c                | 28 +++++++++--------
+ 9 files changed, 65 insertions(+), 94 deletions(-)
+
+diff --git a/bin/nsupdate/nsupdate.1 b/bin/nsupdate/nsupdate.1
+index 1e2dcaf..c847fb8 100644
+--- a/bin/nsupdate/nsupdate.1
++++ b/bin/nsupdate/nsupdate.1
+@@ -259,8 +259,7 @@ on the commandline.
+ .RS 4
+ When using GSS\-TSIG use
+ \fIrealm_name\fR
+-rather than the default realm in
+-\fIkrb5.conf\fR. If no realm is specified the saved realm is cleared.
++rather than leaving the realm detection up to GSSAPI. If no realm is specified the saved realm is cleared.
+ .RE
+ .PP
+ \fB[prereq]\fR\fB nxdomain\fR {domain\-name}
+diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c
+index b901e03..644e3d9 100644
+--- a/bin/nsupdate/nsupdate.c
++++ b/bin/nsupdate/nsupdate.c
+@@ -2489,57 +2489,6 @@ sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr,
+ 
+ #ifdef GSSAPI
+ 
+-/*
+- * Get the realm from the users kerberos ticket if possible
+- */
+-static void
+-get_ticket_realm(isc_mem_t *mctx)
+-{
+-	krb5_context ctx;
+-	krb5_error_code rc;
+-	krb5_ccache ccache;
+-	krb5_principal princ;
+-	char *name, *ticket_realm;
+-
+-	rc = krb5_init_context(&ctx);
+-	if (rc != 0)
+-		return;
+-
+-	rc = krb5_cc_default(ctx, &ccache);
+-	if (rc != 0) {
+-		krb5_free_context(ctx);
+-		return;
+-	}
+-
+-	rc = krb5_cc_get_principal(ctx, ccache, &princ);
+-	if (rc != 0) {
+-		krb5_cc_close(ctx, ccache);
+-		krb5_free_context(ctx);
+-		return;
+-	}
+-
+-	rc = krb5_unparse_name(ctx, princ, &name);
+-	if (rc != 0) {
+-		krb5_free_principal(ctx, princ);
+-		krb5_cc_close(ctx, ccache);
+-		krb5_free_context(ctx);
+-		return;
+-	}
+-
+-	ticket_realm = strrchr(name, '@');
+-	if (ticket_realm != NULL) {
+-		realm = isc_mem_strdup(mctx, ticket_realm);
+-	}
+-
+-	free(name);
+-	krb5_free_principal(ctx, princ);
+-	krb5_cc_close(ctx, ccache);
+-	krb5_free_context(ctx);
+-	if (realm != NULL && debugging)
+-		fprintf(stderr, "Found realm from ticket: %s\n", realm+1);
+-}
+-
+-
+ static void
+ start_gssrequest(dns_name_t *master) {
+ 	gss_ctx_id_t context;
+@@ -2580,11 +2529,15 @@ start_gssrequest(dns_name_t *master) {
+ 	dns_fixedname_init(&fname);
+ 	servname = dns_fixedname_name(&fname);
+ 
+-	if (realm == NULL)
+-		get_ticket_realm(mctx);
+-
+-	result = isc_string_printf(servicename, sizeof(servicename),
+-				   "DNS/%s%s", namestr, realm ? realm : "");
++	if (realm != NULL) {
++		/* Use explicit REALM passed as argument */
++		result = isc_string_printf(servicename, sizeof(servicename),
++				   "DNS/%s%s", namestr, realm);
++	} else {
++		/* Use service@host as advised in RFC4752 section 3.1 */
++		result = isc_string_printf(servicename, sizeof(servicename),
++				   "DNS@%s", namestr);
++	}
+ 	if (result != ISC_R_SUCCESS)
+ 		fatal("isc_string_printf(servicename) failed: %s",
+ 		      isc_result_totext(result));
+@@ -2623,9 +2576,9 @@ start_gssrequest(dns_name_t *master) {
+ 
+ 	/* Build first request. */
+ 	context = GSS_C_NO_CONTEXT;
+-	result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0,
+-					&context, use_win2k_gsstsig,
+-					mctx, &err_message);
++	result = dns_tkey_buildgssquery(rmsg, keyname, servname,
++					realm != NULL ? ISC_TRUE : ISC_FALSE, NULL, 0,
++					&context, use_win2k_gsstsig, mctx, &err_message);
+ 	if (result == ISC_R_FAILURE)
+ 		fatal("tkey query failed: %s",
+ 		      err_message != NULL ? err_message : "unknown error");
+@@ -2765,6 +2718,7 @@ recvgss(isc_task_t *task, isc_event_t *event) {
+ 
+ 	tsigkey = NULL;
+ 	result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname,
++				       realm != NULL ? ISC_TRUE : ISC_FALSE,
+ 				       &context, &tsigkey, gssring,
+ 				       use_win2k_gsstsig,
+ 				       &err_message);
+diff --git a/bin/nsupdate/nsupdate.docbook b/bin/nsupdate/nsupdate.docbook
+index c54211c..bbcc681 100644
+--- a/bin/nsupdate/nsupdate.docbook
++++ b/bin/nsupdate/nsupdate.docbook
+@@ -418,7 +418,7 @@
+           <listitem>
+             <para>
+ 	      When using GSS-TSIG use <parameter>realm_name</parameter> rather
+-	      than the default realm in <filename>krb5.conf</filename>.  If no
++	      than leaving the realm detection up to GSSAPI.  If no
+ 	      realm is specified the saved realm is cleared.
+             </para>
+           </listitem>
+diff --git a/bin/nsupdate/nsupdate.html b/bin/nsupdate/nsupdate.html
+index 276d4af..9c0eba0 100644
+--- a/bin/nsupdate/nsupdate.html
++++ b/bin/nsupdate/nsupdate.html
+@@ -327,7 +327,7 @@
+           </span></dt>
+ <dd><p>
+ 	      When using GSS-TSIG use <em class="parameter"><code>realm_name</code></em> rather
+-	      than the default realm in <code class="filename">krb5.conf</code>.  If no
++	      than leaving the realm detection up to GSSAPI.  If no
+ 	      realm is specified the saved realm is cleared.
+             </p></dd>
+ <dt><span class="term">
+diff --git a/bin/tests/dst/gsstest.c b/bin/tests/dst/gsstest.c
+index c1296f7..7c85d0b 100755
+--- a/bin/tests/dst/gsstest.c
++++ b/bin/tests/dst/gsstest.c
+@@ -309,7 +309,7 @@ initctx2(isc_task_t *task, isc_event_t *event) {
+ 	printf("Received token from server, calling gss_init_sec_context()\n");
+ 	isc_buffer_init(&outtoken, array, DNS_NAME_MAXTEXT + 1);
+ 	result = dns_tkey_processgssresponse(query, response,
+-					     dns_fixedname_name(&gssname),
++					     dns_fixedname_name(&gssname), ISC_FALSE,
+ 					     &gssctx, &outtoken,
+ 					     &tsigkey, ring, NULL);
+ 	gssctx = *gssctxp;
+@@ -396,7 +396,7 @@ initctx1(isc_task_t *task, isc_event_t *event) {
+ 	printf("Calling gss_init_sec_context()\n");
+ 	gssctx = GSS_C_NO_CONTEXT;
+ 	result = dns_tkey_buildgssquery(query, dns_fixedname_name(&servername),
+-					dns_fixedname_name(&gssname),
++					dns_fixedname_name(&gssname), ISC_FALSE,
+ 					NULL, 36000, &gssctx, ISC_TRUE,
+ 					mctx, NULL);
+ 	CHECK("dns_tkey_buildgssquery", result);
+diff --git a/lib/dns/gssapictx.c b/lib/dns/gssapictx.c
+index aeaeb85..21222e0 100644
+--- a/lib/dns/gssapictx.c
++++ b/lib/dns/gssapictx.c
+@@ -558,14 +558,15 @@ gss_err_message(isc_mem_t *mctx, isc_uint32_t major, isc_uint32_t minor,
+ #endif
+ 
+ isc_result_t
+-dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken,
+-		   isc_buffer_t *outtoken, gss_ctx_id_t *gssctx,
+-		   isc_mem_t *mctx, char **err_message)
++dst_gssapi_initctx(dns_name_t *name, isc_boolean_t explicit_realm,
++		   isc_buffer_t *intoken, isc_buffer_t *outtoken,
++		   gss_ctx_id_t *gssctx, isc_mem_t *mctx, char **err_message)
+ {
+ #ifdef GSSAPI
+ 	isc_region_t r;
+ 	isc_buffer_t namebuf;
+ 	gss_name_t gname;
++	gss_OID gname_type;
+ 	OM_uint32 gret, minor, ret_flags, flags;
+ 	gss_buffer_desc gintoken, *gintokenp, gouttoken = GSS_C_EMPTY_BUFFER;
+ 	isc_result_t result;
+@@ -580,7 +581,13 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken,
+ 	name_to_gbuffer(name, &namebuf, &gnamebuf);
+ 
+ 	/* Get the name as a GSS name */
+-	gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname);
++	if (explicit_realm == ISC_TRUE) {
++		gname_type = GSS_C_NO_OID;
++	} else {
++		gname_type = GSS_C_NT_HOSTBASED_SERVICE;
++	}
++
++	gret = gss_import_name(&minor, &gnamebuf, gname_type, &gname);
+ 	if (gret != GSS_S_COMPLETE) {
+ 		gss_err_message(mctx, gret, minor, err_message);
+ 		result = ISC_R_FAILURE;
+@@ -642,6 +649,7 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken,
+ 	return (result);
+ #else
+ 	UNUSED(name);
++	UNUSED(explicit_realm);
+ 	UNUSED(intoken);
+ 	UNUSED(outtoken);
+ 	UNUSED(gssctx);
+diff --git a/lib/dns/include/dns/tkey.h b/lib/dns/include/dns/tkey.h
+index 0dcec1e..a0e6c2a 100644
+--- a/lib/dns/include/dns/tkey.h
++++ b/lib/dns/include/dns/tkey.h
+@@ -123,9 +123,9 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name,
+ 
+ isc_result_t
+ dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname,
+-		       isc_buffer_t *intoken, isc_uint32_t lifetime,
+-		       gss_ctx_id_t *context, isc_boolean_t win2k,
+-		       isc_mem_t *mctx, char **err_message);
++		       isc_boolean_t explicit_realm, isc_buffer_t *intoken,
++		       isc_uint32_t lifetime, gss_ctx_id_t *context,
++		       isc_boolean_t win2k, isc_mem_t *mctx, char **err_message);
+ /*%<
+  *	Builds a query containing a TKEY that will generate a GSSAPI context.
+  *	The key is requested to have the specified lifetime (in seconds).
+@@ -134,6 +134,8 @@ dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname,
+  *\li		'msg'	  is a valid message
+  *\li		'name'	  is a valid name
+  *\li		'gname'	  is a valid name
++ *\li		'explicit_realm' ISC_TRUE if an explicit realm is used,
++ *			  ISC_FALSE if the realm detection is left up to GSSAPI.
+  *\li		'context' is a pointer to a valid gss_ctx_id_t
+  *			  (which may have the value GSS_C_NO_CONTEXT)
+  *\li		'win2k'   when true says to turn on some hacks to work
+@@ -188,9 +190,10 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
+ 
+ isc_result_t
+ dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg,
+-			    dns_name_t *gname, gss_ctx_id_t *context,
+-			    isc_buffer_t *outtoken, dns_tsigkey_t **outkey,
+-			    dns_tsig_keyring_t *ring, char **err_message);
++			    dns_name_t *gname, isc_boolean_t explicit_realm,
++			    gss_ctx_id_t *context, isc_buffer_t *outtoken,
++			    dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring,
++			    char **err_message);
+ /*%<
+  * XXX
+  */
+@@ -216,9 +219,10 @@ dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg,
+ 
+ isc_result_t
+ dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg,
+-		      dns_name_t *server, gss_ctx_id_t *context,
+-		      dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring,
+-		      isc_boolean_t win2k, char **err_message);
++		      dns_name_t *server, isc_boolean_t explicit_realm,
++		      gss_ctx_id_t *context, dns_tsigkey_t **outkey,
++		      dns_tsig_keyring_t *ring, isc_boolean_t win2k,
++		      char **err_message);
+ 
+ /*
+  *	Client side negotiation of GSS-TSIG.  Process the response
+@@ -231,6 +235,8 @@ dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg,
+  *			     it will be filled with the new message to send
+  *		'rmsg'    is a valid message, the incoming TKEY message
+  *		'server'  is the server name
++ *		'explicit_realm' ISC_TRUE if an explicit realm is used,
++ *			      ISC_FALSE if the realm detection is left up to GSSAPI.
+  *		'context' is the input context handle
+  *		'outkey'  receives the established key, if non-NULL;
+  *			      if non-NULL must point to NULL
+diff --git a/lib/dns/include/dst/gssapi.h b/lib/dns/include/dst/gssapi.h
+index 1e81a55..d093fa3 100644
+--- a/lib/dns/include/dst/gssapi.h
++++ b/lib/dns/include/dst/gssapi.h
+@@ -93,15 +93,17 @@ dst_gssapi_releasecred(gss_cred_id_t *cred);
+  */
+ 
+ isc_result_t
+-dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken,
+-		   isc_buffer_t *outtoken, gss_ctx_id_t *gssctx,
+-		   isc_mem_t *mctx, char **err_message);
++dst_gssapi_initctx(dns_name_t *name, isc_boolean_t explicit_realm,
++		   isc_buffer_t *intoken, isc_buffer_t *outtoken,
++		   gss_ctx_id_t *gssctx, isc_mem_t *mctx, char **err_message);
+ /*
+  *	Initiates a GSS context.
+  *
+  *	Requires:
+  * 	'name'     is a valid name, preferably one known by the GSS
+  * 	provider
++ * 	'explicit_realm' True if the REALM is explicitly included in the 'name',
++ *  	   otherwise leave the REALM detection up to GSSAPI
+  * 	'intoken'  is a token received from the acceptor, or NULL if
+  *		   there isn't one
+  * 	'outtoken' is a buffer to receive the token generated by
+diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c
+index 20c98e5..3463d3a 100644
+--- a/lib/dns/tkey.c
++++ b/lib/dns/tkey.c
+@@ -1016,9 +1016,9 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name,
+ 
+ isc_result_t
+ dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname,
+-		       isc_buffer_t *intoken, isc_uint32_t lifetime,
+-		       gss_ctx_id_t *context, isc_boolean_t win2k,
+-		       isc_mem_t *mctx, char **err_message)
++		       isc_boolean_t explicit_realm, isc_buffer_t *intoken,
++		       isc_uint32_t lifetime, gss_ctx_id_t *context,
++		       isc_boolean_t win2k, isc_mem_t *mctx, char **err_message)
+ {
+ 	dns_rdata_tkey_t tkey;
+ 	isc_result_t result;
+@@ -1035,7 +1035,7 @@ dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname,
+ 	REQUIRE(mctx != NULL);
+ 
+ 	isc_buffer_init(&token, array, sizeof(array));
+-	result = dst_gssapi_initctx(gname, NULL, &token, context,
++	result = dst_gssapi_initctx(gname, explicit_realm, NULL, &token, context,
+ 				    mctx, err_message);
+ 	if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS)
+ 		return (result);
+@@ -1251,9 +1251,10 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg,
+ 
+ isc_result_t
+ dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg,
+-			    dns_name_t *gname, gss_ctx_id_t *context,
+-			    isc_buffer_t *outtoken, dns_tsigkey_t **outkey,
+-			    dns_tsig_keyring_t *ring, char **err_message)
++			    dns_name_t *gname, isc_boolean_t explicit_realm,
++			    gss_ctx_id_t *context, isc_buffer_t *outtoken,
++			    dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring,
++			    char **err_message)
+ {
+ 	dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT;
+ 	dns_name_t *tkeyname;
+@@ -1304,7 +1305,7 @@ dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg,
+ 
+ 	isc_buffer_init(outtoken, array, sizeof(array));
+ 	isc_buffer_init(&intoken, rtkey.key, rtkey.keylen);
+-	RETERR(dst_gssapi_initctx(gname, &intoken, outtoken, context,
++	RETERR(dst_gssapi_initctx(gname, explicit_realm, &intoken, outtoken, context,
+ 				  ring->mctx, err_message));
+ 
+ 	RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx,
+@@ -1384,9 +1385,10 @@ dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg,
+ 
+ isc_result_t
+ dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg,
+-		      dns_name_t *server, gss_ctx_id_t *context,
+-		      dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring,
+-		      isc_boolean_t win2k, char **err_message)
++		      dns_name_t *server, isc_boolean_t explicit_realm,
++		      gss_ctx_id_t *context, dns_tsigkey_t **outkey,
++		      dns_tsig_keyring_t *ring, isc_boolean_t win2k,
++		      char **err_message)
+ {
+ 	dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT;
+ 	dns_name_t *tkeyname;
+@@ -1430,8 +1432,8 @@ dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg,
+ 	isc_buffer_init(&intoken, rtkey.key, rtkey.keylen);
+ 	isc_buffer_init(&outtoken, array, sizeof(array));
+ 
+-	result = dst_gssapi_initctx(server, &intoken, &outtoken, context,
+-				    ring->mctx, err_message);
++	result = dst_gssapi_initctx(server, explicit_realm, &intoken, &outtoken,
++					context, ring->mctx, err_message);
+ 	if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS)
+ 		return (result);
+ 
+-- 
+2.4.3
+
diff --git a/SOURCES/bind99-rh1215164.patch b/SOURCES/bind99-rh1215164.patch
new file mode 100644
index 0000000..80bef02
--- /dev/null
+++ b/SOURCES/bind99-rh1215164.patch
@@ -0,0 +1,178 @@
+diff --git a/bin/check/named-checkzone.8 b/bin/check/named-checkzone.8
+index 8538ca8..0ab0049 100644
+--- a/bin/check/named-checkzone.8
++++ b/bin/check/named-checkzone.8
+@@ -251,7 +251,7 @@ so that include directives in the configuration file are processed as if run by
+ .PP
+ \-T \fImode\fR
+ .RS 4
+-Check if Sender Policy Framework records (TXT and SPF) both exist or both don't exist. A warning is issued if they don't match. Possible modes are
++Check if Sender Policy Framework (SPF) records exist and issues a warning if an SPF-formatted TXT record is not also present. Possible modes are
+ \fB"warn"\fR
+ (default),
+ \fB"ignore"\fR.
+diff --git a/bin/check/named-checkzone.docbook b/bin/check/named-checkzone.docbook
+index ea37fa2..e78d574 100644
+--- a/bin/check/named-checkzone.docbook
++++ b/bin/check/named-checkzone.docbook
+@@ -408,10 +408,10 @@
+ 	<term>-T <replaceable class="parameter">mode</replaceable></term>
+ 	<listitem>
+ 	  <para>
+-	    Check if Sender Policy Framework records (TXT and SPF)
+-	    both exist or both don't exist.  A warning is issued
+-	    if they don't match.  Possible modes are
+-	    <command>"warn"</command> (default), <command>"ignore"</command>.
++	    Check if Sender Policy Framework (SPF) records exist
++	    and issues a warning if an SPF-formatted TXT record is
++	    not also present.  Possible modes are <command>"warn"</command>
++	    (default), <command>"ignore"</command>.
+ 	  </para>
+ 	</listitem>
+       </varlistentry>
+diff --git a/bin/tests/system/checkzone/tests.sh b/bin/tests/system/checkzone/tests.sh
+index 2353c14..7d9192e 100644
+--- a/bin/tests/system/checkzone/tests.sh
++++ b/bin/tests/system/checkzone/tests.sh
+@@ -44,12 +44,12 @@ echo "I:checking with spf warnings ($n)"
+ ret=0
+ $CHECKZONE example zones/spf.db > test.out1.$n 2>&1 || ret=1
+ $CHECKZONE -T ignore example zones/spf.db > test.out2.$n 2>&1 || ret=1
+-grep "'x.example' found SPF/TXT" test.out1.$n > /dev/null || ret=1
+-grep "'y.example' found SPF/SPF" test.out1.$n > /dev/null || ret=1
+-grep "'example' found SPF/" test.out1.$n > /dev/null && ret=1
+-grep "'x.example' found SPF/" test.out2.$n > /dev/null && ret=1
+-grep "'y.example' found SPF/" test.out2.$n > /dev/null && ret=1
+-grep "'example' found SPF/" test.out2.$n > /dev/null && ret=1
++grep "'x.example' found type SPF" test.out1.$n > /dev/null && ret=1
++grep "'y.example' found type SPF" test.out1.$n > /dev/null || ret=1
++grep "'example' found type SPF" test.out1.$n > /dev/null && ret=1
++grep "'x.example' found type SPF" test.out2.$n > /dev/null && ret=1
++grep "'y.example' found type SPF" test.out2.$n > /dev/null && ret=1
++grep "'example' found type SPF" test.out2.$n > /dev/null && ret=1
+ n=`expr $n + 1`
+ if [ $ret != 0 ]; then echo "I:failed"; fi
+ status=`expr $status + $ret`
+diff --git a/bin/tests/system/spf/tests.sh b/bin/tests/system/spf/tests.sh
+index 6acd283..3da6e2e 100644
+--- a/bin/tests/system/spf/tests.sh
++++ b/bin/tests/system/spf/tests.sh
+@@ -24,19 +24,16 @@ echo "I:checking that SPF warnings have been correctly generated ($n)"
+ ret=0
+ 
+ grep "zone spf/IN: loaded serial 0" ns1/named.run > /dev/null || ret=1
+-grep "'x.spf' found SPF/TXT" ns1/named.run > /dev/null || ret=1
+-grep "'y.spf' found SPF/SPF" ns1/named.run > /dev/null || ret=1
+-grep "'spf' found SPF/" ns1/named.run > /dev/null && ret=1
++grep "'y.spf' found type SPF" ns1/named.run > /dev/null || ret=1
++grep "'spf' found type SPF" ns1/named.run > /dev/null && ret=1
+ 
+ grep "zone warn/IN: loaded serial 0" ns1/named.run > /dev/null || ret=1
+-grep "'x.warn' found SPF/TXT" ns1/named.run > /dev/null || ret=1
+-grep "'y.warn' found SPF/SPF" ns1/named.run > /dev/null || ret=1
+-grep "'warn' found SPF/" ns1/named.run > /dev/null && ret=1
++grep "'y.warn' found type SPF" ns1/named.run > /dev/null || ret=1
++grep "'warn' found type SPF" ns1/named.run > /dev/null && ret=1
+ 
+ grep "zone nowarn/IN: loaded serial 0" ns1/named.run > /dev/null || ret=1
+-grep "'x.nowarn' found SPF/" ns1/named.run > /dev/null && ret=1
+-grep "'y.nowarn' found SPF/" ns1/named.run > /dev/null && ret=1
+-grep "'nowarn' found SPF/" ns1/named.run > /dev/null && ret=1
++grep "'y.nowarn' found type SPF" ns1/named.run > /dev/null && ret=1
++grep "'nowarn' found type SPF" ns1/named.run > /dev/null && ret=1
+ n=`expr $n + 1`
+ if [ $ret != 0 ]; then echo "I:failed"; fi
+ status=`expr $status + $ret`
+diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml
+index 96c9faf..bd42e11 100644
+--- a/doc/arm/Bv9ARM-book.xml
++++ b/doc/arm/Bv9ARM-book.xml
+@@ -4750,7 +4750,7 @@ badresp:1,adberr:0,findfail:0,valfail:0]
+     <optional> check-mx-cname ( <replaceable>warn</replaceable> | <replaceable>fail</replaceable> | <replaceable>ignore</replaceable> ); </optional>
+     <optional> check-srv-cname ( <replaceable>warn</replaceable> | <replaceable>fail</replaceable> | <replaceable>ignore</replaceable> ); </optional>
+     <optional> check-sibling <replaceable>yes_or_no</replaceable>; </optional>
+-    <optional> check-spf ( <replaceable>warn</replaceable> | <replaceable>fail</replaceable> | <replaceable>ignore</replaceable> ); </optional>
++    <optional> check-spf ( <replaceable>warn</replaceable> | <replaceable>ignore</replaceable> ); </optional>
+     <optional> allow-new-zones { <replaceable>yes_or_no</replaceable> }; </optional>
+     <optional> allow-notify { <replaceable>address_match_list</replaceable> }; </optional>
+     <optional> allow-query { <replaceable>address_match_list</replaceable> }; </optional>
+@@ -6573,10 +6573,13 @@ options {
+ 	          The default is <command>yes</command>.
+ 		</para>
+ 		<para>
+-		  Check that the two forms of Sender Policy Framework
+-		  records (TXT records starting with "v=spf1" and SPF) either
+-		  both exist or both don't exist.  Warnings are
+-		  emitted it they don't and be suppressed with
++		  The use of the SPF record for publishing Sender
++		  Policy Framework is deprecated as the migration
++		  from using TXT records to SPF records was abandoned.
++		  Enabling this option also checks that a TXT Sender
++		  Policy Framework record exists (starts with "v=spf1")
++		  if there is an SPF record. Warnings are emitted if the
++		  TXT record does not exist and can be suppressed with
+ 		  <command>check-spf</command>.
+ 		</para>
+ 	      </listitem>
+@@ -6618,11 +6621,11 @@ options {
+ 	      <term><command>check-spf</command></term>
+ 	      <listitem>
+ 		<para>
+-		  When performing integrity checks, check that the
+-		  two forms of Sender Policy Framwork records (TXT
+-		  records starting with "v=spf1" and SPF) both exist
+-		  or both don't exist and issue a warning if not
+-		  met.  The default is <command>warn</command>.
++		  If <command>check-integrity</command> is set then
++		  check that there is a TXT Sender Policy Framework
++		  record present (starts with "v=spf1") if there is an
++		  SPF record present. The default is
++		  <command>warn</command>.
+ 		</para>
+ 	      </listitem>
+ 	    </varlistentry>
+@@ -10372,7 +10375,7 @@ view "external" {
+     <optional> check-names (<constant>warn</constant>|<constant>fail</constant>|<constant>ignore</constant>) ; </optional>
+     <optional> check-mx (<constant>warn</constant>|<constant>fail</constant>|<constant>ignore</constant>) ; </optional>
+     <optional> check-wildcard <replaceable>yes_or_no</replaceable>; </optional>
+-    <optional> check-spf ( <replaceable>warn</replaceable> | <replaceable>fail</replaceable> | <replaceable>ignore</replaceable> ); </optional>
++    <optional> check-spf ( <replaceable>warn</replaceable> | <replaceable>ignore</replaceable> ); </optional>
+     <optional> check-integrity <replaceable>yes_or_no</replaceable> ; </optional>
+     <optional> dialup <replaceable>dialup_option</replaceable> ; </optional>
+     <optional> file <replaceable>string</replaceable> ; </optional>
+diff --git a/lib/dns/zone.c b/lib/dns/zone.c
+index 86fad98..08c6d10 100644
+--- a/lib/dns/zone.c
++++ b/lib/dns/zone.c
+@@ -2612,8 +2612,8 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
+ 
+  checkspf:
+ 		/*
+-		 * Check if there is a type TXT spf record without a type SPF
+-		 * RRset being present.
++		 * Check if there is a type SPF record without an
++		 * SPF-formatted type TXT record also being present.
+ 		 */
+ 		if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKSPF))
+ 			goto next;
+@@ -2642,16 +2642,13 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) {
+ 		dns_rdataset_disassociate(&rdataset);
+ 
+  notxt:
+-		if (have_spf != have_txt) {
++		if (have_spf && !have_txt) {
+ 			char namebuf[DNS_NAME_FORMATSIZE];
+-			const char *found = have_txt ? "TXT" : "SPF";
+-			const char *need = have_txt ? "SPF" : "TXT";
+ 
+ 			dns_name_format(name, namebuf, sizeof(namebuf));
+-			dns_zone_log(zone, ISC_LOG_WARNING, "'%s' found SPF/%s "
+-				     "record but no SPF/%s record found, add "
+-				     "matching type %s record", namebuf, found,
+-				     need, need);
++			dns_zone_log(zone, ISC_LOG_WARNING, "'%s' found type "
++				     "SPF record but no SPF TXT record found, "
++				     "add matching type TXT record", namebuf);
+ 		}
+ 
+  next:
diff --git a/SOURCES/named-chroot.service b/SOURCES/named-chroot.service
index 39d3700..f8c0496 100644
--- a/SOURCES/named-chroot.service
+++ b/SOURCES/named-chroot.service
@@ -16,7 +16,7 @@ EnvironmentFile=-/etc/sysconfig/named
 Environment=KRB5_KTNAME=/etc/named.keytab
 PIDFile=/var/named/chroot/run/named/named.pid
 
-ExecStartPre=/usr/sbin/named-checkconf -t /var/named/chroot -z /etc/named.conf
+ExecStartPre=/bin/bash -c 'if [ ! "$DISABLE_ZONE_CHECKING" == "yes" ]; then /usr/sbin/named-checkconf -z /etc/named.conf; else echo "Checking of zone files is disabled"; fi'
 ExecStart=/usr/sbin/named -u named -t /var/named/chroot $OPTIONS
 
 ExecReload=/bin/sh -c '/usr/sbin/rndc reload > /dev/null 2>&1 || /bin/kill -HUP $MAINPID'
diff --git a/SOURCES/named-pkcs11.service b/SOURCES/named-pkcs11.service
new file mode 100644
index 0000000..6ce9001
--- /dev/null
+++ b/SOURCES/named-pkcs11.service
@@ -0,0 +1,26 @@
+[Unit]
+Description=Berkeley Internet Name Domain (DNS) with native PKCS#11
+Wants=nss-lookup.target
+Wants=network-online.target
+Wants=named-setup-rndc.service
+Before=nss-lookup.target
+After=network-online.target
+After=named-setup-rndc.service
+
+[Service]
+Type=forking
+EnvironmentFile=-/etc/sysconfig/named
+Environment=KRB5_KTNAME=/etc/named.keytab
+PIDFile=/run/named/named.pid
+
+ExecStartPre=/bin/bash -c 'if [ ! "$DISABLE_ZONE_CHECKING" == "yes" ]; then /usr/sbin/named-checkconf -z /etc/named.conf; else echo "Checking of zone files is disabled"; fi'
+ExecStart=/usr/sbin/named-pkcs11 -u named $OPTIONS
+
+ExecReload=/bin/sh -c '/usr/sbin/rndc reload > /dev/null 2>&1 || /bin/kill -HUP $MAINPID'
+
+ExecStop=/bin/sh -c '/usr/sbin/rndc stop > /dev/null 2>&1 || /bin/kill -TERM $MAINPID'
+
+PrivateTmp=true
+
+[Install]
+WantedBy=multi-user.target
diff --git a/SOURCES/named-sdb.service b/SOURCES/named-sdb.service
index e0cd31c..bb58bca 100644
--- a/SOURCES/named-sdb.service
+++ b/SOURCES/named-sdb.service
@@ -12,7 +12,7 @@ EnvironmentFile=-/etc/sysconfig/named
 Environment=KRB5_KTNAME=/etc/named.keytab
 PIDFile=/run/named/named.pid
 
-ExecStartPre=/usr/sbin/named-checkconf -z /etc/named.conf
+ExecStartPre=/bin/bash -c 'if [ ! "$DISABLE_ZONE_CHECKING" == "yes" ]; then /usr/sbin/named-checkconf -z /etc/named.conf; else echo "Checking of zone files is disabled"; fi'
 ExecStart=/usr/sbin/named-sdb -u named $OPTIONS
 
 ExecReload=/bin/sh -c '/usr/sbin/rndc reload > /dev/null 2>&1 || /bin/kill -HUP $MAINPID'
diff --git a/SOURCES/named.conf.sample b/SOURCES/named.conf.sample
index aee040a..afae47b 100644
--- a/SOURCES/named.conf.sample
+++ b/SOURCES/named.conf.sample
@@ -68,9 +68,6 @@ options
 	/* Enable DNSSEC validation on recursive servers */
 	dnssec-validation yes;
 
-	/* Enable DLV by default, use built-in ISC DLV key. */
-	dnssec-lookaside auto;
-
 	/* In RHEL-7 we use /run/named instead of default /var/run/named
 	   so we have to configure paths properly. */
 	pid-file "/run/named/named.pid";
diff --git a/SOURCES/named.logrotate b/SOURCES/named.logrotate
index 78cacc2..5df448f 100644
--- a/SOURCES/named.logrotate
+++ b/SOURCES/named.logrotate
@@ -3,9 +3,10 @@
     su named named
     create 0644 named named
     postrotate
-        /sbin/systemctl reload named.service > /dev/null 2>&1 || true
-        /sbin/systemctl reload named-chroot.service > /dev/null 2>&1 || true
-        /sbin/systemctl reload named-sdb.service > /dev/null 2>&1 || true
-        /sbin/systemctl reload named-sdb-chroot.service > /dev/null 2>&1 || true
+        /usr/bin/systemctl reload named.service > /dev/null 2>&1 || true
+        /usr/bin/systemctl reload named-chroot.service > /dev/null 2>&1 || true
+        /usr/bin/systemctl reload named-sdb.service > /dev/null 2>&1 || true
+        /usr/bin/systemctl reload named-sdb-chroot.service > /dev/null 2>&1 || true
+        /usr/bin/systemctl reload named-pkcs11.service > /dev/null 2>&1 || true
     endscript
 }
diff --git a/SOURCES/named.service b/SOURCES/named.service
index 7e48c89..f8198fd 100644
--- a/SOURCES/named.service
+++ b/SOURCES/named.service
@@ -12,7 +12,7 @@ EnvironmentFile=-/etc/sysconfig/named
 Environment=KRB5_KTNAME=/etc/named.keytab
 PIDFile=/run/named/named.pid
 
-ExecStartPre=/usr/sbin/named-checkconf -z /etc/named.conf
+ExecStartPre=/bin/bash -c 'if [ ! "$DISABLE_ZONE_CHECKING" == "yes" ]; then /usr/sbin/named-checkconf -z /etc/named.conf; else echo "Checking of zone files is disabled"; fi'
 ExecStart=/usr/sbin/named -u named $OPTIONS
 
 ExecReload=/bin/sh -c '/usr/sbin/rndc reload > /dev/null 2>&1 || /bin/kill -HUP $MAINPID'
diff --git a/SOURCES/named.sysconfig b/SOURCES/named.sysconfig
index 9a6c556..2326043 100644
--- a/SOURCES/named.sysconfig
+++ b/SOURCES/named.sysconfig
@@ -3,4 +3,10 @@
 #
 # OPTIONS="whatever"     --  These additional options will be passed to named
 #                            at startup. Don't add -t here, enable proper
-#                            -chroot.service unit file.  
+#                            -chroot.service unit file.
+#
+# DISABLE_ZONE_CHECKING  --  By default, service file calls named-checkzone
+#                            utility for every zone to ensure all zones are
+#                            valid before named starts. If you set this option
+#                            to 'yes' then service file doesn't perform those
+#                            checks.
diff --git a/SOURCES/setup-named-chroot.sh b/SOURCES/setup-named-chroot.sh
index 8de494b..e0247e1 100755
--- a/SOURCES/setup-named-chroot.sh
+++ b/SOURCES/setup-named-chroot.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-ROOTDIR_MOUNT='/etc/named /etc/pki/dnssec-keys /etc/named.root.key /etc/named.conf
+ROOTDIR_MOUNT='/etc/localtime /etc/named /etc/pki/dnssec-keys /etc/named.root.key /etc/named.conf
 /etc/named.dnssec.keys /etc/named.rfc1912.zones /etc/rndc.conf /etc/rndc.key
 /usr/lib64/bind /usr/lib/bind /etc/named.iscdlv.key /run/named /var/named'
 
diff --git a/SPECS/bind.spec b/SPECS/bind.spec
index 20170e3..de75c45 100644
--- a/SPECS/bind.spec
+++ b/SPECS/bind.spec
@@ -13,11 +13,7 @@
 %{?!bind_uid:  %global bind_uid  25}
 %{?!bind_gid:  %global bind_gid  25}
 %{?!GSSTSIG:   %global GSSTSIG   1}
-%if 0%{?rhel}
-%{?!PKCS11:    %global PKCS11    0}
-%else
 %{?!PKCS11:    %global PKCS11    1}
-%endif
 %{?!DEVEL:     %global DEVEL     1}
 %global        bind_dir          /var/named
 %global        chroot_prefix     %{bind_dir}/chroot
@@ -29,7 +25,7 @@ Summary:  The Berkeley Internet Name Domain (BIND) DNS (Domain Name System) serv
 Name:     bind
 License:  ISC
 Version:  9.9.4
-Release:  18%{?PATCHVER}%{?PREVER}%{?dist}.4
+Release:  29%{?PATCHVER}%{?PREVER}%{?dist}
 Epoch:    32
 Url:      http://www.isc.org/products/BIND/
 Buildroot:%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
@@ -43,7 +39,7 @@ Source7:  bind-9.3.1rc1-sdb_tools-Makefile.in
 Source8:  dnszone.schema
 Source12: README.sdb_pgsql
 Source25: named.conf.sample
-Source28: config-12.tar.bz2
+Source28: config-13.tar.bz2
 Source30: ldap2zone.c
 Source31: ldap2zone.1
 Source32: named-sdb.8
@@ -61,6 +57,7 @@ Source43: named.rwtab
 Source44: named-chroot-setup.service
 Source45: named-sdb-chroot-setup.service
 Source46: named-setup-rndc.service
+Source47: named-pkcs11.service
 
 # Common patches
 Patch5:  bind-nonexec.patch
@@ -71,7 +68,6 @@ Patch87: bind-9.5-parallel-build.patch
 Patch101:bind-96-old-api.patch
 Patch102:bind-95-rh452060.patch
 Patch106:bind93-rh490837.patch
-Patch107:bind97-dist-pkcs11.patch
 Patch109:bind97-rh478718.patch
 Patch110:bind97-rh570851.patch
 Patch111:bind97-exportlib.patch
@@ -98,10 +94,19 @@ Patch145:bind99-rh1072379.patch
 Patch146:bind99-rh1098959.patch
 Patch147:bind99-CVE-2014-8500.patch
 Patch148:bind99-CVE-2015-1349.patch
-Patch149:bind99-CVE-2015-4620.patch
-Patch150:bind99-CVE-2015-5477.patch
-Patch151:bind99-rh1215687-limits.patch
-Patch152:bind-99-socket-maxevents.patch
+Patch149:bind99-rh1215687-limits.patch
+Patch154:bind99-rh1215164.patch
+Patch155:bind99-rh1214827.patch
+Patch156:bind99-CVE-2015-4620.patch
+Patch157:bind99-CVE-2015-5477.patch
+Patch158:bind-99-socket-maxevents.patch
+Patch159:bind99-CVE-2015-5722.patch
+
+# Native PKCS#11 functionality from 9.10
+Patch150:bind-9.9-allow_external_dnskey.patch
+Patch151:bind-9.9-native-pkcs11.patch
+Patch152:bind-9.9-dist-native-pkcs11.patch
+Patch153:bind99-coverity-fixes.patch
 
 # SDB patches
 Patch11: bind-9.3.2b2-sdbsrc.patch
@@ -159,15 +164,45 @@ tools for verifying that the DNS server is operating properly.
 
 %if %{PKCS11}
 %package pkcs11
-Summary: Bind PKCS#11 tools for using DNSSEC
+Summary: Bind with native PKCS#11 functionality for crypto
 Group:   System Environment/Daemons
-Requires: engine_pkcs11 opensc
-#BuildRequires: opensc-devel
+Requires: bind = %{epoch}:%{version}-%{release}
+Requires: bind-pkcs11-libs = %{epoch}:%{version}-%{release}
 
 %description pkcs11
+This is a version of BIND server built with native PKCS#11 functionality.
+It is important to have SoftHSM v2+ installed and some token initialized.
+For other supported HSM modules please check the BIND documentation.
+This version of BIND binary is supported only in setup with the IPA server.
+
+%package pkcs11-utils
+Summary: Bind tools with native PKCS#11 for using DNSSEC
+Group:   System Environment/Daemons
+Requires: bind-pkcs11-libs = %{epoch}:%{version}-%{release}
+
+%description pkcs11-utils
 This is a set of PKCS#11 utilities that when used together create rsa
-keys in a PKCS11 keystore, such as provided by opencryptoki. The keys
-will have a label of "zone,zsk|ksk,xxx" and an id of the keytag in hex.
+keys in a PKCS11 keystore. Also utilities for working with DNSSEC
+compiled with native PKCS#11 functionality are included.
+
+%package pkcs11-libs
+Summary: Bind libraries compiled with native PKCS#11
+Group:   System Environment/Daemons
+Requires: bind-license = %{epoch}:%{version}-%{release}
+Requires: bind-libs = %{epoch}:%{version}-%{release}
+
+%description pkcs11-libs
+This is a set of BIND libraries (dns, isc) compiled with native PKCS#11
+functionality.
+
+%package pkcs11-devel
+Summary: Development files for Bind libraries compiled with native PKCS#11
+Group:   System Environment/Daemons
+Requires: bind-pkcs11-libs = %{epoch}:%{version}-%{release}
+
+%description pkcs11-devel
+This a set of development files for BIND libraries (dns, isc) compiled
+with native PKCS#11 functionality.
 %endif
 
 %if %{SDB}
@@ -303,7 +338,6 @@ Based on the code from Jan "Yenya" Kasprzak <kas@fi.muni.cz>
 
 %patch102 -p1 -b .rh452060
 %patch106 -p0 -b .rh490837
-%patch107 -p1 -b .dist-pkcs11
 %patch109 -p1 -b .rh478718
 %patch110 -p1 -b .rh570851
 %patch111 -p1 -b .exportlib
@@ -329,10 +363,28 @@ popd
 %patch146 -p1 -b .rh1098959
 %patch147 -p1 -b .CVE-2014-8500
 %patch148 -p1 -b .CVE-2015-1349
-%patch149 -p1 -b .CVE-2015-4620
-%patch150 -p1 -b .CVE-2015-5477
-%patch151 -p1 -b .rh1215687-limits
-%patch152 -p1 -b .sock-maxevent
+%patch149 -p1 -b .rh1215687-limits
+
+%patch150 -p1 -b .external_key
+%patch151 -p1 -b .native_pkcs11
+# http://cov01.lab.eng.brq.redhat.com/covscanhub/waiving/9377/
+%patch153 -p1 -b .coverity_9377
+%patch154 -p1 -b .rh1215164
+%patch155 -p1 -b .nsupdate_realm
+%patch156 -p1 -b .CVE-2015-4620
+%patch157 -p1 -b .CVE-2015-5477
+%patch158 -p1 -b .sock-maxevents
+%patch159 -p1 -b .CVE-2015-5722
+
+%if %{PKCS11}
+cp -r bin/named{,-pkcs11}
+cp -r bin/dnssec{,-pkcs11}
+cp -r lib/isc{,-pkcs11}
+cp -r lib/dns{,-pkcs11}
+cp -r lib/export/isc{,-pkcs11}
+cp -r lib/export/dns{,-pkcs11}
+%patch152 -p1 -b .dist_pkcs11
+%endif
 
 %if %{SDB}
 %patch101 -p1 -b .old-api
@@ -404,7 +456,8 @@ libtoolize -c -f; aclocal -I libtool.m4 --force; autoconf -f
   --with-export-includedir=%{_includedir} \
   --includedir=%{_includedir}/bind9 \
 %if %{PKCS11}
-  --with-pkcs11=%{_libdir}/pkcs11/PKCS11_API.so \
+  --enable-native-pkcs11 \
+  --with-pkcs11=%{_libdir}/pkcs11/libsofthsm2.so \
 %endif
 %if %{SDB}
   --with-dlopen=yes \
@@ -477,12 +530,9 @@ popd
 mkdir -p ${RPM_BUILD_ROOT}/%{chroot_prefix}/etc/{pki/dnssec-keys,named}
 mkdir -p ${RPM_BUILD_ROOT}/%{chroot_prefix}/%{_libdir}/bind
 # these are required to prevent them being erased during upgrade of previous
-# versions that included them (bug #130121):
 touch ${RPM_BUILD_ROOT}/%{chroot_prefix}/dev/null
 touch ${RPM_BUILD_ROOT}/%{chroot_prefix}/dev/random
 touch ${RPM_BUILD_ROOT}/%{chroot_prefix}/dev/zero
-touch ${RPM_BUILD_ROOT}/%{chroot_prefix}/etc/localtime
-
 touch ${RPM_BUILD_ROOT}/%{chroot_prefix}/etc/named.conf
 #end chroot
 
@@ -499,12 +549,9 @@ popd
 mkdir -p ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/etc/{pki/dnssec-keys,named}
 mkdir -p ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/%{_libdir}/bind
 # these are required to prevent them being erased during upgrade of previous
-# versions that included them (bug #130121):
 touch ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/dev/null
 touch ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/dev/random
 touch ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/dev/zero
-touch ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/etc/localtime
-
 touch ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/etc/named.conf
 %endif
 #end sdb-chroot
@@ -526,6 +573,9 @@ install -m 644 %{SOURCE39} ${RPM_BUILD_ROOT}%{_unitdir}
 install -m 644 %{SOURCE40} ${RPM_BUILD_ROOT}%{_unitdir}
 install -m 644 %{SOURCE45} ${RPM_BUILD_ROOT}%{_unitdir}
 %endif
+%if %{PKCS11}
+install -m 644 %{SOURCE47} ${RPM_BUILD_ROOT}%{_unitdir}
+%endif
 
 mkdir -p ${RPM_BUILD_ROOT}%{_libexecdir}
 install -m 755 %{SOURCE41} ${RPM_BUILD_ROOT}%{_libexecdir}/setup-named-chroot.sh
@@ -569,6 +619,22 @@ install -m 644 %{SOURCE33} ${RPM_BUILD_ROOT}%{_mandir}/man1/zonetodb.1
 install -m 644 %{SOURCE34} ${RPM_BUILD_ROOT}%{_mandir}/man1/zone2sqlite.1
 %endif
 
+# PKCS11 versions manpages
+%if %{PKCS11}
+pushd ${RPM_BUILD_ROOT}%{_mandir}/man8
+ln -s named.8.gz named-pkcs11.8.gz
+ln -s dnssec-checkds.8.gz dnssec-checkds-pkcs11.8.gz
+ln -s dnssec-coverage.8.gz dnssec-coverage-pkcs11.8.gz
+ln -s dnssec-dsfromkey.8.gz dnssec-dsfromkey-pkcs11.8.gz
+ln -s dnssec-keyfromlabel.8.gz dnssec-keyfromlabel-pkcs11.8.gz
+ln -s dnssec-keygen.8.gz dnssec-keygen-pkcs11.8.gz
+ln -s dnssec-revoke.8.gz dnssec-revoke-pkcs11.8.gz
+ln -s dnssec-settime.8.gz dnssec-settime-pkcs11.8.gz
+ln -s dnssec-signzone.8.gz dnssec-signzone-pkcs11.8.gz
+ln -s dnssec-verify.8.gz dnssec-verify-pkcs11.8.gz
+popd
+%endif
+
 # Ghost config files:
 touch ${RPM_BUILD_ROOT}%{_localstatedir}/log/named.log
 
@@ -593,8 +659,8 @@ for f in my.internal.zone.db slaves/my.slave.internal.zone.db slaves/my.ddns.int
 done
 :;
 
-mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/tmpfiles.d
-install -m 644 %{SOURCE35} ${RPM_BUILD_ROOT}%{_sysconfdir}/tmpfiles.d/named.conf
+mkdir -p ${RPM_BUILD_ROOT}%{_tmpfilesdir}
+install -m 644 %{SOURCE35} ${RPM_BUILD_ROOT}%{_tmpfilesdir}/named.conf
 
 mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/rwtab.d
 install -m 644 %{SOURCE43} ${RPM_BUILD_ROOT}%{_sysconfdir}/rwtab.d/named
@@ -641,6 +707,20 @@ fi
 %systemd_postun_with_restart named-sdb.service
 %endif
 
+%if %{PKCS11}
+%post pkcs11
+# Initial installation
+%systemd_post named-pkcs11.service
+
+%preun pkcs11
+# Package removal, not upgrade
+%systemd_preun named-pkcs11.service
+
+%postun pkcs11
+# Package upgrade, not uninstall
+%systemd_postun_with_restart named-pkcs11.service
+%endif
+
 %triggerpostun -n bind -- bind <= 32:9.5.0-20.b1
 if [ "$1" -gt 0 ]; then
   [ -e /etc/rndc.key ] && chown root:named /etc/rndc.key
@@ -679,8 +759,6 @@ if [ "$1" -gt 0 ]; then
     /bin/mknod %{chroot_prefix}/dev/zero c 1 5
   [ -e %{chroot_prefix}/dev/null ] || \
     /bin/mknod %{chroot_prefix}/dev/null c 1 3
-  rm -f %{chroot_prefix}/etc/localtime
-  cp /etc/localtime %{chroot_prefix}/etc/localtime
 fi;
 :;
 
@@ -695,7 +773,6 @@ fi;
 if [ "$1" -eq 0 ]; then
   # Package removal, not upgrade
   rm -f %{chroot_prefix}/dev/{random,zero,null}
-  rm -f %{chroot_prefix}/etc/localtime
 fi
 :;
 
@@ -715,8 +792,6 @@ if [ "$1" -gt 0 ]; then
     /bin/mknod %{chroot_sdb_prefix}/dev/zero c 1 5
   [ -e %{chroot_sdb_prefix}/dev/null ] || \
     /bin/mknod %{chroot_sdb_prefix}/dev/null c 1 3
-  rm -f %{chroot_sdb_prefix}/etc/localtime
-  cp /etc/localtime %{chroot_sdb_prefix}/etc/localtime
 fi;
 :;
 
@@ -731,7 +806,6 @@ fi;
 if [ "$1" -eq 0 ]; then
   # Package removal, not upgrade
   rm -f %{chroot_sdb_prefix}/dev/{random,zero,null}
-  rm -f %{chroot_sdb_prefix}/etc/localtime
 fi
 :;
 
@@ -751,7 +825,7 @@ rm -rf ${RPM_BUILD_ROOT}
 %config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/sysconfig/named
 %config(noreplace) %attr(0644,root,named) %{_sysconfdir}/named.iscdlv.key
 %config(noreplace) %attr(0644,root,named) %{_sysconfdir}/named.root.key
-%{_sysconfdir}/tmpfiles.d/named.conf
+%{_tmpfilesdir}/named.conf
 %{_sysconfdir}/rwtab.d/named
 %{_unitdir}/named.service
 %{_unitdir}/named-setup-rndc.service
@@ -762,6 +836,7 @@ rm -rf ${RPM_BUILD_ROOT}
 %{_sbindir}/named-journalprint
 %{_sbindir}/nsec3hash
 %{_sbindir}/dnssec*
+%exclude %{_sbindir}/dnssec*pkcs11
 %{_sbindir}/named-check*
 %{_sbindir}/lwresd
 %{_sbindir}/named
@@ -776,6 +851,7 @@ rm -rf ${RPM_BUILD_ROOT}
 %{_mandir}/man8/named.8*
 %{_mandir}/man8/lwresd.8*
 %{_mandir}/man8/dnssec*.8*
+%exclude %{_mandir}/man8/dnssec*-pkcs11.8*
 %{_mandir}/man8/named-checkconf.8*
 %{_mandir}/man8/named-checkzone.8*
 %{_mandir}/man8/named-compilezone.8*
@@ -840,10 +916,13 @@ rm -rf ${RPM_BUILD_ROOT}
 %defattr(-,root,root,-)
 %{_libdir}/*so.*
 %exclude %{_libdir}/*export.so.*
+%exclude %{_libdir}/*pkcs11.so.*
+%exclude %{_libdir}/*pkcs11-export.so.*
 
 %files libs-lite
 %defattr(-,root,root,-)
 %{_libdir}/*export.so.*
+%exclude %{_libdir}/*pkcs11-export.so.*
 
 %files license
 %defattr(-,root,root,-)
@@ -866,7 +945,11 @@ rm -rf ${RPM_BUILD_ROOT}
 %defattr(-,root,root,-)
 %{_libdir}/*so
 %exclude %{_libdir}/*export.so
+%exclude %{_libdir}/*pkcs11.so
+%exclude %{_libdir}/*pkcs11-export.so
 %{_includedir}/bind9
+%exclude %{_includedir}/bind9/pkcs11
+%exclude %{_includedir}/bind9/pk11
 %{_mandir}/man1/isc-config.sh.1*
 %{_mandir}/man3/lwres*
 %{_bindir}/isc-config.sh
@@ -875,6 +958,7 @@ rm -rf ${RPM_BUILD_ROOT}
 %files lite-devel
 %defattr(-,root,root,-)
 %{_libdir}/*export.so
+%exclude %{_libdir}/*pkcs11-export.so
 %{_includedir}/dns
 %{_includedir}/dst
 %{_includedir}/irs
@@ -889,7 +973,6 @@ rm -rf ${RPM_BUILD_ROOT}
 %ghost %{chroot_prefix}/dev/null
 %ghost %{chroot_prefix}/dev/random
 %ghost %{chroot_prefix}/dev/zero
-%ghost %{chroot_prefix}/etc/localtime
 %defattr(0640,root,named,0750)
 %dir %{chroot_prefix}
 %dir %{chroot_prefix}/dev
@@ -919,7 +1002,6 @@ rm -rf ${RPM_BUILD_ROOT}
 %ghost %{chroot_sdb_prefix}/dev/null
 %ghost %{chroot_sdb_prefix}/dev/random
 %ghost %{chroot_sdb_prefix}/dev/zero
-%ghost %{chroot_sdb_prefix}/etc/localtime
 %defattr(0640,root,named,0750)
 %dir %{chroot_sdb_prefix}
 %dir %{chroot_sdb_prefix}/dev
@@ -944,24 +1026,73 @@ rm -rf ${RPM_BUILD_ROOT}
 %if %{PKCS11}
 %files pkcs11
 %defattr(-,root,root,-)
-%doc COPYRIGHT
+%{_sbindir}/named-pkcs11
+%{_unitdir}/named-pkcs11.service
+%{_mandir}/man8/named-pkcs11.8*
+
+%files pkcs11-utils
+%defattr(-,root,root,-)
+%{_sbindir}/dnssec*pkcs11
 %{_sbindir}/pkcs11-destroy
 %{_sbindir}/pkcs11-keygen
 %{_sbindir}/pkcs11-list
-%{_mandir}/man8/pkcs11*
+%{_sbindir}/pkcs11-tokens
+%{_mandir}/man8/pkcs11*.8*
+%{_mandir}/man8/dnssec*-pkcs11.8*
+
+%files pkcs11-libs
+%defattr(-,root,root,-)
+%{_libdir}/*pkcs11.so.*
+%{_libdir}/*pkcs11-export.so.*
+
+%files pkcs11-devel
+%defattr(-,root,root,-)
+%{_includedir}/bind9/pk11
+%{_includedir}/bind9/pkcs11
+%{_libdir}/*pkcs11.so
+%{_libdir}/*pkcs11-export.so
+
 %endif
 
 %changelog
-* Thu Aug 06 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-18.4
-- DNS resolution failure in high load environment with SERVFAIL and "out of memory/success" in the log (#1221180)
-- Increase ISC_SOCKET_MAXEVENTS to 2048 (#1250561)
+* Wed Sep 02 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-29
+- Fix CVE-2015-5722
 
-* Mon Jul 27 2015 Florian Weimer <fweimer@redhat.com> - 32:9.9.4-18.3
+* Wed Aug 05 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-28
+- Increase ISC_SOCKET_MAXEVENTS to 2048 (#1235609)
+
+* Tue Jul 28 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-27
 - Fix CVE-2015-5477
 
-* Wed Jul 08 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-18.2
+* Wed Jul 08 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-26
 - Fix CVE-2015-4620
 
+* Tue Jul 07 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-25
+- Fixed nsupdate realm auto-detection (#1214827)
+
+* Mon Jun 29 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-24
+- Reintroduce the DISABLE_ZONE_CHECKING into /etc/sysconfig/named (#1236475)
+
+* Mon Jun 01 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-23
+- Don't copy /etc/localtime on -chroot package installation (#1186773)
+- Fix SPF resource records check to comply with RFC7208 (#1215164)
+- Don't use ISC's DLV by default (#1223336)
+
+* Fri May 22 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-22
+- Add version specific requires on bind for bind-pkcs11 (Related: #1097753)
+- Resolve issues found by static analysis (Related: #1097753)
+
+* Thu May 21 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-21
+- Added native PKCS#11 functionality (#1097753)
+
+* Wed May 20 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-20
+- DNS resolution failure in high load environment with SERVFAIL and "out of memory/success" in the log (#1221180)
+
+* Thu May 14 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-19
+- Install config for tmpfiles under %%{_tmpfilesdir} (#1180976)
+- Fixed systemctl path in logrotate configuration (#1164264)
+- remove information about system-config-bind from named.8 man page (#1152066)
+
 * Mon Mar 02 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-18.1
 - Fix CVE-2015-1349