pkcs11dh_todns(const dst_key_t *key, isc_buffer_t *data) {
	pk11_object_t *dh;
	CK_ATTRIBUTE *attr;
	isc_region_t r;
	uint16_t dnslen, plen = 0, glen = 0, publen = 0;
	CK_BYTE *prime = NULL, *base = NULL, *pub = NULL;

	REQUIRE(key->keydata.pkey != NULL);

	dh = key->keydata.pkey;

	for (attr = pk11_attribute_first(dh);
	     attr != NULL;
	     attr = pk11_attribute_next(dh, attr))
		switch (attr->type) {
		case CKA_VALUE:
			pub = (CK_BYTE *) attr->pValue;
			publen = (uint16_t) attr->ulValueLen;
			break;
		case CKA_PRIME:
			prime = (CK_BYTE *) attr->pValue;
			plen = (uint16_t) attr->ulValueLen;
			break;
		case CKA_BASE:
			base = (CK_BYTE *) attr->pValue;
			glen = (uint16_t) attr->ulValueLen;
			break;
		}
	REQUIRE((prime != NULL) && (base != NULL) && (pub != NULL));

	isc_buffer_availableregion(data, &r);

	if ((glen == 1) && isc_safe_memequal(pk11_dh_bn2, base, glen) &&
	    (((plen == sizeof(pk11_dh_bn768)) &&
	      isc_safe_memequal(pk11_dh_bn768, prime, plen)) ||
	     ((plen == sizeof(pk11_dh_bn1024)) &&
	      isc_safe_memequal(pk11_dh_bn1024, prime, plen)) ||
	     ((plen == sizeof(pk11_dh_bn1536)) &&
	      isc_safe_memequal(pk11_dh_bn1536, prime, plen)))) {
		plen = 1;
		glen = 0;
	}

	dnslen = plen + glen + publen + 6;
	if (r.length < (unsigned int) dnslen)
		return (ISC_R_NOSPACE);

	uint16_toregion(plen, &r);
	if (plen == 1) {
		if (isc_safe_memequal(pk11_dh_bn768, prime,
				      sizeof(pk11_dh_bn768)))
			*r.base = 1;
		else if (isc_safe_memequal(pk11_dh_bn1024, prime,
					   sizeof(pk11_dh_bn1024)))
			*r.base = 2;
		else
			*r.base = 3;
	}
	else
		memmove(r.base, prime, plen);
	isc_region_consume(&r, plen);

	uint16_toregion(glen, &r);
	if (glen > 0)
		memmove(r.base, base, glen);
	isc_region_consume(&r, glen);

	uint16_toregion(publen, &r);
	memmove(r.base, pub, publen);
	isc_region_consume(&r, publen);

	isc_buffer_add(data, dnslen);

	return (ISC_R_SUCCESS);
}
pkcs11dh_todns(const dst_key_t *key, isc_buffer_t *data) {
	pk11_object_t *dh;
	CK_ATTRIBUTE *attr;
	isc_region_t r;
	uint16_t dnslen, plen = 0, glen = 0, publen = 0;
	CK_BYTE *prime = NULL, *base = NULL, *pub = NULL;

	REQUIRE(key->keydata.pkey != NULL);

	dh = key->keydata.pkey;

	for (attr = pk11_attribute_first(dh);
	     attr != NULL;
	     attr = pk11_attribute_next(dh, attr))
		switch (attr->type) {
		case CKA_VALUE:
			pub = (CK_BYTE *) attr->pValue;
			publen = (uint16_t) attr->ulValueLen;
			break;
		case CKA_PRIME:
			prime = (CK_BYTE *) attr->pValue;
			plen = (uint16_t) attr->ulValueLen;
			break;
		case CKA_BASE:
			base = (CK_BYTE *) attr->pValue;
			glen = (uint16_t) attr->ulValueLen;
			break;
		}
	REQUIRE((prime != NULL) && (base != NULL) && (pub != NULL));

	isc_buffer_availableregion(data, &r);

	if ((glen == 1) && isc_safe_memequal(pk11_dh_bn2, base, glen) &&
	    (((plen == sizeof(pk11_dh_bn768)) &&
	      isc_safe_memequal(pk11_dh_bn768, prime, plen)) ||
	     ((plen == sizeof(pk11_dh_bn1024)) &&
	      isc_safe_memequal(pk11_dh_bn1024, prime, plen)) ||
	     ((plen == sizeof(pk11_dh_bn1536)) &&
	      isc_safe_memequal(pk11_dh_bn1536, prime, plen)))) {
		plen = 1;
		glen = 0;
	}

	dnslen = plen + glen + publen + 6;
	if (r.length < (unsigned int) dnslen)
		return (ISC_R_NOSPACE);

	uint16_toregion(plen, &r);
	if (plen == 1) {
		if (isc_safe_memequal(pk11_dh_bn768, prime,
				      sizeof(pk11_dh_bn768)))
			*r.base = 1;
		else if (isc_safe_memequal(pk11_dh_bn1024, prime,
					   sizeof(pk11_dh_bn1024)))
			*r.base = 2;
		else
			*r.base = 3;
	}
	else
		memmove(r.base, prime, plen);
	isc_region_consume(&r, plen);

	uint16_toregion(glen, &r);
	if (glen > 0)
		memmove(r.base, base, glen);
	isc_region_consume(&r, glen);

	uint16_toregion(publen, &r);
	memmove(r.base, pub, publen);
	isc_region_consume(&r, publen);

	isc_buffer_add(data, dnslen);

	return (ISC_R_SUCCESS);
}