pkcs11rsa_tofile(const dst_key_t *key, const char *directory) {
	int i;
	pk11_object_t *rsa;
	CK_ATTRIBUTE *attr;
	CK_ATTRIBUTE *modulus = NULL, *exponent = NULL;
	CK_ATTRIBUTE  *d = NULL, *p = NULL, *q = NULL;
	CK_ATTRIBUTE *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
	dst_private_t priv;
	unsigned char *bufs[10];
	isc_result_t result;

	if (key->keydata.pkey == NULL)
		return (DST_R_NULLKEY);

	if (key->external) {
		priv.nelements = 0;
		return (dst__privstruct_writefile(key, &priv, directory));
	}

	rsa = key->keydata.pkey;

	for (attr = pk11_attribute_first(rsa);
	     attr != NULL;
	     attr = pk11_attribute_next(rsa, attr))
		switch (attr->type) {
		case CKA_MODULUS:
			modulus = attr;
			break;
		case CKA_PUBLIC_EXPONENT:
			exponent = attr;
			break;
		case CKA_PRIVATE_EXPONENT:
			d = attr;
			break;
		case CKA_PRIME_1:
			p = attr;
			break;
		case CKA_PRIME_2:
			q = attr;
			break;
		case CKA_EXPONENT_1:
			dmp1 = attr;
			break;
		case CKA_EXPONENT_2:
			dmq1 = attr;
			break;
		case CKA_COEFFICIENT:
			iqmp = attr;
			break;
		}
	if ((modulus == NULL) || (exponent == NULL))
		return (DST_R_NULLKEY);

	memset(bufs, 0, sizeof(bufs));

	for (i = 0; i < 10; i++) {
		bufs[i] = isc_mem_get(key->mctx, modulus->ulValueLen);
		if (bufs[i] == NULL) {
			result = ISC_R_NOMEMORY;
			goto fail;
		}
		memset(bufs[i], 0, modulus->ulValueLen);
	}

	i = 0;

	priv.elements[i].tag = TAG_RSA_MODULUS;
	priv.elements[i].length = (unsigned short) modulus->ulValueLen;
	memmove(bufs[i], modulus->pValue, modulus->ulValueLen);
	priv.elements[i].data = bufs[i];
	i++;

	priv.elements[i].tag = TAG_RSA_PUBLICEXPONENT;
	priv.elements[i].length = (unsigned short) exponent->ulValueLen;
	memmove(bufs[i], exponent->pValue, exponent->ulValueLen);
	priv.elements[i].data = bufs[i];
	i++;

	if (d != NULL) {
		priv.elements[i].tag = TAG_RSA_PRIVATEEXPONENT;
		priv.elements[i].length = (unsigned short) d->ulValueLen;
		memmove(bufs[i], d->pValue, d->ulValueLen);
		priv.elements[i].data = bufs[i];
		i++;
	}

	if (p != NULL) {
		priv.elements[i].tag = TAG_RSA_PRIME1;
		priv.elements[i].length = (unsigned short) p->ulValueLen;
		memmove(bufs[i], p->pValue, p->ulValueLen);
		priv.elements[i].data = bufs[i];
		i++;
	}

	if (q != NULL) {
		priv.elements[i].tag = TAG_RSA_PRIME2;
		priv.elements[i].length = (unsigned short) q->ulValueLen;
		memmove(bufs[i], q->pValue, q->ulValueLen);
		priv.elements[i].data = bufs[i];
		i++;
	}

	if (dmp1 != NULL) {
		priv.elements[i].tag = TAG_RSA_EXPONENT1;
		priv.elements[i].length = (unsigned short) dmp1->ulValueLen;
		memmove(bufs[i], dmp1->pValue, dmp1->ulValueLen);
		priv.elements[i].data = bufs[i];
		i++;
	}

	if (dmq1 != NULL) {
		priv.elements[i].tag = TAG_RSA_EXPONENT2;
		priv.elements[i].length = (unsigned short) dmq1->ulValueLen;
		memmove(bufs[i], dmq1->pValue, dmq1->ulValueLen);
		priv.elements[i].data = bufs[i];
		i++;
	}

	if (iqmp != NULL) {
		priv.elements[i].tag = TAG_RSA_COEFFICIENT;
		priv.elements[i].length = (unsigned short) iqmp->ulValueLen;
		memmove(bufs[i], iqmp->pValue, iqmp->ulValueLen);
		priv.elements[i].data = bufs[i];
		i++;
	}

	if (key->engine != NULL) {
		priv.elements[i].tag = TAG_RSA_ENGINE;
		priv.elements[i].length =
			(unsigned short)strlen(key->engine) + 1;
		priv.elements[i].data = (unsigned char *)key->engine;
		i++;
	}

	if (key->label != NULL) {
		priv.elements[i].tag = TAG_RSA_LABEL;
		priv.elements[i].length =
			(unsigned short)strlen(key->label) + 1;
		priv.elements[i].data = (unsigned char *)key->label;
		i++;
	}

	priv.nelements = i;
	result = dst__privstruct_writefile(key, &priv, directory);
 fail:
	for (i = 0; i < 10; i++) {
		if (bufs[i] == NULL)
			break;
		isc_safe_memwipe(bufs[i], modulus->ulValueLen);
		isc_mem_put(key->mctx, bufs[i], modulus->ulValueLen);
	}
	return (result);
}