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;
	isc_region_consume(&r, 1);
	if (t > 8) {
		isc_safe_memwipe(dsa, sizeof(*dsa));
		isc_mem_put(key->mctx, dsa, sizeof(*dsa));
		return (DST_R_INVALIDPUBLICKEY);
	}
	p_bytes = 64 + 8 * t;

	if (r.length < ISC_SHA1_DIGESTLENGTH + 3 * p_bytes) {
		isc_safe_memwipe(dsa, sizeof(*dsa));
		isc_mem_put(key->mctx, dsa, sizeof(*dsa));
		return (DST_R_INVALIDPUBLICKEY);
	}

	subprime = r.base;
	isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH);

	prime = r.base;
	isc_region_consume(&r, p_bytes);

	base = r.base;
	isc_region_consume(&r, p_bytes);

	pub_key = r.base;
	isc_region_consume(&r, 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;
	memmove(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;
	memmove(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;
	memmove(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;
	memmove(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) {
				isc_safe_memwipe(attr->pValue,
						 attr->ulValueLen);
				isc_mem_put(key->mctx,
					    attr->pValue,
					    attr->ulValueLen);
			}
			break;
		}
	if (dsa->repr != NULL) {
		isc_safe_memwipe(dsa->repr, dsa->attrcnt * sizeof(*attr));
		isc_mem_put(key->mctx,
			    dsa->repr,
			    dsa->attrcnt * sizeof(*attr));
	}
	isc_safe_memwipe(dsa, sizeof(*dsa));
	isc_mem_put(key->mctx, dsa, sizeof(*dsa));
	return (ISC_R_NOMEMORY);
}
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;
	isc_region_consume(&r, 1);
	if (t > 8) {
		isc_safe_memwipe(dsa, sizeof(*dsa));
		isc_mem_put(key->mctx, dsa, sizeof(*dsa));
		return (DST_R_INVALIDPUBLICKEY);
	}
	p_bytes = 64 + 8 * t;

	if (r.length < ISC_SHA1_DIGESTLENGTH + 3 * p_bytes) {
		isc_safe_memwipe(dsa, sizeof(*dsa));
		isc_mem_put(key->mctx, dsa, sizeof(*dsa));
		return (DST_R_INVALIDPUBLICKEY);
	}

	subprime = r.base;
	isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH);

	prime = r.base;
	isc_region_consume(&r, p_bytes);

	base = r.base;
	isc_region_consume(&r, p_bytes);

	pub_key = r.base;
	isc_region_consume(&r, 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;
	memmove(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;
	memmove(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;
	memmove(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;
	memmove(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) {
				isc_safe_memwipe(attr->pValue,
						 attr->ulValueLen);
				isc_mem_put(key->mctx,
					    attr->pValue,
					    attr->ulValueLen);
			}
			break;
		}
	if (dsa->repr != NULL) {
		isc_safe_memwipe(dsa->repr, dsa->attrcnt * sizeof(*attr));
		isc_mem_put(key->mctx,
			    dsa->repr,
			    dsa->attrcnt * sizeof(*attr));
	}
	isc_safe_memwipe(dsa, sizeof(*dsa));
	isc_mem_put(key->mctx, dsa, sizeof(*dsa));
	return (ISC_R_NOMEMORY);
}