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;
return (ret);
}
+#else
+
+/*
+ * CKM_<hash>_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;
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,