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;
	isc_region_consume(&r, 1);

	cp = (CK_BYTE *) subprime->pValue;
	memmove(r.base + ISC_SHA1_DIGESTLENGTH - subprime->ulValueLen,
		cp, subprime->ulValueLen);
	isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH);
	cp = (CK_BYTE *) prime->pValue;
	memmove(r.base + key->key_size/8 - prime->ulValueLen,
		cp, prime->ulValueLen);
	isc_region_consume(&r, p_bytes);
	cp = (CK_BYTE *) base->pValue;
	memmove(r.base + key->key_size/8 - base->ulValueLen,
		cp, base->ulValueLen);
	isc_region_consume(&r, p_bytes);
	cp = (CK_BYTE *) pub_key->pValue;
	memmove(r.base + key->key_size/8 - pub_key->ulValueLen,
		cp, pub_key->ulValueLen);
	isc_region_consume(&r, p_bytes);

	isc_buffer_add(data, dnslen);

	return (ISC_R_SUCCESS);
}
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;
	isc_region_consume(&r, 1);

	cp = (CK_BYTE *) subprime->pValue;
	memmove(r.base + ISC_SHA1_DIGESTLENGTH - subprime->ulValueLen,
		cp, subprime->ulValueLen);
	isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH);
	cp = (CK_BYTE *) prime->pValue;
	memmove(r.base + key->key_size/8 - prime->ulValueLen,
		cp, prime->ulValueLen);
	isc_region_consume(&r, p_bytes);
	cp = (CK_BYTE *) base->pValue;
	memmove(r.base + key->key_size/8 - base->ulValueLen,
		cp, base->ulValueLen);
	isc_region_consume(&r, p_bytes);
	cp = (CK_BYTE *) pub_key->pValue;
	memmove(r.base + key->key_size/8 - pub_key->ulValueLen,
		cp, pub_key->ulValueLen);
	isc_region_consume(&r, p_bytes);

	isc_buffer_add(data, dnslen);

	return (ISC_R_SUCCESS);
}