From d56ed2d3a2736a07a09c268f3b2607cca8f1b6ca Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 19 2015 15:37:33 +0000 Subject: import bind-9.9.4-29.el7 --- 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 +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 ++.\" 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 ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#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 \n"); ++ fprintf(stderr, " -K : 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 @@ ++]> ++ ++ ++ ++ ++ ++ August 30, 2013 ++ ++ ++ ++ dnssec-importkey ++ 8 ++ BIND9 ++ ++ ++ ++ dnssec-importkey ++ Import DNSKEY records from external systems so they can be managed. ++ ++ ++ ++ ++ 2013 ++ Internet Systems Consortium, Inc. ("ISC") ++ ++ ++ ++ ++ ++ dnssec-importkey ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ DESCRIPTION ++ dnssec-importkey ++ read a DNSKEY record and generated a .key/.private key pair. ++ Publication () and deletions () ++ times can be set for the key. ++ ++ ++ ++ ++ OPTIONS ++ ++ ++ ++ -f filename ++ ++ ++ Filename to read the key from. ++ ++ ++ ++ ++ ++ -K directory ++ ++ ++ Sets the directory in which the key files are to reside. ++ ++ ++ ++ ++ ++ -L ttl ++ ++ ++ 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. ++ ++ ++ ++ ++ ++ -h ++ ++ ++ Emit usage message and exit. ++ ++ ++ ++ ++ ++ -v level ++ ++ ++ Sets the debugging level. ++ ++ ++ ++ ++ ++ ++ ++ ++ TIMING OPTIONS ++ ++ 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 date/offset ++ ++ ++ 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. ++ ++ ++ ++ ++ ++ -D date/offset ++ ++ ++ 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.) ++ ++ ++ ++ ++ ++ ++ ++ ++ SEE ALSO ++ ++ dnssec-keygen8 ++ , ++ ++ dnssec-signzone8 ++ , ++ BIND 9 Administrator Reference Manual, ++ RFC 5011. ++ ++ ++ ++ ++ AUTHOR ++ Internet Systems Consortium ++ ++ ++ ++ +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 @@ ++ ++ ++ ++ ++ ++dnssec-importkey ++ ++ ++
++
++
++

Name

++

dnssec-importkey — Import DNSKEY records from external systems so they can be managed.

++
++
++

Synopsis

++

dnssec-importkey [-f filename] [-K directory] [-P date/offset] [-D date/offset] [-h] [-v level] [keyname]

++
++
++

DESCRIPTION

++

dnssec-importkey ++ read a DNSKEY record and generated a .key/.private key pair. ++ Publication (-P) and deletions (-D) ++ times can be set for the key. ++

++
++
++

OPTIONS

++
++
-f filename
++

++ Filename to read the key from. ++

++
-K directory
++

++ Sets the directory in which the key files are to reside. ++

++
-L ttl
++

++ 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. ++

++
-h
++

++ Emit usage message and exit. ++

++
-v level
++

++ Sets the debugging level. ++

++
++
++
++

TIMING OPTIONS

++

++ 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 date/offset
++

++ 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. ++

++
-D date/offset
++

++ 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.) ++

++
++
++
++

SEE ALSO

++

dnssec-keygen(8), ++ dnssec-signzone(8), ++ BIND 9 Administrator Reference Manual, ++ RFC 5011. ++

++
++
++

AUTHOR

++

Internet Systems Consortium ++

++
++
++ +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 +Date: Mon, 22 Sep 2014 16:44:29 +0200 +Subject: [PATCH] Distributing native PKCS#11 BIND and utils + +Signed-off-by: Tomas Hozza +--- + 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 +Date: Thu, 21 May 2015 10:52:03 +0200 +Subject: [PATCH] native PKCS#11 + +Signed-off-by: Tomas Hozza +--- + 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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 \n"); ++ fprintf(stderr, " -f file: read key from zone file\n"); + fprintf(stderr, " -K : 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 \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 @@ + + + dnssec-importkey +- + ++ + + + + +- ++ ++ ++ ++ dnssec-importkey ++ ++ ++ ++ ++ ++ ++ ++ + + + + + DESCRIPTION + dnssec-importkey +- read a DNSKEY record and generated a .key/.private key pair. +- Publication () and deletions () +- 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. ++ ++ ++ The newly-created .private file does not ++ contain private key data, and cannot be used for signing. ++ However, having a .private file makes it possible to set ++ publication () and deletion ++ () 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. + + + +@@ -70,9 +93,16 @@ + + -f filename + +- +- Filename to read the key from. +- ++ ++ 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 . If the domain name is the same as ++ , then it may be omitted. ++ ++ ++ If is set to "-", then ++ the zone data is read from the standard input. ++ + + + +@@ -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 + 0 or none removes it. + + +@@ -160,6 +190,16 @@ + + + ++ FILES ++ ++ A keyfile can be designed by the key identification ++ Knnnn.+aaa+iiiii or the full file name ++ Knnnn.+aaa+iiiii.key as generated by ++ dnssec-keygen8. ++ ++ ++ ++ + SEE ALSO + + dnssec-keygen8 +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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 :\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 @@ + -E engine + + +- 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. ++ ++ ++ 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". + + + +@@ -143,9 +150,32 @@ + -l label + + +- 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. ++ ++ ++ When BIND 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:keylabel". ++ ++ ++ When BIND 9 is built with native PKCS#11 ++ support, the label is a PKCS#11 URI string in the format ++ "pkcs11:=value;=value;..." ++ 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. ++ ++ ++ If the label contains a ++ 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. + + + +@@ -429,7 +459,8 @@ + dnssec-signzone8 + , + BIND 9 Administrator Reference Manual, +- RFC 4034. ++ RFC 4034, ++ The PKCS#11 URI Scheme (draft-pechanec-pkcs11uri-13). + + + +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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 : (default: IN)\n"); + fprintf(stderr, " -d (0 => max, default)\n"); +-#ifdef USE_PKCS11 +- fprintf(stderr, " -E (default \"pkcs11\")\n"); ++ fprintf(stderr, " -E :\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 \n"); ++ fprintf(stderr, " name of an OpenSSL engine to use\n"); + #endif + fprintf(stderr, " -f : KSK | REVOKE\n"); + fprintf(stderr, " -g : use specified generator " +@@ -134,7 +143,6 @@ usage(void) { + "records with (default: 0)\n"); + fprintf(stderr, " -T : DNSKEY | KEY (default: DNSKEY; " + "use KEY for SIG(0))\n"); +- fprintf(stderr, " ECCGOST:\tignored\n"); + fprintf(stderr, " -t : " + "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 @@ + -E engine + + +- 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. ++ ++ ++ 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". + + + +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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 @@ + -E engine + + +- 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. ++ ++ ++ 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". + + + +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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 @@ + -E engine + + +- 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. ++ ++ ++ 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". + + + +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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 @@ + -E engine + + +- 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. ++ ++ ++ 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". + + + +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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 @@ + + + ++ -E engine ++ ++ ++ Specifies the cryptographic hardware to use, when applicable. ++ ++ ++ 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". ++ ++ ++ ++ ++ + -I input-format + + +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 + + #include ++#ifdef PKCS11CRYPTO ++#include ++#endif + + #include + +@@ -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 @@ + -E engine-name + + +- 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 +- engine-name +- 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. ++ ++ ++ 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". + + + +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 + #include + #include +-#include "cryptoki.h" + +-#ifdef WIN32 +-#define sleep(x) Sleep(x) +-#include "win32.c" +-#else +-#ifndef FORCE_STATIC_PROVIDER +-#include "unix.c" +-#endif +-#endif ++#include ++#include ++#include ++ ++#include ++#include + + #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 @@ + + + 2009 ++ 2014 + Internet Systems Consortium, Inc. ("ISC") + + +@@ -51,6 +52,7 @@ + -l label + + ++ + + + +@@ -62,9 +64,9 @@ + . + + +- 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. + + + +@@ -119,6 +121,17 @@ + + + ++ ++ ++ -w seconds ++ ++ ++ Specify how long to pause before carrying out key destruction. ++ The default is five seconds. If set to 0, ++ destruction will be immediate. ++ ++ ++ + + + +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 @@ + +
+

Synopsis

+-

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 seconds]

+
+
+-

DESCRIPTION

++

DESCRIPTION

+

+ pkcs11-destroy destroys keys stored in a + PKCS#11 device, identified by their ID or + label. +

+

+- 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. +

+
+
+-

ARGUMENTS

++

ARGUMENTS

+
+
-m module
+

+@@ -71,17 +71,23 @@ + Specify the PIN for the device. If no PIN is provided on the + command line, pkcs11-destroy will prompt for it. +

++
-w seconds
++

++ Specify how long to pause before carrying out key destruction. ++ The default is five seconds. If set to 0, ++ destruction will be immediate. ++

+
+
+
+-

SEE ALSO

++

SEE ALSO

+

+ pkcs11-list(3), + pkcs11-keygen(3) +

+
+
+-

AUTHOR

++

AUTHOR

+

Internet Systems Consortium +

+
+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 + #include + #include +-#include "cryptoki.h" + +-#ifdef WIN32 +-#include "win32.c" +-#else +-#ifndef FORCE_STATIC_PROVIDER +-#include "unix.c" +-#endif +-#endif ++#include ++#include ++#include ++ ++#include ++#include ++#define WANT_DH_PRIMES ++#define WANT_ECC_CURVES ++#include + + #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 @@ + --> + + +- ++ + +- Sep 18, 2009 ++ Feb 30, 2012 + + + +- pkcs11-keygen ++ pkcs11-ecgen + 8 + BIND9 + + + + pkcs11-keygen +- generate RSA keys on a PKCS#11 device ++ generate keys on a PKCS#11 device + + + + + 2009 ++ 2014 + Internet Systems Consortium, Inc. ("ISC") + + +@@ -44,14 +45,17 @@ + + + pkcs11-keygen +- +- +- ++ -a algorithm ++ + +- -b keysize +- -l label + ++ ++ + ++ ++ ++ ++ label + + + +@@ -59,8 +63,8 @@ + DESCRIPTION + + pkcs11-keygen causes a PKCS#11 device to generate +- a new RSA key pair with the specified and +- with bits of modulus. ++ a new key pair with the given (which must be ++ unique) and with bits of prime. + + + +@@ -68,83 +72,109 @@ + ARGUMENTS + + +- -P ++ -a algorithm + + +- 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 ++ 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". + + + + + +- -m module ++ -b keysize + + +- 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 bits of ++ prime. For ECC keys, the only valid values are 256 and 384, ++ and the default is 256. + + + + + +- -s slot ++ -e + + +- Open the session with the given PKCS#11 slot. The default is +- slot 0. ++ For RSA keys only, use a large exponent. + + + + + +- -e ++ -i id + + +- 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. + + + + + +- -b keysize ++ -m module + + +- Create the key pair with 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. ++ ++ ++ ++ ++ ++ -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. + + + + + +- -l label ++ -p PIN + + +- 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, pkcs11-ecgen will ++ prompt for it. + + + + + +- -i id ++ -q + + +- 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. ++ ++ ++ ++ ++ ++ -S ++ ++ ++ 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 PIN ++ -s slot + + +- Specify the PIN for the device. If no PIN is provided on the +- command line, pkcs11-keygen will prompt for it. ++ Open the session with the given PKCS#11 slot. The default is ++ slot 0. + + + +@@ -155,6 +185,12 @@ + SEE ALSO + + ++ pkcs11-rsagen3 ++ , ++ ++ pkcs11-dsagen3 ++ , ++ + pkcs11-list3 + , + +@@ -167,11 +203,6 @@ + + + +- CAVEAT +- Some PKCS#11 providers crash with big public exponent. +- +- +- + AUTHOR + Internet Systems Consortium + +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 @@ + + + +-pkcs11-keygen ++pkcs11-ecgen + + +
+-
++
+
+

Name

+-

pkcs11-keygen — generate RSA keys on a PKCS#11 device

++

pkcs11-keygen — generate keys on a PKCS#11 device

+
+
+

Synopsis

+-

pkcs11-keygen [-P] [-m module] [-s slot] [-e] {-b keysize} {-l label} [-i id] [-p PIN]

++

pkcs11-keygen {-a algorithm} [-b keysize] [-e] [-i id] [-m module] [-P] [-p PIN] [-q] [-S] [-s slot] {label}

+
+
+-

DESCRIPTION

++

DESCRIPTION

+

+ pkcs11-keygen causes a PKCS#11 device to generate +- a new RSA key pair with the specified label and +- with keysize bits of modulus. ++ a new key pair with the given label (which must be ++ unique) and with keysize bits of prime. +

+
+
+-

ARGUMENTS

++

ARGUMENTS

+
+-
-P
++
-a algorithm
+

+- 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 ++ algorithm 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". ++

++
-b keysize
++

++ Create the key pair with keysize bits of ++ prime. For ECC keys, the only valid values are 256 and 384, ++ and the default is 256. ++

++
-e
++

++ For RSA keys only, use a large exponent. ++

++
-i id
++

++ Create key objects with id. The id is either ++ an unsigned short 2 byte or an unsigned long 4 byte number. +

+
-m module
+

+@@ -55,51 +72,48 @@ + path to a shared library object implementing the PKCS#11 API + for the device. +

+-
-s slot
+-

+- Open the session with the given PKCS#11 slot. The default is +- slot 0. +-

+-
-e
++
-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. +

+-
-b keysize
++
-p PIN
+

+- Create the key pair with keysize bits of +- modulus. ++ Specify the PIN for the device. If no PIN is provided on ++ the command line, pkcs11-ecgen will ++ prompt for it. +

+-
-l label
++
-q
+

+- Create key objects with the given label. +- This name must be unique. ++ Quiet mode: suppress unnecessary output. +

+-
-i id
++
-S
+

+- 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 PIN
++
-s slot
+

+- Specify the PIN for the device. If no PIN is provided on the +- command line, pkcs11-keygen will prompt for it. ++ Open the session with the given PKCS#11 slot. The default is ++ slot 0. +

+
+
+
+-

SEE ALSO

++

SEE ALSO

+

++ pkcs11-rsagen(3), ++ pkcs11-dsagen(3), + pkcs11-list(3), + pkcs11-destroy(3), + dnssec-keyfromlabel(3), +

+
+
+-

CAVEAT

+-

Some PKCS#11 providers crash with big public exponent.

+-
+-
+-

AUTHOR

++

AUTHOR

+

Internet Systems Consortium +

+
+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 + #include + #include +-#include "cryptoki.h" + +-#ifdef WIN32 +-#include "win32.c" +-#else +-#ifndef FORCE_STATIC_PROVIDER +-#include "unix.c" +-#endif +-#endif ++#include ++#include ++#include ++ ++#include ++#include + + #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 ++.\" 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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++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 @@ ++]> ++ ++ ++ ++ ++ ++ August 25, 2013 ++ ++ ++ ++ pkcs11-tokens ++ 8 ++ BIND9 ++ ++ ++ ++ pkcs11-tokens ++ list PKCS#11 available tokens ++ ++ ++ ++ ++ 2013 ++ Internet Systems Consortium, Inc. ("ISC") ++ ++ ++ ++ ++ ++ pkcs11-tokens ++ ++ ++ ++ ++ ++ DESCRIPTION ++ ++ pkcs11-tokens ++ lists the PKCS#11 available tokens with defaults from the slot/token ++ scan performed at application initialization. ++ ++ ++ ++ ++ ARGUMENTS ++ ++ ++ -m module ++ ++ ++ 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. ++ ++ ++ ++ ++ ++ ++ ++ AUTHOR ++ Internet Systems Consortium ++ ++ ++ ++ +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 @@ ++ ++ ++ ++ ++ ++pkcs11-tokens ++ ++ ++
++
++
++

Name

++

pkcs11-tokens — list PKCS#11 available tokens

++
++
++

Synopsis

++

pkcs11-tokens [-m module]

++
++
++

DESCRIPTION

++

++ pkcs11-tokens ++ lists the PKCS#11 available tokens with defaults from the slot/token ++ scan performed at application initialization. ++

++
++
++

ARGUMENTS

++
++
-m module
++

++ 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. ++

++
++
++
++

AUTHOR

++

Internet Systems Consortium ++

++
++
++ +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 /* Required for HP/UX (and others?) */ + + #include ++#include + #include + #include + +@@ -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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 < /dev/null < 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 < 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 + + #include +@@ -44,8 +44,16 @@ + #include + #include + ++#ifdef OPENSSL + #include + #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 + #include + + 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 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 + #include +@@ -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 ++#include ++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 @@ + + + +- PKCS #11 (Cryptoki) support +- 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. +- 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. ++ PKCS#11 (Cryptoki) support ++ ++ 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. ++ ++ ++ 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. ++ ++ ++ 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. ++ ++ ++ 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. ++ + + Prerequisites +- See the HSM vendor documentation for information about +- installing, initializing, testing and troubleshooting the +- HSM. +- 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. +- 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. +- 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: ++ ++ See the documentation provided by your HSM vendor for ++ information about installing, initializing, testing and ++ troubleshooting the HSM. ++ ++ ++ ++ Native PKCS#11 ++ ++ Native PKCS#11 mode will only work with an HSM capable of carrying ++ out every 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.) ++ ++ ++ To build BIND with native PKCS#11, configure as follows: ++ ++ ++$ cd bind9 ++$ ./configure --enable-native-pkcs11 \ ++ --with-pkcs11=provider-library-path ++ ++ ++ This will cause all BIND tools, including named ++ and the dnssec-* and pkcs11-* ++ tools, to use the PKCS#11 provider library specified in ++ provider-library-path for cryptography. ++ (The provider library path can be overridden using the ++ in named and the ++ dnssec-* tools, or the in ++ the pkcs11-* tools.) ++ ++ ++ ++ OpenSSL-based PKCS#11 ++ ++ 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. ++ ++ ++ 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: ++ + + +- 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. ++ ++ 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. ++ + + +- 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 — 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. ++ ++ 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 — 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. ++ + + +- 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. ++ ++ 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. + + +- 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. ++ is expected to change. ++ + +- 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. +- Obtain OpenSSL 0.9.8s: +- +-$ wget http://www.openssl.org/source/openssl-0.9.8s.tar.gz +- +- Extract the tarball: +- +-$ tar zxf openssl-0.9.8s.tar.gz ++ 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. ++ ++ ++ Patching OpenSSL ++ ++$ wget http://www.openssl.org/source/openssl-0.9.8y.tar.gz ++ ++ Extract the tarball: ++ ++$ tar zxf openssl-0.9.8y.tar.gz + +- Apply the patch from the BIND 9 release: +- +-$ patch -p1 -d openssl-0.9.8s \ +- < bind9/bin/pkcs11/openssl-0.9.8s-patch ++ Apply the patch from the BIND 9 release: ++ ++$ patch -p1 -d openssl-0.9.8y \ ++ < bind9/bin/pkcs11/openssl-0.9.8y-patch + +- (Note that the patch file may not be compatible with the +- "patch" utility on all operating systems. You may need to +- install GNU patch.) +- 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. ++ ++ Note that the patch file may not be compatible with the ++ "patch" utility on all operating systems. You may need to ++ install GNU patch. ++ ++ ++ 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. ++ ++ ++ Later, when building BIND 9, the location of the custom-built ++ OpenSSL library will need to be specified via configure. ++ ++ + + + Building OpenSSL for the AEP Keyper on Linux +- 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. +- The Keyper-specific PKCS #11 provider library is +- delivered with the Keyper software. In this example, we place +- it /opt/pkcs11/usr/lib: ++ ++ 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. ++ ++ ++ The Keyper-specific PKCS#11 provider library is ++ delivered with the Keyper software. In this example, we place ++ it /opt/pkcs11/usr/lib: ++ + + $ cp pkcs11.GCC4.0.2.so.4.05 /opt/pkcs11/usr/lib/libpkcs11.so + +- 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. +- Finally, the Keyper library requires threads, so we +- must specify -pthread. ++ ++ 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. ++ ++ ++ Finally, the Keyper library requires threads, so we ++ must specify -pthread. ++ + +-$ cd openssl-0.9.8s ++$ cd openssl-0.9.8y + $ ./Configure linux-generic32 -m32 -pthread \ + --pk11-libname=/opt/pkcs11/usr/lib/libpkcs11.so \ + --pk11-flavor=sign-only \ + --prefix=/opt/pkcs11/usr + +- After configuring, run "make" +- and "make test". If "make +- test" fails with "pthread_atfork() not found", you forgot to +- add the -pthread above. ++ ++ After configuring, run "make" ++ and "make test". If "make ++ test" fails with "pthread_atfork() not found", you forgot to ++ add the -pthread above. ++ + + + + Building OpenSSL for the SCA 6000 on Solaris +- 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'. +- In this example, we are building on Solaris x86 on an +- AMD64 system. ++ ++ 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'. ++ ++ ++ In this example, we are building on Solaris x86 on an ++ AMD64 system. ++ + +-$ cd openssl-0.9.8s ++$ cd openssl-0.9.8y + $ ./Configure solaris64-x86_64-cc \ + --pk11-libname=/usr/lib/64/libpkcs11.so \ + --pk11-flavor=crypto-accelerator \ + --prefix=/opt/pkcs11/usr + +- (For a 32-bit build, use "solaris-x86-cc" and +- /usr/lib/libpkcs11.so.) +- After configuring, run +- make and +- make test. ++ ++ (For a 32-bit build, use "solaris-x86-cc" and /usr/lib/libpkcs11.so.) ++ ++ ++ After configuring, run ++ make and ++ make test. ++ + + + + Building OpenSSL for SoftHSM +- 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. +- 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: ++ ++ 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. ++ ++ ++ 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: ++ + + $ cd softhsm-1.3.0 + $ configure --prefix=/opt/pkcs11/usr +@@ -185,25 +282,31 @@ $ export SOFTHSM_CONF=/opt/pkcs11/softhsm.conf + $ echo "0:/opt/pkcs11/softhsm.db" > $SOFTHSM_CONF + $ /opt/pkcs11/usr/bin/softhsm --init-token 0 --slot 0 --label softhsm + +- 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. ++ ++ 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. ++ + +-$ cd openssl-0.9.8s ++$ cd openssl-0.9.8y + $ ./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 + +- After configuring, run "make" +- and "make test". ++ ++ After configuring, run "make" ++ and "make test". ++ + +- Once you have built OpenSSL, run +- "apps/openssl engine pkcs11" to confirm +- that PKCS #11 support was compiled in correctly. The output +- should be one of the following lines, depending on the flavor +- selected: ++ ++ Once you have built OpenSSL, run ++ "apps/openssl engine pkcs11" to confirm ++ that PKCS#11 support was compiled in correctly. The output ++ should be one of the following lines, depending on the flavor ++ selected: ++ + + (pkcs11) PKCS #11 engine support (sign only) + +@@ -211,29 +314,31 @@ $ ./Configure linux-x86_64 -pthread \ + + (pkcs11) PKCS #11 engine support (crypto accelerator) + +- Next, run +- "apps/openssl engine pkcs11 -t". This will +- attempt to initialize the PKCS #11 engine. If it is able to +- do so successfully, it will report +- [ available ]. +- If the output is correct, run +- "make install" which will install the +- modified OpenSSL suite to +- /opt/pkcs11/usr. +- +- +- Building BIND 9 with PKCS#11 +- When building BIND 9, the location of the custom-built +- OpenSSL library must be specified via configure. ++ ++ Next, run ++ "apps/openssl engine pkcs11 -t". This will ++ attempt to initialize the PKCS#11 engine. If it is able to ++ do so successfully, it will report ++ [ available ]. ++ ++ ++ If the output is correct, run ++ "make install" which will install the ++ modified OpenSSL suite to /opt/pkcs11/usr. ++ + + + Configuring BIND 9 for Linux with the AEP Keyper +- To link with the PKCS #11 provider, threads must be +- enabled in the BIND 9 build. +- 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. ++ ++ To link with the PKCS#11 provider, threads must be ++ enabled in the BIND 9 build. ++ ++ ++ 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. ++ + + $ cd ../bind9 + $ ./configure CC="gcc -m32" --enable-threads \ +@@ -244,8 +349,10 @@ $ ./configure CC="gcc -m32" --enable-threads \ + + + Configuring BIND 9 for Solaris with the SCA 6000 +- To link with the PKCS #11 provider, threads must be +- enabled in the BIND 9 build. ++ ++ To link with the PKCS#11 provider, threads must be ++ enabled in the BIND 9 build. ++ + + $ cd ../bind9 + $ ./configure CC="cc -xarch=amd64" --enable-threads \ +@@ -253,11 +360,13 @@ $ ./configure CC="cc -xarch=amd64" --enable-threads \ + --with-pkcs11=/usr/lib/64/libpkcs11.so + + (For a 32-bit build, omit CC="cc -xarch=amd64".) +- 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). ++ ++ 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). ++ + + + +@@ -266,63 +375,85 @@ $ ./configure CC="cc -xarch=amd64" --enable-threads \ + $ cd ../bind9 + $ ./configure --enable-threads \ + --with-openssl=/opt/pkcs11/usr \ +- --with-pkcs11=/opt/pkcs11/usr/lib/libpkcs11.so ++ --with-pkcs11=/opt/pkcs11/usr/lib/libsofthsm.so + + +- After configuring, run +- "make", +- "make test" and +- "make install". +- (Note: If "make test" fails in the "pkcs11" system test, you may +- have forgotten to set the SOFTHSM_CONF environment variable.) ++ ++ After configuring, run ++ "make", ++ "make test" and ++ "make install". ++ ++ ++ (Note: If "make test" fails in the "pkcs11" system test, you may ++ have forgotten to set the SOFTHSM_CONF environment variable.) ++ + + +- PKCS #11 Tools +- BIND 9 includes a minimal set of tools to operate the +- HSM, including +- pkcs11-keygen to generate a new key pair +- within the HSM, +- pkcs11-list to list objects currently +- available, and +- pkcs11-destroy to remove objects. +- 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.) ++ PKCS#11 Tools ++ ++ BIND 9 includes a minimal set of tools to operate the ++ HSM, including ++ pkcs11-keygen to generate a new key pair ++ within the HSM, ++ pkcs11-list to list objects currently ++ available, ++ pkcs11-destroy to remove objects, and ++ pkcs11-tokens to list available tokens. ++ ++ ++ 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.) ++ + + + Using the HSM +- First, we must set up the runtime environment so the +- OpenSSL and PKCS #11 libraries can be loaded: ++ ++ For OpenSSL-based PKCS#11, we must first set up the runtime ++ environment so the OpenSSL and PKCS#11 libraries can be loaded: ++ + + $ export LD_LIBRARY_PATH=/opt/pkcs11/usr/lib:${LD_LIBRARY_PATH} + +- 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 +- /opt/Keyper/PKCS11Provider/machine, +- use: ++ ++ This causes named and other binaries to load ++ the OpenSSL library from /opt/pkcs11/usr/lib ++ rather than from the default location. This step is not necessary ++ when using native PKCS#11. ++ ++ ++ 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 ++ /opt/Keyper/PKCS11Provider/machine, ++ use: ++ + + $ export KEYPER_LIBRARY_PATH=/opt/Keyper/PKCS11Provider + +- +- These environment variables must be set whenever running +- any tool that uses the HSM, including +- pkcs11-keygen, +- pkcs11-list, +- pkcs11-destroy, +- dnssec-keyfromlabel, +- dnssec-signzone, +- dnssec-keygen(which will use the HSM for +- random number generation), and +- named. +- 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": ++ ++ Such environment variables must be set whenever running ++ any tool that uses the HSM, including ++ pkcs11-keygen, ++ pkcs11-list, ++ pkcs11-destroy, ++ dnssec-keyfromlabel, ++ dnssec-signzone, ++ dnssec-keygen, and ++ named. ++ ++ ++ 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": ++ + + $ pkcs11-keygen -b 2048 -l sample-ksk + +@@ -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] + +- 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": ++ ++ 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": ++ + + $ dnssec-keyfromlabel -l sample-ksk -f KSK example.net + +- 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. +- 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: ++ ++ 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. ++ ++ ++ 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: ++ + + $ pkcs11-keygen -b 1024 -l sample-zsk + $ dnssec-keyfromlabel -l sample-zsk example.net + +- Alternatively, you may prefer to generate a conventional +- on-disk key, using dnssec-keygen: ++ ++ Alternatively, you may prefer to generate a conventional ++ on-disk key, using dnssec-keygen: ++ + + $ dnssec-keygen example.net + +- 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. +- Now you can sign the zone. (Note: If not using the -S +- option to +- dnssec-signzone, it will be necessary to add +- the contents of both +- K*.key files to the zone master file before +- signing it.) ++ ++ 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.) ++ ++ ++ Now you can sign the zone. (Note: If not using the -S ++ option to dnssec-signzone, it will be ++ necessary to add the contents of both K*.key ++ files to the zone master file before signing it.) ++ + + $ dnssec-signzone -S example.net + Enter PIN: +@@ -383,36 +526,50 @@ example.net.signed + + + Specifying the engine on the command line +- The OpenSSL engine can be specified in +- named and all of the BIND +- dnssec-* tools by using the "-E +- <engine>" 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. +- If you wish to disable use of the "pkcs11" engine — +- for troubleshooting purposes, or because the HSM is unavailable +- — set the engine to the empty string. For example: ++ ++ When using OpenSSL-based PKCS#11, the "engine" to be used by ++ OpenSSL can be specified in named and all of ++ the BIND dnssec-* tools by using the "-E ++ <engine>" 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. ++ ++ ++ If you wish to disable use of the "pkcs11" engine — ++ for troubleshooting purposes, or because the HSM is unavailable ++ — set the engine to the empty string. For example: ++ + + $ dnssec-signzone -E '' -S example.net + +- This causes +- dnssec-signzone to run as if it were compiled +- without the --with-pkcs11 option. ++ ++ This causes ++ dnssec-signzone to run as if it were compiled ++ without the --with-pkcs11 option. ++ ++ ++ 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. ++ + + + Running named with automatic zone re-signing +- If you want +- named 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, +- /opt/pkcs11/usr/ssl/openssl.cnf). +- The location of the openssl.cnf file can be overridden by +- setting the OPENSSL_CONF environment variable before running +- named. ++ ++ If you want named 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, ++ /opt/pkcs11/usr/ssl/openssl.cnf). ++ ++ ++ The location of the openssl.cnf file can be overridden by ++ setting the OPENSSL_CONF environment variable before running ++ named. ++ + Sample openssl.cnf: + + openssl_conf = openssl_def +@@ -423,22 +580,25 @@ $ dnssec-signzone -E '' -S example.net + [ pkcs11_section ] + PIN = <PLACE PIN HERE> + +- 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.) +- ++ ++ 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.) ++ ++ ++ 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 ++ pkcs11:object=local-zsk;pin-source=/etc/hsmpin", ++ then the PIN would be read from the file ++ /etc/hsmpin. ++ + +- 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. ++ ++ 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. ++ + + +- +- + +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 + +-#ifdef HAVE_OPENSSL_GOST +-#include +-#include +- +-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 ++#include ++#include ++ ++#define ISC_GOST_DIGESTLENGTH 32U ++ ++#ifdef HAVE_OPENSSL_GOST ++#include ++ ++typedef EVP_MD_CTX isc_gost_t; ++#endif ++#ifdef HAVE_PKCS11_GOST ++#include ++ ++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 ++#include ++#include ++ ++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 + +-#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 + #include +@@ -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 ++ ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++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 ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++#include "dst_internal.h" ++#include "dst_parse.h" ++#include "dst_pkcs11.h" ++ ++#include ++#include ++#define WANT_DH_PRIMES ++#include ++ ++#include ++ ++/* ++ * 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 ++ ++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 ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "dst_internal.h" ++#include "dst_parse.h" ++#include "dst_pkcs11.h" ++ ++#include ++ ++/* ++ * 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 ++ ++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 ++ ++#if defined(PKCS11CRYPTO) && defined(HAVE_PKCS11_ECDSA) ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "dst_internal.h" ++#include "dst_parse.h" ++#include "dst_pkcs11.h" ++ ++#include ++#include ++#define WANT_ECC_CURVES ++#include ++ ++#include ++ ++/* ++ * 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) ++ */ ++ ++#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 ++ ++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 ++ ++#if defined(PKCS11CRYPTO) && defined(HAVE_PKCS11_GOST) ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "dst_internal.h" ++#include "dst_parse.h" ++#include "dst_pkcs11.h" ++#include "dst_gost.h" ++ ++#include ++#include ++#define WANT_GOST_PARAMS ++#include ++ ++#include ++ ++/* ++ * 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: (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 ++ ++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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "dst_internal.h" ++#include "dst_parse.h" ++#include "dst_pkcs11.h" ++ ++#include ++ ++/* ++ * 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 ++ ++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 + ++#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 + ++#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 ++ ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#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 + #include + ++#include "dst_internal.h" ++ + #define TKEY_RANDOM_AMOUNT 16 + ++#ifdef PKCS11CRYPTO ++#include ++#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 + #include + ++#ifdef PKCS11CRYPTO ++#include ++#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 + #include + ++#if PKCS11CRYPTO || PKCS11CRYPTOWITHHMAC ++#include ++#include ++#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 + #include + ++#if PKCS11CRYPTO ++#include ++#include ++#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 ++ ++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 ++ ++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 ++ ++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 ++ ++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 ++ ++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 ++#include ++#include ++ ++#define PK11_FATALCHECK(func, args) \ ++ ((void) (((rv = (func) args) == CKR_OK) || \ ++ ((pk11_error_fatalcheck)(__FILE__, __LINE__, #func, rv), 0))) ++ ++#include ++ ++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 ++#include ++ ++/* ++ * Nothing in this file truly depends on , 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 /* 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 + #include + #include ++ ++#if PKCS11CRYPTO ++#include ++#include ++#endif ++ + #include + + #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 ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++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 + #include + +-#ifdef ISC_PLATFORM_OPENSSLHASH ++#if PKCS11CRYPTO ++#include ++#include ++#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 + #include + ++#if PKCS11CRYPTO ++#include ++#include ++#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 ++#define NULL_PTR NULL ++ ++#undef CK_PKCS11_FUNCTION_INFO ++ ++#include ++ ++#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 ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define KEEP_PKCS11_NAMES ++#include ++#include ++ ++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 +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 +--- + 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, ®); + 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 + #include + +-#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 +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 +--- + 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 @@ + + + When using GSS-TSIG use realm_name rather +- than the default realm in krb5.conf. If no ++ than leaving the realm detection up to GSSAPI. If no + realm is specified the saved realm is cleared. + + +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 @@ + +

+ When using GSS-TSIG use realm_name rather +- than the default realm in krb5.conf. If no ++ than leaving the realm detection up to GSSAPI. If no + realm is specified the saved realm is cleared. +

+
+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 @@ + -T mode + + +- 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 +- "warn" (default), "ignore". ++ 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 "warn" ++ (default), "ignore". + + + +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] + check-mx-cname ( warn | fail | ignore ); + check-srv-cname ( warn | fail | ignore ); + check-sibling yes_or_no; +- check-spf ( warn | fail | ignore ); ++ check-spf ( warn | ignore ); + allow-new-zones { yes_or_no }; + allow-notify { address_match_list }; + allow-query { address_match_list }; +@@ -6573,10 +6573,13 @@ options { + The default is yes. + + +- 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 + check-spf. + + +@@ -6618,11 +6621,11 @@ options { + check-spf + + +- 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 warn. ++ If check-integrity 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 ++ warn. + + + +@@ -10372,7 +10375,7 @@ view "external" { + check-names (warn|fail|ignore) ; + check-mx (warn|fail|ignore) ; + check-wildcard yes_or_no; +- check-spf ( warn | fail | ignore ); ++ check-spf ( warn | ignore ); + check-integrity yes_or_no ; + dialup dialup_option ; + file string ; +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 %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 - 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 - 32:9.9.4-29 +- Fix CVE-2015-5722 -* Mon Jul 27 2015 Florian Weimer - 32:9.9.4-18.3 +* Wed Aug 05 2015 Tomas Hozza - 32:9.9.4-28 +- Increase ISC_SOCKET_MAXEVENTS to 2048 (#1235609) + +* Tue Jul 28 2015 Tomas Hozza - 32:9.9.4-27 - Fix CVE-2015-5477 -* Wed Jul 08 2015 Tomas Hozza - 32:9.9.4-18.2 +* Wed Jul 08 2015 Tomas Hozza - 32:9.9.4-26 - Fix CVE-2015-4620 +* Tue Jul 07 2015 Tomas Hozza - 32:9.9.4-25 +- Fixed nsupdate realm auto-detection (#1214827) + +* Mon Jun 29 2015 Tomas Hozza - 32:9.9.4-24 +- Reintroduce the DISABLE_ZONE_CHECKING into /etc/sysconfig/named (#1236475) + +* Mon Jun 01 2015 Tomas Hozza - 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 - 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 - 32:9.9.4-21 +- Added native PKCS#11 functionality (#1097753) + +* Wed May 20 2015 Tomas Hozza - 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 - 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 - 32:9.9.4-18.1 - Fix CVE-2015-1349