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