From f5c17a057fc5974bb51d7bc8c5827a7fd6dc9aee Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 3 Jan 2017 16:40:59 -0800 Subject: [PATCH] [v9_11] add support for native pkcs11 on keyper 4547. [port] Add support for --enable-native-pkcs11 on the AEP Keyper HSM. [RT #42463] --- CHANGES | 3 + configure | 20 +- configure.in | 4 +- lib/dns/pkcs11dh_link.c | 5 +- lib/dns/pkcs11dsa_link.c | 14 +- lib/dns/pkcs11ecdsa_link.c | 8 +- lib/dns/pkcs11gost_link.c | 16 +- lib/dns/pkcs11rsa_link.c | 509 +++++++++++++++++++++++++++++++ lib/isc/include/pk11/README.site | 3 +- lib/isc/include/pk11/site.h | 17 +- lib/isc/pk11.c | 20 +- 11 files changed, 596 insertions(+), 23 deletions(-) diff --git a/CHANGES b/CHANGES index 5f4cabe11b..a907dacdc6 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +4547. [port] Add support for --enable-native-pkcs11 on the AEP + Keyper HSM. [RT #42463] + --- 9.11.1b1 released --- 4545. [func] Expand YAML output from dnstap-read to include diff --git a/configure b/configure index c3eedb81fe..b5f6a6b66e 100755 --- a/configure +++ b/configure @@ -954,6 +954,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -1109,6 +1110,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1361,6 +1363,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1498,7 +1509,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1651,6 +1662,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -16721,8 +16733,10 @@ $as_echo "Cryptech" >&6; } set_pk11_flavor="yes" ;; *Keyper*) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: AEP Keyper: not yet supported" >&5 -$as_echo "AEP Keyper: not yet supported" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: AEP Keyper" >&5 +$as_echo "AEP Keyper" >&6; } + pk11_flavor="PK11_AEP_FLAVOR" + set_pk11_flavor="yes" ;; undefined) { $as_echo "$as_me:${as_lineno-$LINENO}: result: undefined provider?" >&5 diff --git a/configure.in b/configure.in index 097a6f8013..68dd978378 100644 --- a/configure.in +++ b/configure.in @@ -2184,7 +2184,9 @@ case "$want_native_pkcs11" in set_pk11_flavor="yes" ;; *Keyper*) - AC_MSG_RESULT(AEP Keyper: not yet supported) + AC_MSG_RESULT(AEP Keyper) + pk11_flavor="PK11_AEP_FLAVOR" + set_pk11_flavor="yes" ;; undefined) AC_MSG_RESULT(undefined provider?) diff --git a/lib/dns/pkcs11dh_link.c b/lib/dns/pkcs11dh_link.c index b9d895f3a6..701a2da091 100644 --- a/lib/dns/pkcs11dh_link.c +++ b/lib/dns/pkcs11dh_link.c @@ -191,8 +191,9 @@ pkcs11dh_computesecret(const dst_key_t *pub, const dst_key_t *priv, 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)); + ret = pk11_get_session(&ctx, OP_DH, ISC_TRUE, ISC_FALSE, + priv->keydata.pkey->reqlogon, NULL, + pk11_get_best_token(OP_DH)); if (ret != ISC_R_SUCCESS) return (ret); diff --git a/lib/dns/pkcs11dsa_link.c b/lib/dns/pkcs11dsa_link.c index 0737328f8b..9d595fc388 100644 --- a/lib/dns/pkcs11dsa_link.c +++ b/lib/dns/pkcs11dsa_link.c @@ -95,16 +95,20 @@ pkcs11dsa_createctx_sign(dst_key_t *key, dst_context_t *dctx) { isc_result_t ret; unsigned int i; + REQUIRE(key != NULL); + dsa = key->keydata.pkey; + REQUIRE(dsa != NULL); + 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)); + dsa->reqlogon, 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; @@ -225,16 +229,18 @@ pkcs11dsa_createctx_verify(dst_key_t *key, dst_context_t *dctx) { isc_result_t ret; unsigned int i; + dsa = key->keydata.pkey; + REQUIRE(dsa != NULL); 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)); + dsa->reqlogon, 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; diff --git a/lib/dns/pkcs11ecdsa_link.c b/lib/dns/pkcs11ecdsa_link.c index 473eaf4097..e2b5b3c5b1 100644 --- a/lib/dns/pkcs11ecdsa_link.c +++ b/lib/dns/pkcs11ecdsa_link.c @@ -74,9 +74,9 @@ pkcs11ecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { 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); + REQUIRE(ec != NULL); if (dctx->key->key_alg == DST_ALG_ECDSA256) mech.mechanism = CKM_SHA256; @@ -92,8 +92,8 @@ pkcs11ecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { 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); + ret = pk11_get_session(pk11_ctx, OP_EC, ISC_TRUE, ISC_FALSE, + ec->reqlogon, NULL, slotid); if (ret != ISC_R_SUCCESS) goto err; @@ -348,7 +348,7 @@ pkcs11ecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) { (pk11_ctx->session, digest, dgstlen, (CK_BYTE_PTR) sig->base, (CK_ULONG) sig->length), - DST_R_SIGNFAILURE); + DST_R_VERIFYFAILURE); err: diff --git a/lib/dns/pkcs11gost_link.c b/lib/dns/pkcs11gost_link.c index 79853a0b33..05d148c481 100644 --- a/lib/dns/pkcs11gost_link.c +++ b/lib/dns/pkcs11gost_link.c @@ -156,16 +156,20 @@ pkcs11gost_createctx_sign(dst_key_t *key, dst_context_t *dctx) { isc_result_t ret; unsigned int i; + REQUIRE(key != NULL); + gost = key->keydata.pkey; + REQUIRE(gost != NULL); + 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)); + gost->reqlogon, 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; @@ -257,16 +261,20 @@ pkcs11gost_createctx_verify(dst_key_t *key, dst_context_t *dctx) { isc_result_t ret; unsigned int i; + REQUIRE(key != NULL); + gost = key->keydata.pkey; + REQUIRE(gost != NULL); + 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)); + gost->reqlogon, 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; diff --git a/lib/dns/pkcs11rsa_link.c b/lib/dns/pkcs11rsa_link.c index 9fca8e309f..32948d93eb 100644 --- a/lib/dns/pkcs11rsa_link.c +++ b/lib/dns/pkcs11rsa_link.c @@ -47,6 +47,8 @@ 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); +#ifndef PK11_RSA_PKCS_REPLACE + static isc_result_t pkcs11rsa_createctx_sign(dst_key_t *key, dst_context_t *dctx) { CK_RV rv; @@ -499,6 +501,509 @@ pkcs11rsa_verify(dst_context_t *dctx, const isc_region_t *sig) { return (ret); } +#else + +/* + * CKM__RSA_PKCS mechanisms are not available so fall back + * to CKM_RSA_PKCS and do the EMSA-PKCS#1-v1.5 encapsulation by hand. + */ + +CK_BYTE md5_der[] = + { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, + 0x04, 0x10 }; +CK_BYTE sha1_der[] = + { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, + 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 }; +CK_BYTE sha256_der[] = + { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, + 0x00, 0x04, 0x20 }; +CK_BYTE sha512_der[] = + { 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, + 0x00, 0x04, 0x40 }; +#define MAX_DER_SIZE 19 +#define MIN_PKCS1_PADLEN 11 + +static isc_result_t +pkcs11rsa_createctx(dst_key_t *key, dst_context_t *dctx) { + CK_RV rv; + CK_MECHANISM mech = { 0, NULL, 0 }; + CK_SLOT_ID slotid; + pk11_object_t *rsa = key->keydata.pkey; + pk11_context_t *pk11_ctx; + isc_result_t ret; + +#ifndef PK11_MD5_DISABLE + 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); +#else + REQUIRE(key->key_alg == DST_ALG_RSASHA1 || + key->key_alg == DST_ALG_NSEC3RSASHA1 || + key->key_alg == DST_ALG_RSASHA256 || + key->key_alg == DST_ALG_RSASHA512); +#endif + REQUIRE(rsa != NULL); + + switch (key->key_alg) { +#ifndef PK11_MD5_DISABLE + case DST_ALG_RSAMD5: + mech.mechanism = CKM_MD5; + break; +#endif + case DST_ALG_RSASHA1: + case DST_ALG_NSEC3RSASHA1: + mech.mechanism = CKM_SHA_1; + break; + case DST_ALG_RSASHA256: + mech.mechanism = CKM_SHA256; + break; + case DST_ALG_RSASHA512: + mech.mechanism = CKM_SHA512; + break; + default: + INSIST(0); + } + + 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; + + 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 +pkcs11rsa_destroyctx(dst_context_t *dctx) { + CK_BYTE garbage[ISC_SHA512_DIGESTLENGTH]; + CK_ULONG len = ISC_SHA512_DIGESTLENGTH; + pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; + + 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 +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; + + 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 +pkcs11rsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { + CK_RV rv; + CK_MECHANISM mech = { CKM_RSA_PKCS, NULL, 0 }; + CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; + 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_BYTE digest[MAX_DER_SIZE + ISC_SHA512_DIGESTLENGTH]; + CK_BYTE *der; + CK_ULONG derlen; + CK_ULONG hashlen; + CK_ULONG dgstlen; + CK_ULONG siglen = 0; + pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; + dst_key_t *key = dctx->key; + pk11_object_t *rsa = key->keydata.pkey; + isc_region_t r; + isc_result_t ret = ISC_R_SUCCESS; + unsigned int i; + +#ifndef PK11_MD5_DISABLE + 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); +#else + REQUIRE(key->key_alg == DST_ALG_RSASHA1 || + key->key_alg == DST_ALG_NSEC3RSASHA1 || + key->key_alg == DST_ALG_RSASHA256 || + key->key_alg == DST_ALG_RSASHA512); +#endif + REQUIRE(rsa != NULL); + + switch (key->key_alg) { +#ifndef PK11_MD5_DISABLE + case DST_ALG_RSAMD5: + der = md5_der; + derlen = sizeof(md5_der); + hashlen = ISC_MD5_DIGESTLENGTH; + break; +#endif + case DST_ALG_RSASHA1: + case DST_ALG_NSEC3RSASHA1: + der = sha1_der; + derlen = sizeof(sha1_der); + hashlen = ISC_SHA1_DIGESTLENGTH; + break; + case DST_ALG_RSASHA256: + der = sha256_der; + derlen = sizeof(sha256_der); + hashlen = ISC_SHA256_DIGESTLENGTH; + break; + case DST_ALG_RSASHA512: + der = sha512_der; + derlen = sizeof(sha512_der); + hashlen = ISC_SHA512_DIGESTLENGTH; + break; + default: + INSIST(0); + } + dgstlen = derlen + hashlen; + INSIST(dgstlen <= sizeof(digest)); + memmove(digest, der, derlen); + + PK11_RET(pkcs_C_DigestFinal, + (pk11_ctx->session, digest + derlen, &hashlen), + DST_R_SIGNFAILURE); + + isc_buffer_availableregion(sig, &r); + if (r.length < (unsigned int) dgstlen + MIN_PKCS1_PADLEN) + return (ISC_R_NOSPACE); + + 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); + memmove(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); + memmove(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); + memmove(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); + memmove(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); + memmove(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); + memmove(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); + memmove(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); + memmove(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, + &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, + NULL, &siglen), + DST_R_SIGNFAILURE); + + if (r.length < (unsigned int) siglen) + return (ISC_R_NOSPACE); + + 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 = 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)); + dctx->ctxdata.pk11_ctx = NULL; + + return (ret); +} + +static isc_result_t +pkcs11rsa_verify(dst_context_t *dctx, const isc_region_t *sig) { + CK_RV rv; + CK_MECHANISM mech = { CKM_RSA_PKCS, NULL, 0 }; + CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; + 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; + CK_BYTE digest[MAX_DER_SIZE + ISC_SHA512_DIGESTLENGTH]; + CK_BYTE *der; + CK_ULONG derlen; + CK_ULONG hashlen; + CK_ULONG dgstlen; + pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; + dst_key_t *key = dctx->key; + pk11_object_t *rsa = key->keydata.pkey; + isc_result_t ret = ISC_R_SUCCESS; + unsigned int i; + +#ifndef PK11_MD5_DISABLE + 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); +#else + REQUIRE(key->key_alg == DST_ALG_RSASHA1 || + key->key_alg == DST_ALG_NSEC3RSASHA1 || + key->key_alg == DST_ALG_RSASHA256 || + key->key_alg == DST_ALG_RSASHA512); +#endif + REQUIRE(rsa != NULL); + + switch (key->key_alg) { +#ifndef PK11_MD5_DISABLE + case DST_ALG_RSAMD5: + der = md5_der; + derlen = sizeof(md5_der); + hashlen = ISC_MD5_DIGESTLENGTH; + break; +#endif + case DST_ALG_RSASHA1: + case DST_ALG_NSEC3RSASHA1: + der = sha1_der; + derlen = sizeof(sha1_der); + hashlen = ISC_SHA1_DIGESTLENGTH; + break; + case DST_ALG_RSASHA256: + der = sha256_der; + derlen = sizeof(sha256_der); + hashlen = ISC_SHA256_DIGESTLENGTH; + break; + case DST_ALG_RSASHA512: + der = sha512_der; + derlen = sizeof(sha512_der); + hashlen = ISC_SHA512_DIGESTLENGTH; + break; + default: + INSIST(0); + } + dgstlen = derlen + hashlen; + INSIST(dgstlen <= sizeof(digest)); + memmove(digest, der, derlen); + + PK11_RET(pkcs_C_DigestFinal, + (pk11_ctx->session, digest + derlen, &hashlen), + DST_R_SIGNFAILURE); + + 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); + memmove(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); + memmove(keyTemplate[6].pValue, attr->pValue, + attr->ulValueLen); + keyTemplate[6].ulValueLen = attr->ulValueLen; + if (pk11_numbits(attr->pValue, + attr->ulValueLen) + > RSA_MAX_PUBEXP_BITS) + 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, + &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_VERIFYFAILURE); + + 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); +} +#endif + static isc_boolean_t pkcs11rsa_compare(const dst_key_t *key1, const dst_key_t *key2) { pk11_object_t *rsa1, *rsa2; @@ -1546,7 +2051,11 @@ pkcs11rsa_fromlabel(dst_key_t *key, const char *engine, const char *label, static dst_func_t pkcs11rsa_functions = { pkcs11rsa_createctx, +#ifndef PK11_RSA_PKCS_REPLACE pkcs11rsa_createctx2, +#else + NULL, /*%< createctx2 */ +#endif pkcs11rsa_destroyctx, pkcs11rsa_adddata, pkcs11rsa_sign, diff --git a/lib/isc/include/pk11/README.site b/lib/isc/include/pk11/README.site index 7e81f642b8..b595b91883 100644 --- a/lib/isc/include/pk11/README.site +++ b/lib/isc/include/pk11/README.site @@ -30,7 +30,8 @@ Current well-known HSMs are predefined in site.h according to HSM "flavors": ...and with experimental status: - OpenDNSSEC SoftHSMv1 with SHA224 support added - - Cryptech with SHA224 support added + - Cryptech + - AEP Keyper If BIND9 is configured with native PKCS#11 support (--enable-native-pkcs11), then pkcs11-tokens will raise an error when a mandatory algorithm is not diff --git a/lib/isc/include/pk11/site.h b/lib/isc/include/pk11/site.h index b877b0f7f7..3a4b8c63b6 100644 --- a/lib/isc/include/pk11/site.h +++ b/lib/isc/include/pk11/site.h @@ -28,6 +28,7 @@ /* current implemented flags are: PK11_DH_PKCS_PARAMETER_GEN_SKIP PK11_DSA_PARAMETER_GEN_SKIP +PK11_RSA_PKCS_REPLACE PK11_MD5_HMAC_REPLACE PK11_SHA_1_HMAC_REPLACE PK11_SHA224_HMAC_REPLACE @@ -48,8 +49,10 @@ PK11_DH_DISABLE #define PK11_SOFTHSMV1_FLAVOR 1 /* SoftHSMv2 */ #define PK11_SOFTHSMV2_FLAVOR 2 -/* Cryptech with SHA224 */ +/* Cryptech */ #define PK11_CRYPTECH_FLAVOR 3 +/* AEP Keyper */ +#define PK11_AEP_FLAVOR 4 /* Default is for Thales nCipher */ #ifndef PK11_FLAVOR @@ -87,4 +90,16 @@ PK11_DH_DISABLE #define PK11_SHA512_HMAC_REPLACE #endif +#if PK11_FLAVOR == PK11_AEP_FLAVOR +#define PK11_DH_DISABLE +#define PK11_DSA_DISABLE +#define PK11_RSA_PKCS_REPLACE +#define PK11_MD5_HMAC_REPLACE +#define PK11_SHA_1_HMAC_REPLACE +#define PK11_SHA224_HMAC_REPLACE +#define PK11_SHA256_HMAC_REPLACE +#define PK11_SHA384_HMAC_REPLACE +#define PK11_SHA512_HMAC_REPLACE +#endif + #endif /* PK11_SITE_H */ diff --git a/lib/isc/pk11.c b/lib/isc/pk11.c index 0296da73f3..51db6c77e7 100644 --- a/lib/isc/pk11.c +++ b/lib/isc/pk11.c @@ -631,7 +631,7 @@ scan_slots(void) { if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0) || ((mechInfo.flags & CKF_VERIFY) == 0)) { -#ifndef PK11_MD5_DISABLE +#if !defined(PK11_MD5_DISABLE) && !defined(PK11_RSA_PKCS_REPLACE) bad = ISC_TRUE; #endif PK11_TRACEM(CKM_MD5_RSA_PKCS); @@ -641,7 +641,9 @@ scan_slots(void) { if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0) || ((mechInfo.flags & CKF_VERIFY) == 0)) { +#ifndef PK11_RSA_PKCS_REPLACE bad = ISC_TRUE; +#endif PK11_TRACEM(CKM_SHA1_RSA_PKCS); } rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256_RSA_PKCS, @@ -649,7 +651,9 @@ scan_slots(void) { if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0) || ((mechInfo.flags & CKF_VERIFY) == 0)) { +#ifndef PK11_RSA_PKCS_REPLACE bad = ISC_TRUE; +#endif PK11_TRACEM(CKM_SHA256_RSA_PKCS); } rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512_RSA_PKCS, @@ -657,9 +661,20 @@ scan_slots(void) { if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0) || ((mechInfo.flags & CKF_VERIFY) == 0)) { +#ifndef PK11_RSA_PKCS_REPLACE bad = ISC_TRUE; +#endif PK11_TRACEM(CKM_SHA512_RSA_PKCS); } + rv = pkcs_C_GetMechanismInfo(slot, CKM_RSA_PKCS, &mechInfo); + if ((rv != CKR_OK) || + ((mechInfo.flags & CKF_SIGN) == 0) || + ((mechInfo.flags & CKF_VERIFY) == 0)) { +#ifdef PK11_RSA_PKCS_REPLACE + bad = ISC_TRUE; +#endif + PK11_TRACEM(CKM_RSA_PKCS); + } if (bad) goto try_dsa; token->operations |= 1 << OP_RSA; @@ -1282,8 +1297,7 @@ pk11_error_fatalcheck(const char *file, int line, } void -pk11_dump_tokens(void) -{ +pk11_dump_tokens(void) { pk11_token_t *token; isc_boolean_t first;