diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ncrypto_nss.c | 756 |
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, ¶ms); +} + /* Asymmetric operations */ CK_RV |