#include "tpmtok_int.h"
CK_ULONG
ber_encode_INTEGER(CK_BBOOL length_only,
CK_BYTE ** ber_int,
CK_ULONG * ber_int_len,
CK_BYTE * data,
CK_ULONG data_len)
{
CK_BYTE *buf = NULL;
CK_ULONG len;
if (data_len < 128)
len = 1 + 1 + data_len;
else if (data_len < 256)
len = 1 + (1 + 1) + data_len;
else if (data_len < (1 << 16))
len = 1 + (1 + 2) + data_len;
else if (data_len < (1 << 24))
len = 1 + (1 + 3) + data_len;
else
return (CKR_FUNCTION_FAILED);
if (length_only == TRUE) {
*ber_int_len = len;
return (CKR_OK);
}
buf = (CK_BYTE *)malloc(len);
if (! buf) {
return (CKR_HOST_MEMORY);
}
if (data_len < 128) {
buf[0] = 0x02;
buf[1] = data_len;
(void) memcpy(&buf[2], data, data_len);
*ber_int_len = len;
*ber_int = buf;
return (CKR_OK);
}
if (data_len < 256) {
buf[0] = 0x02;
buf[1] = 0x81;
buf[2] = data_len;
(void) memcpy(&buf[3], data, data_len);
*ber_int_len = len;
*ber_int = buf;
return (CKR_OK);
}
if (data_len < (1 << 16)) {
buf[0] = 0x02;
buf[1] = 0x82;
buf[2] = (data_len >> 8) & 0xFF;
buf[3] = (data_len) & 0xFF;
(void) memcpy(&buf[4], data, data_len);
*ber_int_len = len;
*ber_int = buf;
return (CKR_OK);
}
if (data_len < (1 << 24)) {
buf[0] = 0x02;
buf[1] = 0x83;
buf[2] = (data_len >> 16) & 0xFF;
buf[3] = (data_len >> 8) & 0xFF;
buf[4] = (data_len) & 0xFF;
(void) memcpy(&buf[5], data, data_len);
*ber_int_len = len;
*ber_int = buf;
return (CKR_OK);
}
free(buf);
return (CKR_FUNCTION_FAILED);
}
CK_RV
ber_decode_INTEGER(CK_BYTE * ber_int,
CK_BYTE ** data,
CK_ULONG * data_len,
CK_ULONG * field_len)
{
CK_ULONG len, length_octets;
if (! ber_int) {
return (CKR_FUNCTION_FAILED);
}
if (ber_int[0] != 0x02) {
return (CKR_FUNCTION_FAILED);
}
if ((ber_int[1] & 0x80) == 0) {
len = ber_int[1] & 0x7F;
*data = &ber_int[2];
*data_len = len;
*field_len = 1 + 1 + len;
return (CKR_OK);
}
length_octets = ber_int[1] & 0x7F;
if (length_octets == 1) {
len = ber_int[2];
*data = &ber_int[3];
*data_len = len;
*field_len = 1 + (1 + 1) + len;
return (CKR_OK);
}
if (length_octets == 2) {
len = ber_int[2];
len = len << 8;
len |= ber_int[3];
*data = &ber_int[4];
*data_len = len;
*field_len = 1 + (1 + 2) + len;
return (CKR_OK);
}
if (length_octets == 3) {
len = ber_int[2];
len = len << 8;
len |= ber_int[3];
len = len << 8;
len |= ber_int[4];
*data = &ber_int[5];
*data_len = len;
*field_len = 1 + (1 + 3) + len;
return (CKR_OK);
}
return (CKR_FUNCTION_FAILED);
}
CK_RV
ber_encode_OCTET_STRING(CK_BBOOL length_only,
CK_BYTE ** str,
CK_ULONG * str_len,
CK_BYTE * data,
CK_ULONG data_len)
{
CK_BYTE *buf = NULL;
CK_ULONG len;
if (data_len < 128)
len = 1 + 1 + data_len;
else if (data_len < 256)
len = 1 + (1 + 1) + data_len;
else if (data_len < (1 << 16))
len = 1 + (1 + 2) + data_len;
else if (data_len < (1 << 24))
len = 1 + (1 + 3) + data_len;
else
return (CKR_FUNCTION_FAILED);
if (length_only == TRUE) {
*str_len = len;
return (CKR_OK);
}
buf = (CK_BYTE *)malloc(len);
if (! buf) {
return (CKR_HOST_MEMORY);
}
if (data_len < 128) {
buf[0] = 0x04;
buf[1] = data_len;
(void) memcpy(&buf[2], data, data_len);
*str_len = len;
*str = buf;
return (CKR_OK);
}
if (data_len < 256) {
buf[0] = 0x04;
buf[1] = 0x81;
buf[2] = data_len;
(void) memcpy(&buf[3], data, data_len);
*str_len = len;
*str = buf;
return (CKR_OK);
}
if (data_len < (1 << 16)) {
buf[0] = 0x04;
buf[1] = 0x82;
buf[2] = (data_len >> 8) & 0xFF;
buf[3] = (data_len) & 0xFF;
(void) memcpy(&buf[4], data, data_len);
*str_len = len;
*str = buf;
return (CKR_OK);
}
if (data_len < (1 << 24)) {
buf[0] = 0x04;
buf[1] = 0x83;
buf[2] = (data_len >> 16) & 0xFF;
buf[3] = (data_len >> 8) & 0xFF;
buf[4] = (data_len) & 0xFF;
(void) memcpy(&buf[5], data, data_len);
*str_len = len;
*str = buf;
return (CKR_OK);
}
free(buf);
return (CKR_FUNCTION_FAILED);
}
CK_RV
ber_decode_OCTET_STRING(CK_BYTE * str,
CK_BYTE ** data,
CK_ULONG * data_len,
CK_ULONG * field_len)
{
CK_ULONG len, length_octets;
if (! str) {
return (CKR_FUNCTION_FAILED);
}
if (str[0] != 0x04) {
return (CKR_FUNCTION_FAILED);
}
if ((str[1] & 0x80) == 0) {
len = str[1] & 0x7F;
*data = &str[2];
*data_len = len;
*field_len = 1 + (1) + len;
return (CKR_OK);
}
length_octets = str[1] & 0x7F;
if (length_octets == 1) {
len = str[2];
*data = &str[3];
*data_len = len;
*field_len = 1 + (1 + 1) + len;
return (CKR_OK);
}
if (length_octets == 2) {
len = str[2];
len = len << 8;
len |= str[3];
*data = &str[4];
*data_len = len;
*field_len = 1 + (1 + 2) + len;
return (CKR_OK);
}
if (length_octets == 3) {
len = str[2];
len = len << 8;
len |= str[3];
len = len << 8;
len |= str[4];
*data = &str[5];
*data_len = len;
*field_len = 1 + (1 + 3) + len;
return (CKR_OK);
}
return (CKR_FUNCTION_FAILED);
}
CK_RV
ber_encode_SEQUENCE(CK_BBOOL length_only,
CK_BYTE ** seq,
CK_ULONG * seq_len,
CK_BYTE * data,
CK_ULONG data_len)
{
CK_BYTE *buf = NULL;
CK_ULONG len;
if (data_len < 128)
len = 1 + 1 + data_len;
else if (data_len < 256)
len = 1 + (1 + 1) + data_len;
else if (data_len < (1 << 16))
len = 1 + (1 + 2) + data_len;
else if (data_len < (1 << 24))
len = 1 + (1 + 3) + data_len;
else
return (CKR_FUNCTION_FAILED);
if (length_only == TRUE) {
*seq_len = len;
return (CKR_OK);
}
buf = (CK_BYTE *)malloc(len);
if (! buf) {
return (CKR_HOST_MEMORY);
}
if (data_len < 128) {
buf[0] = 0x30;
buf[1] = data_len;
(void) memcpy(&buf[2], data, data_len);
*seq_len = len;
*seq = buf;
return (CKR_OK);
}
if (data_len < 256) {
buf[0] = 0x30;
buf[1] = 0x81;
buf[2] = data_len;
(void) memcpy(&buf[3], data, data_len);
*seq_len = len;
*seq = buf;
return (CKR_OK);
}
if (data_len < (1 << 16)) {
buf[0] = 0x30;
buf[1] = 0x82;
buf[2] = (data_len >> 8) & 0xFF;
buf[3] = (data_len) & 0xFF;
(void) memcpy(&buf[4], data, data_len);
*seq_len = len;
*seq = buf;
return (CKR_OK);
}
if (data_len < (1 << 24)) {
buf[0] = 0x30;
buf[1] = 0x83;
buf[2] = (data_len >> 16) & 0xFF;
buf[3] = (data_len >> 8) & 0xFF;
buf[4] = (data_len) & 0xFF;
(void) memcpy(&buf[5], data, data_len);
*seq_len = len;
*seq = buf;
return (CKR_OK);
}
return (CKR_FUNCTION_FAILED);
}
CK_RV
ber_decode_SEQUENCE(CK_BYTE * seq,
CK_BYTE ** data,
CK_ULONG * data_len,
CK_ULONG * field_len)
{
CK_ULONG len, length_octets;
if (! seq) {
return (CKR_FUNCTION_FAILED);
}
if (seq[0] != 0x30) {
return (CKR_FUNCTION_FAILED);
}
if ((seq[1] & 0x80) == 0) {
len = seq[1] & 0x7F;
*data = &seq[2];
*data_len = len;
*field_len = 1 + (1) + len;
return (CKR_OK);
}
length_octets = seq[1] & 0x7F;
if (length_octets == 1) {
len = seq[2];
*data = &seq[3];
*data_len = len;
*field_len = 1 + (1 + 1) + len;
return (CKR_OK);
}
if (length_octets == 2) {
len = seq[2];
len = len << 8;
len |= seq[3];
*data = &seq[4];
*data_len = len;
*field_len = 1 + (1 + 2) + len;
return (CKR_OK);
}
if (length_octets == 3) {
len = seq[2];
len = len << 8;
len |= seq[3];
len = len << 8;
len |= seq[4];
*data = &seq[5];
*data_len = len;
*field_len = 1 + (1 + 3) + len;
return (CKR_OK);
}
return (CKR_FUNCTION_FAILED);
}
CK_RV
ber_encode_PrivateKeyInfo(CK_BBOOL length_only,
CK_BYTE ** data,
CK_ULONG * data_len,
CK_BYTE * algorithm_id,
CK_ULONG algorithm_id_len,
CK_BYTE * priv_key,
CK_ULONG priv_key_len)
{
CK_BYTE * buf = NULL;
CK_BYTE * tmp = NULL;
CK_BYTE version[] = { 0 };
CK_BYTE attrib[] = { 0x05, 0x00 };
CK_ULONG len, total;
CK_RV rc;
len = 0;
rc = ber_encode_INTEGER(TRUE, NULL, &total, version, sizeof (version));
if (rc != CKR_OK) {
return (rc);
}
else
len += total;
len += algorithm_id_len;
rc = ber_encode_OCTET_STRING(TRUE, NULL, &total,
priv_key, priv_key_len);
if (rc != CKR_OK)
return (rc);
len += total;
len += sizeof (attrib);
if (length_only == TRUE) {
rc = ber_encode_SEQUENCE(TRUE, NULL, &total, NULL, len);
if (rc == CKR_OK)
*data_len = total;
return (rc);
}
buf = (CK_BYTE *)malloc(len);
if (! buf) {
return (CKR_HOST_MEMORY);
}
len = 0;
rc = ber_encode_INTEGER(FALSE, &tmp, &total, version, sizeof (version));
if (rc != CKR_OK) {
goto error;
}
(void) memcpy(buf + len, tmp, total);
len += total;
free(tmp);
(void) memcpy(buf + len, algorithm_id, algorithm_id_len);
len += algorithm_id_len;
rc = ber_encode_OCTET_STRING(FALSE, &tmp, &total,
priv_key, priv_key_len);
if (rc != CKR_OK) {
goto error;
}
(void) memcpy(buf + len, tmp, total);
len += total;
free(tmp);
(void) memcpy(buf + len, attrib, sizeof (attrib));
len += sizeof (attrib);
rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, len);
error:
free(buf);
return (rc);
}
CK_RV
ber_decode_PrivateKeyInfo(CK_BYTE * data,
CK_ULONG data_len,
CK_BYTE ** algorithm,
CK_ULONG * alg_len,
CK_BYTE ** priv_key)
{
CK_BYTE *buf = NULL;
CK_BYTE *alg = NULL;
CK_BYTE *ver = NULL;
CK_ULONG buf_len, offset, len, field_len;
CK_RV rc;
if (! data || (data_len == 0)) {
return (CKR_FUNCTION_FAILED);
}
rc = ber_decode_SEQUENCE(data, &buf, &buf_len, &field_len);
if (rc != CKR_OK) {
return (rc);
}
offset = 0;
rc = ber_decode_INTEGER(buf + offset, &ver, &len, &field_len);
if (rc != CKR_OK) {
return (rc);
}
offset += field_len;
rc = ber_decode_SEQUENCE(buf + offset, &alg, &len, &field_len);
if (rc != CKR_OK) {
return (rc);
}
*algorithm = alg;
*alg_len = len;
rc = ber_decode_OCTET_STRING(alg + len, priv_key, &buf_len, &field_len);
return (rc);
}
CK_RV
ber_encode_RSAPrivateKey(CK_BBOOL length_only,
CK_BYTE ** data,
CK_ULONG * data_len,
CK_ATTRIBUTE * modulus,
CK_ATTRIBUTE * publ_exp,
CK_ATTRIBUTE * priv_exp,
CK_ATTRIBUTE * prime1,
CK_ATTRIBUTE * prime2,
CK_ATTRIBUTE * exponent1,
CK_ATTRIBUTE * exponent2,
CK_ATTRIBUTE * coeff)
{
CK_BYTE *buf = NULL;
CK_BYTE *buf2 = NULL;
CK_ULONG len, offset;
CK_BYTE version[] = { 0 };
CK_RV rc;
offset = 0;
rc = 0;
rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL,
sizeof (version));
offset += len;
rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL,
modulus->ulValueLen);
offset += len;
rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL,
publ_exp->ulValueLen);
offset += len;
rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL,
priv_exp->ulValueLen);
offset += len;
rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL,
prime1->ulValueLen);
offset += len;
rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL,
prime2->ulValueLen);
offset += len;
rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL,
exponent1->ulValueLen);
offset += len;
rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL,
exponent2->ulValueLen);
offset += len;
rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL,
coeff->ulValueLen);
offset += len;
if (rc != CKR_OK) {
return (CKR_FUNCTION_FAILED);
}
if (length_only == TRUE) {
rc = ber_encode_SEQUENCE(TRUE, NULL, &len, NULL, offset);
if (rc != CKR_OK)
return (rc);
rc = ber_encode_PrivateKeyInfo(TRUE,
NULL, data_len,
NULL, ber_AlgIdRSAEncryptionLen,
NULL, len);
if (rc != CKR_OK)
return (rc);
return (rc);
}
buf = (CK_BYTE *)malloc(offset);
if (! buf) {
return (CKR_HOST_MEMORY);
}
offset = 0;
rc = 0;
rc = ber_encode_INTEGER(FALSE, &buf2, &len, version, sizeof (version));
if (rc != CKR_OK) {
goto error;
}
(void) memcpy(buf + offset, buf2, len);
offset += len;
free(buf2);
rc = ber_encode_INTEGER(FALSE, &buf2, &len,
(CK_BYTE *)modulus + sizeof (CK_ATTRIBUTE), modulus->ulValueLen);
if (rc != CKR_OK) {
goto error;
}
(void) memcpy(buf + offset, buf2, len);
offset += len;
free(buf2);
rc = ber_encode_INTEGER(FALSE, &buf2, &len,
(CK_BYTE *)publ_exp + sizeof (CK_ATTRIBUTE), publ_exp->ulValueLen);
if (rc != CKR_OK) {
goto error;
}
(void) memcpy(buf + offset, buf2, len);
offset += len;
free(buf2);
rc = ber_encode_INTEGER(FALSE, &buf2, &len,
(CK_BYTE *)priv_exp + sizeof (CK_ATTRIBUTE),
priv_exp->ulValueLen);
if (rc != CKR_OK) {
goto error;
}
(void) memcpy(buf + offset, buf2, len);
offset += len;
free(buf2);
rc = ber_encode_INTEGER(FALSE, &buf2, &len,
(CK_BYTE *)prime1 + sizeof (CK_ATTRIBUTE), prime1->ulValueLen);
if (rc != CKR_OK) {
goto error;
}
(void) memcpy(buf + offset, buf2, len);
offset += len;
free(buf2);
rc = ber_encode_INTEGER(FALSE, &buf2, &len,
(CK_BYTE *)prime2 + sizeof (CK_ATTRIBUTE), prime2->ulValueLen);
if (rc != CKR_OK) {
goto error;
}
(void) memcpy(buf + offset, buf2, len);
offset += len;
free(buf2);
rc = ber_encode_INTEGER(FALSE, &buf2, &len,
(CK_BYTE *)exponent1 + sizeof (CK_ATTRIBUTE),
exponent1->ulValueLen);
if (rc != CKR_OK) {
goto error;
}
(void) memcpy(buf + offset, buf2, len);
offset += len;
free(buf2);
rc = ber_encode_INTEGER(FALSE, &buf2, &len,
(CK_BYTE *)exponent2 + sizeof (CK_ATTRIBUTE),
exponent2->ulValueLen);
if (rc != CKR_OK) {
goto error;
}
(void) memcpy(buf + offset, buf2, len);
offset += len;
free(buf2);
rc = ber_encode_INTEGER(FALSE, &buf2, &len,
(CK_BYTE *)coeff + sizeof (CK_ATTRIBUTE), coeff->ulValueLen);
if (rc != CKR_OK) {
goto error;
}
(void) memcpy(buf + offset, buf2, len);
offset += len;
free(buf2);
rc = ber_encode_SEQUENCE(FALSE, &buf2, &len, buf, offset);
if (rc != CKR_OK) {
goto error;
}
rc = ber_encode_PrivateKeyInfo(FALSE,
data, data_len,
ber_AlgIdRSAEncryption, ber_AlgIdRSAEncryptionLen,
buf2, len);
error:
if (buf2) free(buf2);
if (buf) free(buf);
return (rc);
}
CK_RV
ber_decode_RSAPrivateKey(CK_BYTE * data,
CK_ULONG data_len,
CK_ATTRIBUTE ** modulus,
CK_ATTRIBUTE ** publ_exp,
CK_ATTRIBUTE ** priv_exp,
CK_ATTRIBUTE ** prime1,
CK_ATTRIBUTE ** prime2,
CK_ATTRIBUTE ** exponent1,
CK_ATTRIBUTE ** exponent2,
CK_ATTRIBUTE ** coeff)
{
CK_ATTRIBUTE *n_attr = NULL;
CK_ATTRIBUTE *e_attr = NULL;
CK_ATTRIBUTE *d_attr = NULL;
CK_ATTRIBUTE *p_attr = NULL;
CK_ATTRIBUTE *q_attr = NULL;
CK_ATTRIBUTE *e1_attr = NULL;
CK_ATTRIBUTE *e2_attr = NULL;
CK_ATTRIBUTE *coeff_attr = NULL;
CK_BYTE *alg = NULL;
CK_BYTE *rsa_priv_key = NULL;
CK_BYTE *buf = NULL;
CK_BYTE *tmp = NULL;
CK_ULONG offset, buf_len, field_len, len;
CK_RV rc;
rc = ber_decode_PrivateKeyInfo(data, data_len, &alg,
&len, &rsa_priv_key);
if (rc != CKR_OK) {
return (rc);
}
if (memcmp(alg, ber_rsaEncryption, ber_rsaEncryptionLen) != 0) {
return (CKR_FUNCTION_FAILED);
}
rc = ber_decode_SEQUENCE(rsa_priv_key, &buf, &buf_len, &field_len);
if (rc != CKR_OK)
return (rc);
offset = 0;
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
if (offset > buf_len) {
return (CKR_FUNCTION_FAILED);
}
offset = 0;
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
} else {
rc = build_attribute(CKA_MODULUS, tmp, len, &n_attr);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
}
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
} else {
rc = build_attribute(CKA_PUBLIC_EXPONENT, tmp, len, &e_attr);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
}
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
} else {
rc = build_attribute(CKA_PRIVATE_EXPONENT, tmp, len, &d_attr);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
}
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
} else {
rc = build_attribute(CKA_PRIME_1, tmp, len, &p_attr);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
}
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
} else {
rc = build_attribute(CKA_PRIME_2, tmp, len, &q_attr);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
}
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
} else {
rc = build_attribute(CKA_EXPONENT_1, tmp, len, &e1_attr);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
}
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
} else {
rc = build_attribute(CKA_EXPONENT_2, tmp, len, &e2_attr);
if (rc != CKR_OK) {
goto cleanup;
}
offset += field_len;
}
rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len);
if (rc != CKR_OK) {
goto cleanup;
} else {
rc = build_attribute(CKA_COEFFICIENT, tmp, len, &coeff_attr);
if (rc != CKR_OK) {
goto cleanup;
}
offset += len;
}
*modulus = n_attr;
*publ_exp = e_attr;
*priv_exp = d_attr;
*prime1 = p_attr;
*prime2 = q_attr;
*exponent1 = e1_attr;
*exponent2 = e2_attr;
*coeff = coeff_attr;
return (CKR_OK);
cleanup:
if (n_attr) free(n_attr);
if (e_attr) free(e_attr);
if (d_attr) free(d_attr);
if (p_attr) free(p_attr);
if (q_attr) free(q_attr);
if (e1_attr) free(e1_attr);
if (e2_attr) free(e2_attr);
if (coeff_attr) free(coeff_attr);
return (rc);
}