예제 #1
0
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;
	memmove(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;
	memmove(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);
}
예제 #2
0
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);
			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) > 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);
}
예제 #3
0
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);
}
예제 #4
0
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);
			memmove(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);
}
예제 #5
0
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);
	memmove(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);
	memmove(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
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);
		memmove(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);
}