summaryrefslogtreecommitdiffstats
path: root/lib/ncrypto_nss.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ncrypto_nss.c')
-rw-r--r--lib/ncrypto_nss.c756
1 files changed, 652 insertions, 104 deletions
diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c
index 70868a8..4737fc2 100644
--- a/lib/ncrypto_nss.c
+++ b/lib/ncrypto_nss.c
@@ -27,11 +27,13 @@ Red Hat author: Miloslav Trmač <mitr@redhat.com> */
#include <config.h>
#include <pthread.h>
+#include <stdbool.h>
#include <glib.h>
#include <keyhi.h>
#include <nss.h>
#include <pk11pub.h>
+#include <secmodt.h>
#include <ncrypto/ncrypto.h>
@@ -122,8 +124,32 @@ struct ncr_public_key
struct ncr_private_key
{
SECKEYPrivateKey *key;
+ bool sensitive;
};
+struct private_key_info
+{
+ SECItem version;
+ SECAlgorithmID algorithm;
+ SECItem private_key;
+};
+
+static const SEC_ASN1Template private_key_info_asn1_template[] =
+ {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct private_key_info) },
+ { SEC_ASN1_INTEGER, offsetof (struct private_key_info, version), NULL, 0 },
+ {
+ SEC_ASN1_INLINE, offsetof (struct private_key_info, algorithm),
+ SECOID_AlgorithmIDTemplate, 0
+ },
+ {
+ SEC_ASN1_OCTET_STRING, offsetof (struct private_key_info, private_key),
+ NULL, 0
+ },
+ /* Attributes are optional and we never use them. */
+ { 0, 0, NULL, 0 }
+ };
+
static CK_RV
public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type,
const SECItem *der_key)
@@ -145,6 +171,56 @@ public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type,
return CKR_OK;
}
+/* The caller is responsible for freeing der_spki. */
+static CK_RV
+public_key_export (struct ncr_public_key *key, PRArenaPool *arena,
+ void **der_key, size_t *der_key_size, SECItem **der_spki_ptr)
+{
+ struct subject_pub_key_info
+ {
+ SECAlgorithmID algorithm;
+ SECItem pub_key;
+ };
+
+ static const SEC_ASN1Template asn1_template[] =
+ {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct subject_pub_key_info) },
+ {
+ SEC_ASN1_INLINE, offsetof (struct subject_pub_key_info, algorithm),
+ SECOID_AlgorithmIDTemplate, 0,
+ },
+ {
+ SEC_ASN1_BIT_STRING, offsetof (struct subject_pub_key_info, pub_key),
+ NULL, 0,
+ },
+ { 0, 0, NULL, 0 }
+ };
+
+ struct subject_pub_key_info der_output;
+ SECItem *der_spki;
+
+ g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD);
+
+ der_spki = SECKEY_EncodeDERSubjectPublicKeyInfo (key->key);
+ if (der_spki == NULL)
+ return CKR_GENERAL_ERROR;
+
+ if (SEC_QuickDERDecodeItem (arena, &der_output, asn1_template, der_spki)
+ != SECSuccess)
+ {
+ SECITEM_FreeItem (der_spki, PR_TRUE);
+ return CKR_GENERAL_ERROR;
+ }
+
+ *der_key = der_output.pub_key.data;
+ /* der_output.pub_key is encoded as BIT_STRING, so pub_key.len is a number of
+ _bits_. */
+ *der_key_size = (der_output.pub_key.len / 8
+ + (der_output.pub_key.len % 8 != 0));
+ *der_spki_ptr = der_spki;
+ return CKR_OK;
+}
+
CK_RV
ncr_public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type,
const void *der, size_t der_size)
@@ -165,6 +241,56 @@ ncr_public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type,
}
CK_RV
+ncr_public_key_export (struct ncr_public_key *key, void *dest,
+ size_t *dest_size_ptr)
+{
+ PRArenaPool *arena;
+ SECItem *der_spki;
+ void *der_key;
+ size_t der_key_size;
+ CK_RV res;
+
+ res = ensure_ncr_is_open ();
+ if (res != CKR_OK)
+ return res;
+
+ g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD);
+
+ /* Ugly... the PLArenaPool type is from NSPR, but NSS implementation accesses
+ memory only initialized through NSS's PORT_* */
+ arena = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (arena == NULL)
+ return CKR_HOST_MEMORY;
+
+ res = public_key_export (key, arena, &der_key, &der_key_size, &der_spki);
+ if (res != CKR_OK)
+ goto end_arena;
+
+ if (dest == NULL)
+ {
+ *dest_size_ptr = der_key_size;
+ res = CKR_OK;
+ goto end_der_spki;
+ }
+ if (*dest_size_ptr < der_key_size)
+ {
+ *dest_size_ptr = der_key_size;
+ res = CKR_BUFFER_TOO_SMALL;
+ goto end_der_spki;
+ }
+ *dest_size_ptr = der_key_size;
+
+ memcpy (dest, der_key, der_key_size);
+ res = CKR_OK;
+
+ end_der_spki:
+ SECITEM_FreeItem (der_spki, PR_TRUE);
+ end_arena:
+ PORT_FreeArena (arena, PR_FALSE);
+ return res;
+}
+
+CK_RV
ncr_public_key_destroy (struct ncr_public_key *key)
{
CK_RV res;
@@ -183,34 +309,15 @@ ncr_public_key_destroy (struct ncr_public_key *key)
static CK_RV
private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
- const SECItem *der_key, const SECItem *public_value)
+ bool sensitive, const SECItem *der_key,
+ const SECItem *public_value)
{
- struct priv_key_info
- {
- SECItem version;
- SECAlgorithmID algorithm;
- SECItem private_key;
- };
-
- static const SEC_ASN1Template asn1_template[] =
- {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct priv_key_info) },
- { SEC_ASN1_INTEGER, offsetof (struct priv_key_info, version), NULL, 0, },
- { SEC_ASN1_INLINE, offsetof (struct priv_key_info, algorithm),
- SECOID_AlgorithmIDTemplate, 0, },
- {
- SEC_ASN1_OCTET_STRING, offsetof (struct priv_key_info, private_key),
- NULL, 0,
- },
- /* Attributes are optional and we never use them. */
- { 0, 0, NULL, 0 }
- };
static const uint8_t wrap_key[32]; /* = { 0, }; */
static const uint8_t wrap_iv[16]; /* = { 0, }; */
static const uint8_t zero; /* = 0; */
struct ncr_private_key *k;
- struct priv_key_info der_input;
+ struct private_key_info der_input;
PK11SlotInfo *slot;
SECItem der_info, *der_res, key_item, iv_item, wrapped_item;
SECOidTag alg_tag;
@@ -236,6 +343,7 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
der_input.version.type = siUnsignedInteger;
der_input.version.data = (void *)&zero;
der_input.version.len = sizeof (zero);
+ memset (&der_input.algorithm, 0, sizeof (der_input.algorithm));
if (SECOID_SetAlgorithmID (NULL, &der_input.algorithm, alg_tag, NULL)
!= SECSuccess)
{
@@ -246,7 +354,8 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
der_info.data = NULL;
der_info.len = 0;
- der_res = SEC_ASN1EncodeItem (NULL, &der_info, &der_input, asn1_template);
+ der_res = SEC_ASN1EncodeItem (NULL, &der_info, &der_input,
+ private_key_info_asn1_template);
SECOID_DestroyAlgorithmID (&der_input.algorithm, PR_FALSE);
@@ -276,21 +385,21 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
&iv_item);
if (ctx == NULL)
goto err_wrapping_key;
+ memset (&wrapped_item, 0, sizeof (wrapped_item));
if (SECITEM_AllocItem (NULL, &wrapped_item, der_info.len + 16) == NULL)
{
PK11_DestroyContext (ctx, PR_TRUE);
goto err_wrapping_key;
}
- ss = PK11_CipherOp (ctx, wrapped_item.data, &wrapped_len, wrapped_item.len,
- der_info.data, der_info.len);
- if (ss != SECSuccess)
+ if (PK11_CipherOp (ctx, wrapped_item.data, &wrapped_len, wrapped_item.len,
+ der_info.data, der_info.len) != SECSuccess)
{
PK11_DestroyContext (ctx, PR_TRUE);
goto err_wrapped_item;
}
/* C_EncryptFinal is only available through this function. "Nice.". */
ss = PK11_DigestFinal (ctx, wrapped_item.data + wrapped_len,
- &wrapped_item.len, wrapped_len);
+ &wrapped_item.len, wrapped_item.len - wrapped_len);
PK11_DestroyContext (ctx, PR_TRUE);
if (ss != SECSuccess)
goto err_wrapped_item;
@@ -298,8 +407,8 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
k->key = PK11_UnwrapPrivKey (slot, wrapping_key, CKM_AES_CBC_PAD, &iv_item,
&wrapped_item, NULL, (SECItem *)public_value,
- PR_FALSE /* token */, PR_FALSE /* sensitive */,
- type, NULL, 0, NULL);
+ PR_FALSE /* token */, sensitive, type, NULL, 0,
+ NULL);
SECITEM_ZfreeItem (&wrapped_item, PR_FALSE);
PK11_FreeSymKey (wrapping_key);
PK11_FreeSlot (slot);
@@ -308,6 +417,7 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
if (k->key == NULL)
goto err_k;
+ k->sensitive = sensitive;
*key = k;
return CKR_OK;
@@ -324,10 +434,129 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
return CKR_GENERAL_ERROR;
}
+static CK_RV
+private_key_export (struct ncr_private_key *key, PRArenaPool *arena,
+ SECItem *der_key)
+{
+ static const uint8_t wrap_key[32]; /* = { 0, }; */
+ static const uint8_t wrap_iv[16]; /* = { 0, }; */
+
+ PK11SlotInfo *slot;
+ SECItem key_item, iv_item, wrapped_item, der_info;
+ PK11SymKey *wrapping_key;
+ PK11Context *ctx;
+ int der_info_len;
+ struct private_key_info der_output;
+ SECStatus ss;
+ CK_RV res;
+
+ g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID);
+
+ g_return_val_if_fail (!key->sensitive, CKR_ATTRIBUTE_SENSITIVE);
+
+ slot = PK11_GetBestSlot (CKM_AES_CBC_PAD, NULL);
+ if (slot == NULL)
+ return CKR_GENERAL_ERROR;
+
+ key_item.data = (void *)wrap_key;
+ key_item.len = sizeof (wrap_key);
+ wrapping_key = PK11_ImportSymKeyWithFlags (slot, CKM_AES_CBC_PAD,
+ PK11_OriginUnwrap, CKA_FLAGS_ONLY,
+ &key_item,
+ CKF_ENCRYPT | CKF_UNWRAP,
+ PR_FALSE /* isPerm */, NULL);
+ if (wrapping_key == NULL)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto err_slot;
+ }
+ iv_item.data = (void *)wrap_iv;
+ iv_item.len = sizeof (wrap_iv);
+
+ memset (&wrapped_item, 0, sizeof (wrapped_item));
+ if (PK11_WrapPrivKey(slot, wrapping_key, key->key, CKM_AES_CBC_PAD, &iv_item,
+ &wrapped_item, NULL) != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto err_wrapping_key;
+ }
+ if (SECITEM_AllocItem (NULL, &wrapped_item, wrapped_item.len) == NULL)
+ {
+ res = CKR_HOST_MEMORY;
+ goto err_wrapping_key;
+ }
+ if (PK11_WrapPrivKey(slot, wrapping_key, key->key, CKM_AES_CBC_PAD, &iv_item,
+ &wrapped_item, NULL) != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto err_wrapped_item;
+ }
+
+ ctx = PK11_CreateContextBySymKey (CKM_AES_CBC_PAD, CKA_DECRYPT, wrapping_key,
+ &iv_item);
+ if (ctx == NULL)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto err_wrapped_item;
+ }
+ memset (&der_info, 0, sizeof (der_info));
+ if (SECITEM_AllocItem (arena, &der_info, wrapped_item.len) == NULL)
+ {
+ PK11_DestroyContext (ctx, PR_TRUE);
+ res = CKR_HOST_MEMORY;
+ goto err_wrapped_item;
+ }
+ if (PK11_CipherOp (ctx, der_info.data, &der_info_len, der_info.len,
+ wrapped_item.data, wrapped_item.len) != SECSuccess)
+ {
+ PK11_DestroyContext (ctx, PR_TRUE);
+ res = CKR_GENERAL_ERROR;
+ goto err_wrapped_item;
+ }
+ /* C_DecryptFinal is only available through this function. "Nice.". */
+ ss = PK11_DigestFinal (ctx, der_info.data + der_info_len,
+ &der_info.len, der_info.len - der_info_len);
+ PK11_DestroyContext (ctx, PR_TRUE);
+ if (ss != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto err_wrapped_item;
+ }
+ der_info.len += der_info_len;
+
+ /* "type" is accessed by the decoder for ASN1_INTEGER */
+ der_output.version.type = siUnsignedInteger;
+ if (SEC_QuickDERDecodeItem (arena, &der_output,
+ private_key_info_asn1_template, &der_info)
+ != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto err_wrapped_item;
+ }
+
+ /* Should we validate the version and algorithm ID here? */
+
+ *der_key = der_output.private_key;
+
+ SECITEM_ZfreeItem (&wrapped_item, PR_FALSE);
+ PK11_FreeSymKey (wrapping_key);
+ PK11_FreeSlot (slot);
+
+ return CKR_OK;
+
+ err_wrapped_item:
+ SECITEM_ZfreeItem (&wrapped_item, PR_FALSE);
+ err_wrapping_key:
+ PK11_FreeSymKey (wrapping_key);
+ err_slot:
+ PK11_FreeSlot (slot);
+ return res;
+}
+
/* FIXME: public_value should not be necessary, it is somewhere inside "der". */
CK_RV
ncr_private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
- const void *der, size_t der_size,
+ _Bool sensitive, const void *der, size_t der_size,
const void *public_value, size_t public_value_size)
{
SECItem der_key;
@@ -345,7 +574,79 @@ ncr_private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
der_key.len = der_size;
public.data = (void *)public_value;
public.len = public_value_size;
- return private_key_create (key, type, &der_key, &public);
+ return private_key_create (key, type, sensitive, &der_key, &public);
+}
+
+CK_RV
+ncr_private_key_set_sensitive (struct ncr_private_key *key)
+{
+ static const CK_BBOOL true_value = CK_TRUE;
+
+ CK_RV res;
+ SECStatus ss;
+ SECItem item;
+
+ res = ensure_ncr_is_open ();
+ if (res != CKR_OK)
+ return res;
+
+ g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID);
+
+ item.data = (void *)&true_value;
+ item.len = sizeof (true_value);
+ ss = PK11_WriteRawAttribute (PK11_TypePrivKey, key->key, CKA_SENSITIVE,
+ &item);
+ if (ss != SECSuccess)
+ return CKR_GENERAL_ERROR;
+
+ key->sensitive = true;
+ return CKR_OK;
+}
+
+CK_RV
+ncr_private_key_export (struct ncr_private_key *key, void *dest,
+ size_t *dest_size_ptr)
+{
+ PRArenaPool *arena;
+ SECItem der_key;
+ CK_RV res;
+
+ res = ensure_ncr_is_open ();
+ if (res != CKR_OK)
+ return res;
+
+ g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD);
+
+ /* Ugly... the PLArenaPool type is from NSPR, but NSS implementation accesses
+ memory only initialized through NSS's PORT_* */
+ arena = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (arena == NULL)
+ return CKR_HOST_MEMORY;
+
+ res = private_key_export (key, arena, &der_key);
+ if (res != CKR_OK)
+ goto end;
+
+ if (dest == NULL)
+ {
+ *dest_size_ptr = der_key.len;
+ res = CKR_OK;
+ goto end;
+ }
+ if (*dest_size_ptr < der_key.len)
+ {
+ *dest_size_ptr = der_key.len;
+ res = CKR_BUFFER_TOO_SMALL;
+ goto end;
+ }
+ *dest_size_ptr = der_key.len;
+
+ memcpy (dest, der_key.data, der_key.len);
+ res = CKR_OK;
+
+ end:
+ PORT_FreeArena (arena, PR_TRUE);
+ return res;
}
CK_RV
@@ -364,26 +665,162 @@ ncr_private_key_destroy (struct ncr_private_key *key)
return CKR_OK;
}
-CK_RV
-ncr_public_key_create_rsa (struct ncr_public_key **key, const void *modulus,
- size_t modulus_size, const void *public_exponent,
- size_t public_exponent_size)
+static CK_RV
+key_pair_generate (struct ncr_public_key **public_key,
+ struct ncr_private_key **private_key, CK_MECHANISM_TYPE mech,
+ bool sensitive, void *params)
+{
+ struct ncr_public_key *pub;
+ struct ncr_private_key *priv;
+ PK11SlotInfo *slot;
+
+ g_return_val_if_fail (public_key != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (private_key != NULL, CKR_ARGUMENTS_BAD);
+
+ pub = malloc (sizeof (*pub));
+ if (pub == NULL)
+ return CKR_HOST_MEMORY;
+ priv = malloc (sizeof (*priv));
+ if (priv == NULL)
+ {
+ free (pub);
+ return CKR_HOST_MEMORY;
+ }
+
+ slot = PK11_GetBestSlot (mech, NULL);
+ if (slot == NULL)
+ goto err_priv;
+
+ priv->key = PK11_GenerateKeyPair(slot, mech, params, &pub->key,
+ PR_FALSE /* isPerm */, sensitive, NULL);
+ PK11_FreeSlot (slot);
+ if (priv->key == NULL)
+ goto err_priv;
+
+
+ priv->sensitive = sensitive;
+ *public_key = pub;
+ *private_key = priv;
+ return CKR_OK;
+
+ err_priv:
+ free (priv);
+ free (pub);
+ return CKR_GENERAL_ERROR;
+}
+
+ /* Multi-precision integers */
+
+/* Validate SRC and use it to set up DEST for ASN.1 encoding */
+static CK_RV
+mpi_create_SECItems_for_encoding (SECItem *dest, const struct ncr_mpi *src,
+ size_t num)
+{
+ size_t i;
+
+ g_return_val_if_fail (src != NULL, CKR_ARGUMENTS_BAD);
+ for (i = 0; i < num; i++)
+ g_return_val_if_fail (src[i].data != NULL, CKR_ARGUMENTS_BAD);
+
+ for (i = 0; i < num; i++)
+ {
+ dest[i].type = siUnsignedInteger;
+ dest[i].data = src[i].data;
+ dest[i].len = src[i].size;
+ }
+ return CKR_OK;
+}
+
+/* Handle of decoded SRC to DEST */
+static CK_RV
+mpi_output_decoded_SECItems (struct ncr_mpi *dest, const SECItem *src,
+ size_t num)
+{
+ size_t i;
+ CK_RV res;
+
+ for (i = 0; i < num; i++)
+ {
+ if (dest[i].data == NULL)
+ goto sizes_only;
+ }
+
+ res = CKR_OK;
+ for (i = 0; i < num; i++)
+ {
+ if (dest[i].size < src[i].len)
+ res = CKR_BUFFER_TOO_SMALL;
+ dest[i].size = src[i].len;
+ }
+ if (res != CKR_OK)
+ return res;
+
+ for (i = 0; i < num; i++)
+ memcpy (dest[i].data, src[i].data, src[i].len);
+
+ return CKR_OK;
+
+ sizes_only:
+ for (i = 0; i < num; i++)
+ dest[i].size = src[i].len;
+ return CKR_OK;
+}
+
+ /* RSA keys */
+
+struct rsa_public_key
{
- struct rsa_pub_key
+ SECItem items[NCR_RSA_PUBLIC_NUM_MPIS];
+};
+
+static const SEC_ASN1Template rsa_public_key_asn1_template[] =
{
- SECItem modulus, public_exponent;
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct rsa_public_key) },
+#define INT(X) \
+ { \
+ SEC_ASN1_INTEGER, \
+ offsetof (struct rsa_public_key, items) + (X) * sizeof (SECItem), NULL, \
+ 0 \
+ }
+
+ INT (NCR_RSA_PUBLIC_MPI_MODULUS), INT (NCR_RSA_PUBLIC_MPI_PUBLIC_EXPONENT),
+#undef INT
+ { 0, 0, NULL, 0 }
};
- static const SEC_ASN1Template asn1_template[] =
- {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct rsa_pub_key) },
-#define INT(X) { SEC_ASN1_INTEGER, offsetof (struct rsa_pub_key, X), NULL, 0, }
- INT (modulus), INT (public_exponent),
+struct rsa_private_key
+{
+ SECItem version;
+ SECItem items[NCR_RSA_PRIVATE_NUM_MPIS];
+};
+
+static const SEC_ASN1Template rsa_private_key_asn1_template[] =
+ {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct rsa_private_key) },
+ { SEC_ASN1_INTEGER, offsetof (struct rsa_private_key, version), NULL, 0 },
+#define INT(X) \
+ { \
+ SEC_ASN1_INTEGER, \
+ offsetof (struct rsa_private_key, items) + (X) * sizeof (SECItem), NULL, \
+ 0 \
+ }
+
+ INT (NCR_RSA_PRIVATE_MPI_MODULUS),
+ INT (NCR_RSA_PRIVATE_MPI_PUBLIC_EXPONENT),
+ INT (NCR_RSA_PRIVATE_MPI_PRIVATE_EXPONENT),
+ INT (NCR_RSA_PRIVATE_MPI_PRIME_1), INT (NCR_RSA_PRIVATE_MPI_PRIME_2),
+ INT (NCR_RSA_PRIVATE_MPI_EXPONENT_1), INT (NCR_RSA_PRIVATE_MPI_EXPONENT_2),
+ INT (NCR_RSA_PRIVATE_MPI_COEFFICIENT),
#undef INT
- { 0, 0, NULL, 0 }
- };
+ { 0, 0, NULL, 0 }
+ };
- struct rsa_pub_key der_input;
+CK_RV
+ncr_public_key_create_rsa (struct ncr_public_key **key,
+ const struct ncr_mpi
+ mpis[static NCR_RSA_PUBLIC_NUM_MPIS])
+{
+ struct rsa_public_key der_input;
SECItem der_key;
CK_RV res;
@@ -391,21 +828,15 @@ ncr_public_key_create_rsa (struct ncr_public_key **key, const void *modulus,
if (res != CKR_OK)
return res;
- g_return_val_if_fail (modulus != NULL, CKR_ARGUMENTS_BAD);
- g_return_val_if_fail (public_exponent != NULL, CKR_ARGUMENTS_BAD);
-
-#define INT(X) \
- der_input.X.type = siUnsignedInteger; \
- der_input.X.data = (void *)X; \
- der_input.X.len = X##_size;
-
- INT (modulus);
- INT (public_exponent);
-#undef INT
+ res = mpi_create_SECItems_for_encoding (der_input.items, mpis,
+ NCR_RSA_PUBLIC_NUM_MPIS);
+ if (res != CKR_OK)
+ return res;
der_key.data = NULL;
der_key.len = 0;
- if (SEC_ASN1EncodeItem(NULL, &der_key, &der_input, asn1_template) == NULL)
+ if (SEC_ASN1EncodeItem(NULL, &der_key, &der_input,
+ rsa_public_key_asn1_template) == NULL)
return CKR_HOST_MEMORY;
res = public_key_create (key, CKK_RSA, &der_key);
@@ -415,38 +846,68 @@ ncr_public_key_create_rsa (struct ncr_public_key **key, const void *modulus,
}
CK_RV
-ncr_private_key_create_rsa (struct ncr_private_key **key, const void *modulus,
- size_t modulus_size, const void *public_exponent,
- size_t public_exponent_size,
- const void *private_exponent,
- size_t private_exponent_size, const void *prime_1,
- size_t prime_1_size, const void *prime_2,
- size_t prime_2_size, const void *exponent_1,
- size_t exponent_1_size, const void *exponent_2,
- size_t exponent_2_size, const void *coefficient,
- size_t coefficient_size)
-{
- struct rsa_pub_key
- {
- SECItem version;
- SECItem modulus, public_exponent, private_exponent, prime_1, prime_2;
- SECItem exponent_1, exponent_2, coefficient;
- };
+ncr_public_key_export_rsa (struct ncr_public_key *key,
+ struct ncr_mpi mpis[static NCR_RSA_PUBLIC_NUM_MPIS])
+{
+ struct rsa_public_key der_output;
+ PRArenaPool *arena;
+ SECItem *der_spki, der_key_item;
+ void *der_key;
+ size_t der_key_size;
+ CK_RV res;
+ size_t i;
- static const SEC_ASN1Template asn1_template[] =
+ res = ensure_ncr_is_open ();
+ if (res != CKR_OK)
+ return res;
+
+ g_return_val_if_fail (mpis != NULL, CKR_ARGUMENTS_BAD);
+
+ /* Ugly... the PLArenaPool type is from NSPR, but NSS implementation accesses
+ memory only initialized through NSS's PORT_* */
+ arena = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (arena == NULL)
+ return CKR_HOST_MEMORY;
+
+ res = public_key_export (key, arena, &der_key, &der_key_size, &der_spki);
+ if (res != CKR_OK)
+ goto end_arena;
+
+ der_key_item.data = der_key;
+ der_key_item.len = der_key_size;
+ if (der_key_item.len != der_key_size)
{
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct rsa_pub_key) },
-#define INT(X) { SEC_ASN1_INTEGER, offsetof (struct rsa_pub_key, X), NULL, 0, }
- INT (version),
- INT (modulus), INT (public_exponent), INT (private_exponent),
- INT (prime_1), INT (prime_2), INT (exponent_1), INT (exponent_2),
- INT (coefficient),
-#undef INT
- { 0, 0, NULL, 0 }
- };
+ res = CKR_GENERAL_ERROR;
+ goto end_der_spki;
+ }
+ /* Setting type to siUnsignedInteger requests removal of leading zeroes. */
+ for (i = 0; i < NCR_RSA_PUBLIC_NUM_MPIS; i++)
+ der_output.items[i].type = siUnsignedInteger;
+ if (SEC_QuickDERDecodeItem (arena, &der_output, rsa_public_key_asn1_template,
+ &der_key_item) != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end_der_spki;
+ }
+
+ res = mpi_output_decoded_SECItems(mpis, der_output.items,
+ NCR_RSA_PUBLIC_NUM_MPIS);
+
+ end_der_spki:
+ SECITEM_FreeItem (der_spki, PR_TRUE);
+ end_arena:
+ PORT_FreeArena (arena, PR_FALSE);
+ return res;
+}
+
+CK_RV
+ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive,
+ const struct ncr_mpi
+ mpis[static NCR_RSA_PRIVATE_NUM_MPIS])
+{
static const uint8_t zero; /* = 0; */
- struct rsa_pub_key der_input;
+ struct rsa_private_key der_input;
SECItem der_key;
CK_RV res;
@@ -454,38 +915,125 @@ ncr_private_key_create_rsa (struct ncr_private_key **key, const void *modulus,
if (res != CKR_OK)
return res;
- g_return_val_if_fail (modulus != NULL, CKR_ARGUMENTS_BAD);
- g_return_val_if_fail (public_exponent != NULL, CKR_ARGUMENTS_BAD);
+ res = mpi_create_SECItems_for_encoding (der_input.items, mpis,
+ NCR_RSA_PRIVATE_NUM_MPIS);
+ if (res != CKR_OK)
+ return res;
der_input.version.type = siUnsignedInteger;
der_input.version.data = (void *)&zero;
der_input.version.len = sizeof (zero);
-#define INT(X) \
- der_input.X.type = siUnsignedInteger; \
- der_input.X.data = (void *)X; \
- der_input.X.len = X##_size;
-
- INT (modulus);
- INT (public_exponent);
- INT (private_exponent);
- INT (prime_1);
- INT (prime_2);
- INT (exponent_1);
- INT (exponent_2);
- INT (coefficient);
-#undef INT
-
der_key.data = NULL;
der_key.len = 0;
- if (SEC_ASN1EncodeItem (NULL, &der_key, &der_input, asn1_template) == NULL)
+ if (SEC_ASN1EncodeItem (NULL, &der_key, &der_input,
+ rsa_private_key_asn1_template) == NULL)
return CKR_HOST_MEMORY;
- res = private_key_create (key, CKK_RSA, &der_key, &der_input.modulus);
+ res = private_key_create (key, CKK_RSA, sensitive, &der_key,
+ &der_input.items[NCR_RSA_PRIVATE_MPI_MODULUS]);
PORT_Free (der_key.data);
return res;
}
+CK_RV
+ncr_private_key_export_rsa (struct ncr_private_key *key,
+ struct ncr_mpi
+ mpis[static NCR_RSA_PRIVATE_NUM_MPIS])
+{
+ struct rsa_private_key der_output;
+ PRArenaPool *arena;
+ SECItem der_key;
+ CK_RV res;
+ size_t i;
+
+ res = ensure_ncr_is_open ();
+ if (res != CKR_OK)
+ return res;
+
+ g_return_val_if_fail (mpis != NULL, CKR_ARGUMENTS_BAD);
+
+ /* Ugly... the PLArenaPool type is from NSPR, but NSS implementation accesses
+ memory only initialized through NSS's PORT_* */
+ arena = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (arena == NULL)
+ return CKR_HOST_MEMORY;
+
+ res = private_key_export (key, arena, &der_key);
+ if (res != CKR_OK)
+ goto end;
+
+ /* Setting type to siUnsignedInteger requests removal of leading zeroes. */
+ der_output.version.type = siUnsignedInteger;
+ for (i = 0; i < NCR_RSA_PRIVATE_NUM_MPIS; i++)
+ der_output.items[i].type = siUnsignedInteger;
+ if (SEC_QuickDERDecodeItem (arena, &der_output, rsa_private_key_asn1_template,
+ &der_key) != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end;
+ }
+
+ res = mpi_output_decoded_SECItems(mpis, der_output.items,
+ NCR_RSA_PRIVATE_NUM_MPIS);
+
+ end:
+ PORT_FreeArena (arena, PR_TRUE);
+ return res;
+}
+
+CK_RV
+ncr_key_pair_generate_rsa (struct ncr_public_key **public_key,
+ struct ncr_private_key **private_key,
+ CK_MECHANISM_TYPE mech, _Bool sensitive,
+ CK_ULONG modulus_bits,
+ const struct ncr_mpi *public_exponent)
+{
+ PK11RSAGenParams params;
+ CK_RV res;
+
+ res = ensure_ncr_is_open ();
+ if (res != CKR_OK)
+ return res;
+
+ switch (mech)
+ {
+ case CKM_RSA_PKCS_KEY_PAIR_GEN:
+ case CKM_RSA_X9_31_KEY_PAIR_GEN:
+ break;
+
+ default:
+ g_return_val_if_reached (CKR_MECHANISM_INVALID);
+ }
+
+ g_return_val_if_fail (modulus_bits <= INT_MAX, CKR_ARGUMENTS_BAD);
+
+ params.keySizeInBits = modulus_bits;
+ if (public_exponent == NULL)
+ params.pe = 65537;
+ else
+ {
+ unsigned long val;
+ const uint8_t *p, *end;
+
+ end = (const uint8_t *)public_exponent->data + public_exponent->size;
+ for (p = public_exponent->data; p < end && *p == 0; p++)
+ ;
+ g_return_val_if_fail ((size_t)(end - p) <= sizeof (val),
+ CKR_ARGUMENTS_BAD);
+
+ val = 0;
+ while (p < end)
+ {
+ val = (val << 8) | *p;
+ p++;
+ }
+ params.pe = val;
+ }
+
+ return key_pair_generate (public_key, private_key, mech, sensitive, &params);
+}
+
/* Asymmetric operations */
CK_RV