From 6e61d5e3245e3ba15e9fa97a588cf8e7e4e84da9 Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Thu, 25 Nov 2010 17:56:25 +0100 Subject: Fix failures with enabled NSS assertions --- lib/ncrypto_nss.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index 70868a8..2879f49 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -236,6 +236,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) { @@ -276,6 +277,7 @@ 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); -- cgit From 3712df97eb0a1149823c6f0c6aace2ecfdb53f1b Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Thu, 25 Nov 2010 17:57:27 +0100 Subject: Beautify --- lib/ncrypto_nss.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index 2879f49..2c806c4 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -196,8 +196,10 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type, { { 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_INLINE, offsetof (struct priv_key_info, algorithm), + SECOID_AlgorithmIDTemplate, 0, + }, { SEC_ASN1_OCTET_STRING, offsetof (struct priv_key_info, private_key), NULL, 0, @@ -283,9 +285,8 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type, 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; -- cgit From 012b4861d820dfd954dcd3563b6366812a30205f Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Thu, 25 Nov 2010 18:07:25 +0100 Subject: Add ncr_public_key_export --- include/ncrypto/ncrypto.h | 2 ++ lib/ncrypto_nss.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/include/ncrypto/ncrypto.h b/include/ncrypto/ncrypto.h index a09d451..c4de81e 100644 --- a/include/ncrypto/ncrypto.h +++ b/include/ncrypto/ncrypto.h @@ -73,6 +73,8 @@ struct ncr_private_key; CK_RV ncr_public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type, const void *der, size_t der_size); +CK_RV ncr_public_key_export (struct ncr_public_key *key, void *dest, + size_t *dest_size_ptr); CK_RV ncr_public_key_destroy (struct ncr_public_key *key); CK_RV ncr_private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type, const void *der, size_t der_size, diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index 2c806c4..71f63bc 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -145,6 +145,92 @@ public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type, return CKR_OK; } +CK_RV +ncr_public_key_export (struct ncr_public_key *key, void *dest, + size_t *dest_size_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; + PRArenaPool *arena; + SECItem *der_key; + size_t dest_size; + CK_RV res; + + res = ensure_ncr_is_open (); + if (res != CKR_OK) + return res; + + g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD); + g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD); + + der_key = SECKEY_EncodeDERSubjectPublicKeyInfo (key->key); + if (der_key == NULL) + return CKR_GENERAL_ERROR; + + /* 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) + { + res = CKR_HOST_MEMORY; + goto end_der_key; + } + + if (SEC_QuickDERDecodeItem (arena, &der_output, asn1_template, der_key) + != SECSuccess) + { + res = CKR_GENERAL_ERROR; + goto end_arena; + } + + /* der_output.pub_key is encoded as BIT_STRING, so pub_key.len is a number of + _bits_. */ + dest_size = der_output.pub_key.len / 8; + if (der_output.pub_key.len % 8 != 0) + dest_size ++; + if (dest == NULL) + { + *dest_size_ptr = dest_size; + res = CKR_OK; + goto end_arena; + } + if (*dest_size_ptr < dest_size) + { + *dest_size_ptr = dest_size; + res = CKR_BUFFER_TOO_SMALL; + goto end_arena; + } + *dest_size_ptr = dest_size; + + memcpy (dest, der_output.pub_key.data, dest_size); + res = CKR_OK; + + end_arena: + PORT_FreeArena (arena, PR_FALSE); + end_der_key: + SECITEM_FreeItem (der_key, PR_TRUE); + return res; +} + CK_RV ncr_public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type, const void *der, size_t der_size) -- cgit From 4c7d02965c0ad914068eb9edd65b5d918ffbf7be Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Thu, 25 Nov 2010 18:43:58 +0100 Subject: Add ncr_public_key_export_rsa(). --- include/ncrypto/ncrypto.h | 6 ++ lib/ncrypto_nss.c | 192 +++++++++++++++++++++++++++++++++++----------- tests/rsa.c | 14 +++- 3 files changed, 166 insertions(+), 46 deletions(-) diff --git a/include/ncrypto/ncrypto.h b/include/ncrypto/ncrypto.h index c4de81e..9f5a3f4 100644 --- a/include/ncrypto/ncrypto.h +++ b/include/ncrypto/ncrypto.h @@ -82,10 +82,16 @@ CK_RV ncr_private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type, size_t public_value_size); CK_RV ncr_private_key_destroy (struct ncr_private_key *key); + /* RSA keys */ + 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); +CK_RV ncr_public_key_export_rsa (struct ncr_public_key *key, + void *modulus, size_t *modulus_size_ptr, + void *public_exponent, + size_t *public_exponent_size_ptr); CK_RV ncr_private_key_create_rsa (struct ncr_private_key **key, const void *modulus, size_t modulus_size, const void *public_exponent, diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index 71f63bc..13eeb6e 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -145,9 +145,11 @@ public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type, return CKR_OK; } -CK_RV -ncr_public_key_export (struct ncr_public_key *key, void *dest, - size_t *dest_size_ptr) +/* The caller is responsible for freeing the arena and der_spki. */ +static CK_RV +public_key_export (struct ncr_public_key *key, void **der_key, + size_t *der_key_size, PRArenaPool **arena_ptr, + SECItem **der_spki_ptr) { struct subject_pub_key_info { @@ -171,19 +173,13 @@ ncr_public_key_export (struct ncr_public_key *key, void *dest, struct subject_pub_key_info der_output; PRArenaPool *arena; - SECItem *der_key; - size_t dest_size; + SECItem *der_spki; CK_RV res; - res = ensure_ncr_is_open (); - if (res != CKR_OK) - return res; - g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD); - g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD); - der_key = SECKEY_EncodeDERSubjectPublicKeyInfo (key->key); - if (der_key == NULL) + der_spki = SECKEY_EncodeDERSubjectPublicKeyInfo (key->key); + if (der_spki == NULL) return CKR_GENERAL_ERROR; /* Ugly... the PLArenaPool type is from NSPR, but NSS implementation accesses @@ -192,42 +188,72 @@ ncr_public_key_export (struct ncr_public_key *key, void *dest, if (arena == NULL) { res = CKR_HOST_MEMORY; - goto end_der_key; + goto err_der_spki; } - if (SEC_QuickDERDecodeItem (arena, &der_output, asn1_template, der_key) + if (SEC_QuickDERDecodeItem (arena, &der_output, asn1_template, der_spki) != SECSuccess) { res = CKR_GENERAL_ERROR; - goto end_arena; + goto err_arena; } + *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_. */ - dest_size = der_output.pub_key.len / 8; - if (der_output.pub_key.len % 8 != 0) - dest_size ++; + *der_key_size = (der_output.pub_key.len / 8 + + (der_output.pub_key.len % 8 != 0)); + *arena_ptr = arena; + *der_spki_ptr = der_spki; + return CKR_OK; + + err_arena: + PORT_FreeArena (arena, PR_FALSE); + err_der_spki: + SECITEM_FreeItem (der_spki, PR_TRUE); + return res; +} + +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); + + res = public_key_export (key, &der_key, &der_key_size, &arena, &der_spki); + if (res != CKR_OK) + return res; + if (dest == NULL) { - *dest_size_ptr = dest_size; + *dest_size_ptr = der_key_size; res = CKR_OK; - goto end_arena; + goto end; } - if (*dest_size_ptr < dest_size) + if (*dest_size_ptr < der_key_size) { - *dest_size_ptr = dest_size; + *dest_size_ptr = der_key_size; res = CKR_BUFFER_TOO_SMALL; - goto end_arena; + goto end; } - *dest_size_ptr = dest_size; + *dest_size_ptr = der_key_size; - memcpy (dest, der_output.pub_key.data, dest_size); + memcpy (dest, der_key, der_key_size); res = CKR_OK; - end_arena: + end: PORT_FreeArena (arena, PR_FALSE); - end_der_key: - SECITEM_FreeItem (der_key, PR_TRUE); + SECITEM_FreeItem (der_spki, PR_TRUE); return res; } @@ -453,26 +479,30 @@ ncr_private_key_destroy (struct ncr_private_key *key) return CKR_OK; } + /* RSA keys */ + +struct rsa_public_key +{ + SECItem modulus, public_exponent; +}; + +static const SEC_ASN1Template rsa_public_key_asn1_template[] = + { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct rsa_public_key) }, +#define INT(X) { \ + SEC_ASN1_INTEGER, offsetof (struct rsa_public_key, X), NULL, 0, \ + } + INT (modulus), INT (public_exponent), +#undef INT + { 0, 0, NULL, 0 } + }; + 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) { - struct rsa_pub_key - { - SECItem modulus, public_exponent; - }; - - 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), -#undef INT - { 0, 0, NULL, 0 } - }; - - struct rsa_pub_key der_input; + struct rsa_public_key der_input; SECItem der_key; CK_RV res; @@ -494,7 +524,8 @@ ncr_public_key_create_rsa (struct ncr_public_key **key, const void *modulus, 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); @@ -503,6 +534,79 @@ ncr_public_key_create_rsa (struct ncr_public_key **key, const void *modulus, return res; } +CK_RV +ncr_public_key_export_rsa (struct ncr_public_key *key, void *modulus, + size_t *modulus_size_ptr, void *public_exponent, + size_t *public_exponent_size_ptr) +{ + 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; + + res = ensure_ncr_is_open (); + if (res != CKR_OK) + return res; + + g_return_val_if_fail (modulus_size_ptr != NULL, CKR_ARGUMENTS_BAD); + g_return_val_if_fail (public_exponent_size_ptr != NULL, CKR_ARGUMENTS_BAD); + + res = public_key_export (key, &der_key, &der_key_size, &arena, &der_spki); + if (res != CKR_OK) + return res; + + der_key_item.data = der_key; + der_key_item.len = der_key_size; + if (der_key_item.len != der_key_size) + { + res = CKR_GENERAL_ERROR; + goto end; + } + /* Setting type to siUnsignedInteger requests removal of leading zeroes. */ + der_output.modulus.type = siUnsignedInteger; + der_output.public_exponent.type = siUnsignedInteger; + if (SEC_QuickDERDecodeItem (arena, &der_output, rsa_public_key_asn1_template, + &der_key_item) != SECSuccess) + { + res = CKR_GENERAL_ERROR; + goto end; + } + + if (modulus == NULL || public_exponent == NULL) + { + *modulus_size_ptr = der_output.modulus.len; + *public_exponent_size_ptr = der_output.public_exponent.len; + res = CKR_OK; + goto end; + } + res = CKR_OK; + if (*modulus_size_ptr < der_output.modulus.len) + { + *modulus_size_ptr = der_output.modulus.len; + res = CKR_BUFFER_TOO_SMALL; + } + if (*public_exponent_size_ptr < der_output.public_exponent.len) + { + *public_exponent_size_ptr = der_output.public_exponent.len; + res = CKR_BUFFER_TOO_SMALL; + } + if (res != CKR_OK) + goto end; + *modulus_size_ptr = der_output.modulus.len; + *public_exponent_size_ptr = der_output.public_exponent.len; + + memcpy (modulus, der_output.modulus.data, der_output.modulus.len); + memcpy (public_exponent, der_output.public_exponent.data, + der_output.public_exponent.len); + + end: + PORT_FreeArena (arena, PR_FALSE); + SECITEM_FreeItem (der_spki, PR_TRUE); + return res; +} + CK_RV ncr_private_key_create_rsa (struct ncr_private_key **key, const void *modulus, size_t modulus_size, const void *public_exponent, diff --git a/tests/rsa.c b/tests/rsa.c index d14e05c..4e16769 100644 --- a/tests/rsa.c +++ b/tests/rsa.c @@ -49,8 +49,8 @@ main (void) { struct ncr_public_key *public; struct ncr_private_key *private; - uint8_t dest[4096]; - size_t src_size, dest_size; + uint8_t dest[4096], dest2[4096]; + size_t src_size, dest_size, dest2_size; CK_RV res; /* Test key loading. Should we test the generic version as well? */ @@ -95,6 +95,16 @@ main (void) sizeof (input)); assert (res != CKR_OK); + dest_size = sizeof (dest); + dest2_size = sizeof (dest2); + res = ncr_public_key_export_rsa (public, dest, &dest_size, dest2, + &dest2_size); + assert (res == CKR_OK); + assert (dest_size == sizeof (modulus)); + assert (dest2_size == sizeof (public_exponent)); + assert (memcmp (dest, modulus, dest_size) == 0); + assert (memcmp (dest2, public_exponent, dest2_size) == 0); + res = ncr_private_key_destroy (private); assert (res == CKR_OK); -- cgit From b131c15c65257c06847c5e667e7699035746362f Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Thu, 25 Nov 2010 21:46:23 +0100 Subject: Beautify --- lib/ncrypto_nss.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index 13eeb6e..b5bb753 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -214,6 +214,25 @@ public_key_export (struct ncr_public_key *key, void **der_key, return res; } +CK_RV +ncr_public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type, + const void *der, size_t der_size) +{ + CK_RV res; + SECItem der_key; + + res = ensure_ncr_is_open (); + if (res != CKR_OK) + return res; + + g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD); + g_return_val_if_fail (der != NULL, CKR_ARGUMENTS_BAD); + + der_key.data = (void *)der; + der_key.len = der_size; + return public_key_create (key, type, &der_key); +} + CK_RV ncr_public_key_export (struct ncr_public_key *key, void *dest, size_t *dest_size_ptr) @@ -257,25 +276,6 @@ ncr_public_key_export (struct ncr_public_key *key, void *dest, return res; } -CK_RV -ncr_public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type, - const void *der, size_t der_size) -{ - CK_RV res; - SECItem der_key; - - res = ensure_ncr_is_open (); - if (res != CKR_OK) - return res; - - g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD); - g_return_val_if_fail (der != NULL, CKR_ARGUMENTS_BAD); - - der_key.data = (void *)der; - der_key.len = der_size; - return public_key_create (key, type, &der_key); -} - CK_RV ncr_public_key_destroy (struct ncr_public_key *key) { -- cgit From e4dee3eb1f10e14dd63c7ed6e20d718c5f2d56a3 Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Thu, 25 Nov 2010 23:07:40 +0100 Subject: Fix buffer size computation when importing keys --- lib/ncrypto_nss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index b5bb753..d6ded4f 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -405,7 +405,7 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type, } /* 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; -- cgit From 6e919f9347656ba0ae390038679ac942ad6a9964 Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Thu, 25 Nov 2010 23:11:03 +0100 Subject: Add private key extraction support --- include/ncrypto/ncrypto.h | 8 +- lib/ncrypto_nss.c | 223 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 199 insertions(+), 32 deletions(-) diff --git a/include/ncrypto/ncrypto.h b/include/ncrypto/ncrypto.h index 9f5a3f4..47ca5df 100644 --- a/include/ncrypto/ncrypto.h +++ b/include/ncrypto/ncrypto.h @@ -76,10 +76,14 @@ CK_RV 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); CK_RV ncr_public_key_destroy (struct ncr_public_key *key); +/* "Sensitive" corresponds to CKA_SENSITIVE. */ 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); +CK_RV ncr_private_key_set_sensitive (struct ncr_private_key *key); +CK_RV ncr_private_key_export (struct ncr_private_key *key, void *dest, + size_t *dest_size_ptr); CK_RV ncr_private_key_destroy (struct ncr_private_key *key); /* RSA keys */ @@ -92,7 +96,7 @@ CK_RV ncr_public_key_export_rsa (struct ncr_public_key *key, void *modulus, size_t *modulus_size_ptr, void *public_exponent, size_t *public_exponent_size_ptr); -CK_RV ncr_private_key_create_rsa (struct ncr_private_key **key, +CK_RV ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive, const void *modulus, size_t modulus_size, const void *public_exponent, size_t public_exponent_size, diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index d6ded4f..48d2e47 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -27,6 +27,7 @@ Red Hat author: Miloslav Trmač */ #include #include +#include #include #include @@ -122,8 +123,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) @@ -295,36 +320,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; @@ -361,7 +365,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); @@ -423,6 +428,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; @@ -442,7 +448,7 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type, /* 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; @@ -460,7 +466,162 @@ 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) +{ + CK_RV res; + + res = ensure_ncr_is_open (); + if (res != CKR_OK) + return res; + + g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID); + key->sensitive = true; + return CKR_OK; +} + +CK_RV +ncr_private_key_export (struct ncr_private_key *key, void *dest, + size_t *dest_size_ptr) +{ + 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; + PRArenaPool *arena; + 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 (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD); + + 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 end_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 end_wrapping_key; + } + if (SECITEM_AllocItem (NULL, &wrapped_item, wrapped_item.len) == NULL) + { + res = CKR_HOST_MEMORY; + goto end_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 end_wrapped_item; + } + + ctx = PK11_CreateContextBySymKey (CKM_AES_CBC_PAD, CKA_DECRYPT, wrapping_key, + &iv_item); + if (ctx == NULL) + { + res = CKR_GENERAL_ERROR; + goto end_wrapped_item; + } + memset (&der_info, 0, sizeof (der_info)); + if (SECITEM_AllocItem (NULL, &der_info, wrapped_item.len) == NULL) + { + PK11_DestroyContext (ctx, PR_TRUE); + res = CKR_HOST_MEMORY; + goto end_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 end_der_info; + } + /* 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 end_der_info; + } + der_info.len += der_info_len; + + /* 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) + { + res = CKR_HOST_MEMORY; + goto end_der_info; + } + + /* "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 end_arena; + } + + /* Should we validate the version and algorithm ID here? */ + + if (dest == NULL) + { + *dest_size_ptr = der_output.private_key.len; + return CKR_OK; + } + if (*dest_size_ptr < der_output.private_key.len) + { + *dest_size_ptr = der_output.private_key.len; + return CKR_BUFFER_TOO_SMALL; + } + *dest_size_ptr = der_output.private_key.len; + + memcpy (dest, der_output.private_key.data, der_output.private_key.len); + res = CKR_OK; + + end_arena: + PORT_FreeArena (arena, PR_TRUE); + end_der_info: + SECITEM_ZfreeItem (&der_info, PR_FALSE); + end_wrapped_item: + SECITEM_ZfreeItem (&wrapped_item, PR_FALSE); + end_wrapping_key: + PK11_FreeSymKey (wrapping_key); + end_slot: + PK11_FreeSlot (slot); + return res; } CK_RV @@ -608,8 +769,9 @@ ncr_public_key_export_rsa (struct ncr_public_key *key, 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, +ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive, + 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, @@ -673,7 +835,8 @@ ncr_private_key_create_rsa (struct ncr_private_key **key, const void *modulus, if (SEC_ASN1EncodeItem (NULL, &der_key, &der_input, 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.modulus); PORT_Free (der_key.data); return res; -- cgit From e4392e2df40c8d89109630fa7cab951f6c8ab70d Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Thu, 25 Nov 2010 23:46:03 +0100 Subject: Beautify --- lib/ncrypto_nss.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index 48d2e47..24e7e30 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -650,9 +650,9 @@ struct rsa_public_key static const SEC_ASN1Template rsa_public_key_asn1_template[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct rsa_public_key) }, -#define INT(X) { \ - SEC_ASN1_INTEGER, offsetof (struct rsa_public_key, X), NULL, 0, \ - } +#define INT(X) \ + { SEC_ASN1_INTEGER, offsetof (struct rsa_public_key, X), NULL, 0, } + INT (modulus), INT (public_exponent), #undef INT { 0, 0, NULL, 0 } -- cgit From eafbed071d3e3de75f8539c1473edd5a8af28cac Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Thu, 25 Nov 2010 23:46:40 +0100 Subject: Report all required sizes if any one is too small --- lib/ncrypto_nss.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index 24e7e30..b6e7464 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -744,19 +744,13 @@ ncr_public_key_export_rsa (struct ncr_public_key *key, void *modulus, } res = CKR_OK; if (*modulus_size_ptr < der_output.modulus.len) - { - *modulus_size_ptr = der_output.modulus.len; - res = CKR_BUFFER_TOO_SMALL; - } + res = CKR_BUFFER_TOO_SMALL; + *modulus_size_ptr = der_output.modulus.len; if (*public_exponent_size_ptr < der_output.public_exponent.len) - { - *public_exponent_size_ptr = der_output.public_exponent.len; - res = CKR_BUFFER_TOO_SMALL; - } + res = CKR_BUFFER_TOO_SMALL; + *public_exponent_size_ptr = der_output.public_exponent.len; if (res != CKR_OK) goto end; - *modulus_size_ptr = der_output.modulus.len; - *public_exponent_size_ptr = der_output.public_exponent.len; memcpy (modulus, der_output.modulus.data, der_output.modulus.len); memcpy (public_exponent, der_output.public_exponent.data, -- cgit From 6185079fd24c308530a4cebc66acc86dd7b40375 Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Fri, 26 Nov 2010 00:37:52 +0100 Subject: Add ncr_private_key_export_rsa () --- include/ncrypto/ncrypto.h | 12 ++ lib/ncrypto_nss.c | 312 ++++++++++++++++++++++++++++++++-------------- tests/rsa.c | 77 +++++++++--- 3 files changed, 286 insertions(+), 115 deletions(-) diff --git a/include/ncrypto/ncrypto.h b/include/ncrypto/ncrypto.h index 47ca5df..fe10d9f 100644 --- a/include/ncrypto/ncrypto.h +++ b/include/ncrypto/ncrypto.h @@ -110,6 +110,18 @@ CK_RV ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive, size_t exponent_2_size, const void *coefficient, size_t coefficient_size); +CK_RV ncr_private_key_export_rsa (struct ncr_private_key *key, void *modulus, + size_t *modulus_size_ptr, + void *public_exponent, + size_t *public_exponent_size_ptr, + void *private_exponent, + size_t *private_exponent_size_ptr, + void *prime_1, size_t *prime_1_size_ptr, + void *prime_2, size_t *prime_2_size_ptr, + void *exponent_1, size_t *exponent_1_size_ptr, + void *exponent_2, size_t *exponent_2_size_ptr, + void *coefficient, + size_t *coefficient_size_ptr); /* Asymmetric operations */ diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index b6e7464..a925c48 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -445,53 +445,16 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type, return CKR_GENERAL_ERROR; } -/* 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, - _Bool sensitive, const void *der, size_t der_size, - const void *public_value, size_t public_value_size) -{ - SECItem der_key; - SECItem public; - CK_RV res; - - res = ensure_ncr_is_open (); - if (res != CKR_OK) - return res; - - g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD); - g_return_val_if_fail (der != NULL, CKR_ARGUMENTS_BAD); - - der_key.data = (void *)der; - der_key.len = der_size; - public.data = (void *)public_value; - public.len = public_value_size; - return private_key_create (key, type, sensitive, &der_key, &public); -} - -CK_RV -ncr_private_key_set_sensitive (struct ncr_private_key *key) -{ - CK_RV res; - - res = ensure_ncr_is_open (); - if (res != CKR_OK) - return res; - - g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID); - key->sensitive = true; - return CKR_OK; -} - -CK_RV -ncr_private_key_export (struct ncr_private_key *key, void *dest, - size_t *dest_size_ptr) +/* The caller is responsible for freeing the arena and der_info. */ +static CK_RV +private_key_export (struct ncr_private_key *key, SECItem *der_key, + PRArenaPool **arena_ptr, SECItem *der_info) { 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; + SECItem key_item, iv_item, wrapped_item; PK11SymKey *wrapping_key; PK11Context *ctx; int der_info_len; @@ -501,7 +464,6 @@ ncr_private_key_export (struct ncr_private_key *key, void *dest, CK_RV res; g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID); - g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD); g_return_val_if_fail (!key->sensitive, CKR_ATTRIBUTE_SENSITIVE); @@ -519,7 +481,7 @@ ncr_private_key_export (struct ncr_private_key *key, void *dest, if (wrapping_key == NULL) { res = CKR_GENERAL_ERROR; - goto end_slot; + goto err_slot; } iv_item.data = (void *)wrap_iv; iv_item.len = sizeof (wrap_iv); @@ -529,18 +491,18 @@ ncr_private_key_export (struct ncr_private_key *key, void *dest, &wrapped_item, NULL) != SECSuccess) { res = CKR_GENERAL_ERROR; - goto end_wrapping_key; + goto err_wrapping_key; } if (SECITEM_AllocItem (NULL, &wrapped_item, wrapped_item.len) == NULL) { res = CKR_HOST_MEMORY; - goto end_wrapping_key; + 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 end_wrapped_item; + goto err_wrapped_item; } ctx = PK11_CreateContextBySymKey (CKM_AES_CBC_PAD, CKA_DECRYPT, wrapping_key, @@ -548,32 +510,32 @@ ncr_private_key_export (struct ncr_private_key *key, void *dest, if (ctx == NULL) { res = CKR_GENERAL_ERROR; - goto end_wrapped_item; + goto err_wrapped_item; } - memset (&der_info, 0, sizeof (der_info)); - if (SECITEM_AllocItem (NULL, &der_info, wrapped_item.len) == NULL) + memset (der_info, 0, sizeof (*der_info)); + if (SECITEM_AllocItem (NULL, der_info, wrapped_item.len) == NULL) { PK11_DestroyContext (ctx, PR_TRUE); res = CKR_HOST_MEMORY; - goto end_wrapped_item; + goto err_wrapped_item; } - if (PK11_CipherOp (ctx, der_info.data, &der_info_len, der_info.len, + 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 end_der_info; + goto err_der_info; } /* 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); + 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 end_der_info; + goto err_der_info; } - der_info.len += der_info_len; + der_info->len += der_info_len; /* Ugly... the PLArenaPool type is from NSPR, but NSS implementation accesses memory only initialized through NSS's PORT_* */ @@ -581,46 +543,115 @@ ncr_private_key_export (struct ncr_private_key *key, void *dest, if (arena == NULL) { res = CKR_HOST_MEMORY; - goto end_der_info; + goto err_der_info; } /* "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) + private_key_info_asn1_template, der_info) != SECSuccess) { res = CKR_GENERAL_ERROR; - goto end_arena; + goto err_arena; } /* Should we validate the version and algorithm ID here? */ + *der_key = der_output.private_key; + *arena_ptr = arena; + + SECITEM_ZfreeItem (&wrapped_item, PR_FALSE); + PK11_FreeSymKey (wrapping_key); + PK11_FreeSlot (slot); + + return CKR_OK; + + err_arena: + PORT_FreeArena (arena, PR_TRUE); + err_der_info: + SECITEM_ZfreeItem (der_info, PR_FALSE); + 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, + _Bool sensitive, const void *der, size_t der_size, + const void *public_value, size_t public_value_size) +{ + SECItem der_key; + SECItem public; + CK_RV res; + + res = ensure_ncr_is_open (); + if (res != CKR_OK) + return res; + + g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD); + g_return_val_if_fail (der != NULL, CKR_ARGUMENTS_BAD); + + der_key.data = (void *)der; + der_key.len = der_size; + public.data = (void *)public_value; + public.len = public_value_size; + return private_key_create (key, type, sensitive, &der_key, &public); +} + +CK_RV +ncr_private_key_set_sensitive (struct ncr_private_key *key) +{ + CK_RV res; + + res = ensure_ncr_is_open (); + if (res != CKR_OK) + return res; + + g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID); + 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_info, der_key; + CK_RV res; + + g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD); + + res = private_key_export (key, &der_key, &arena, &der_info); + if (res != CKR_OK) + return res; + if (dest == NULL) { - *dest_size_ptr = der_output.private_key.len; - return CKR_OK; + *dest_size_ptr = der_key.len; + res = CKR_OK; + goto end; } - if (*dest_size_ptr < der_output.private_key.len) + if (*dest_size_ptr < der_key.len) { - *dest_size_ptr = der_output.private_key.len; - return CKR_BUFFER_TOO_SMALL; + *dest_size_ptr = der_key.len; + res = CKR_BUFFER_TOO_SMALL; + goto end; } - *dest_size_ptr = der_output.private_key.len; + *dest_size_ptr = der_key.len; - memcpy (dest, der_output.private_key.data, der_output.private_key.len); + memcpy (dest, der_key.data, der_key.len); res = CKR_OK; - end_arena: + end: PORT_FreeArena (arena, PR_TRUE); - end_der_info: SECITEM_ZfreeItem (&der_info, PR_FALSE); - end_wrapped_item: - SECITEM_ZfreeItem (&wrapped_item, PR_FALSE); - end_wrapping_key: - PK11_FreeSymKey (wrapping_key); - end_slot: - PK11_FreeSlot (slot); return res; } @@ -658,6 +689,26 @@ static const SEC_ASN1Template rsa_public_key_asn1_template[] = { 0, 0, NULL, 0 } }; +struct rsa_private_key +{ + SECItem version; + SECItem modulus, public_exponent, private_exponent, prime_1, prime_2; + SECItem exponent_1, exponent_2, coefficient; +}; + +static const SEC_ASN1Template rsa_private_key_asn1_template[] = + { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct rsa_private_key) }, +#define INT(X) \ + { SEC_ASN1_INTEGER, offsetof (struct rsa_private_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 } + }; + CK_RV ncr_public_key_create_rsa (struct ncr_public_key **key, const void *modulus, size_t modulus_size, const void *public_exponent, @@ -775,27 +826,9 @@ ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive, 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; - }; - - 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 (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 } - }; static const uint8_t zero; /* = 0; */ - struct rsa_pub_key der_input; + struct rsa_private_key der_input; SECItem der_key; CK_RV res; @@ -826,7 +859,8 @@ ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive, 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, sensitive, &der_key, @@ -836,6 +870,94 @@ ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive, return res; } +CK_RV +ncr_private_key_export_rsa (struct ncr_private_key *key, void *modulus, + size_t *modulus_size_ptr, void *public_exponent, + size_t *public_exponent_size_ptr, + void *private_exponent, + size_t *private_exponent_size_ptr, + void *prime_1, size_t *prime_1_size_ptr, + void *prime_2, size_t *prime_2_size_ptr, + void *exponent_1, size_t *exponent_1_size_ptr, + void *exponent_2, size_t *exponent_2_size_ptr, + void *coefficient, size_t *coefficient_size_ptr) +{ + struct rsa_private_key der_output; + PRArenaPool *arena; + SECItem der_info, der_key; + CK_RV res; + + /* This works in C because "INT" is expanded only at the point where ALL_INTS + is used. */ +#define ALL_INTS \ + INT (modulus); \ + INT (public_exponent); \ + INT (private_exponent); \ + INT (prime_1); \ + INT (prime_2); \ + INT (exponent_1); \ + INT (exponent_2); \ + INT (coefficient); + + res = ensure_ncr_is_open (); + if (res != CKR_OK) + return res; + +#define INT(X) g_return_val_if_fail (X##_size_ptr != NULL, CKR_ARGUMENTS_BAD) + ALL_INTS; +#undef INT + + res = private_key_export (key, &der_key, &arena, &der_info); + if (res != CKR_OK) + return res; + + /* Setting type to siUnsignedInteger requests removal of leading zeroes. */ + der_output.version.type = siUnsignedInteger; +#define INT(X) der_output.X.type = siUnsignedInteger + ALL_INTS; +#undef INT + if (SEC_QuickDERDecodeItem (arena, &der_output, rsa_private_key_asn1_template, + &der_key) != SECSuccess) + { + res = CKR_GENERAL_ERROR; + goto end; + } + + if (modulus == NULL || public_exponent == NULL || private_exponent == NULL + || prime_1 == NULL || prime_2 == NULL || exponent_1 == NULL + || exponent_2 == NULL || coefficient == NULL) + { +#define INT(X) *X##_size_ptr = der_output.X.len + ALL_INTS; +#undef INT + res = CKR_OK; + goto end; + } + res = CKR_OK; +#define INT(X) \ + do \ + { \ + if (*X##_size_ptr < der_output.X.len) \ + res = CKR_BUFFER_TOO_SMALL; \ + *X##_size_ptr = der_output.X.len; \ + } \ + while (0) + ALL_INTS; +#undef INT + if (res != CKR_OK) + goto end; + +#define INT(X) memcpy((X), der_output.X.data, der_output.X.len) + ALL_INTS; +#undef INT + + end: + PORT_FreeArena (arena, PR_TRUE); + SECITEM_ZfreeItem (&der_info, PR_FALSE); + return res; +#undef DO_INTS +} + /* Asymmetric operations */ CK_RV diff --git a/tests/rsa.c b/tests/rsa.c index 4e16769..85e1fe6 100644 --- a/tests/rsa.c +++ b/tests/rsa.c @@ -26,6 +26,7 @@ POSSIBILITY OF SUCH DAMAGE. Red Hat author: Miloslav Trmač */ #include +#include #include #include #include @@ -47,25 +48,43 @@ static const uint8_t input[] = "\x00\x01\x02\x03\x04\x05"; int main (void) { + /* This works in C because "INT" is expanded only at the point where the other + macros are used. */ +#define PUBLIC_INTS_COMMAS INT (modulus), INT (public_exponent) +#define PUBLIC_INTS \ + INT (modulus); \ + INT (public_exponent); +#define ALL_INTS_COMMAS \ + INT (modulus), INT (public_exponent), INT (private_exponent), INT (prime_1), \ + INT (prime_2), INT (exponent_1), INT (exponent_2), INT (coefficient) +#define ALL_INTS \ + INT (modulus); \ + INT (public_exponent); \ + INT (private_exponent); \ + INT (prime_1); \ + INT (prime_2); \ + INT (exponent_1); \ + INT (exponent_2); \ + INT (coefficient); + struct ncr_public_key *public; struct ncr_private_key *private; - uint8_t dest[4096], dest2[4096]; - size_t src_size, dest_size, dest2_size; + uint8_t dest[4096]; + size_t src_size, dest_size; +#define INT(X) uint8_t export_##X[256]; size_t export_##X##_size + ALL_INTS; +#undef INT CK_RV res; /* Test key loading. Should we test the generic version as well? */ - res = ncr_public_key_create_rsa (&public, modulus, sizeof (modulus), - public_exponent, sizeof (public_exponent)); +#define INT(X) X, sizeof (X) + res = ncr_public_key_create_rsa (&public, + PUBLIC_INTS_COMMAS); assert (res == CKR_OK); - res = ncr_private_key_create_rsa (&private, modulus, sizeof (modulus), - public_exponent, sizeof (public_exponent), - private_exponent, sizeof (private_exponent), - prime_1, sizeof (prime_1), prime_2, - sizeof (prime_2), exponent_1, - sizeof (exponent_1), exponent_2, - sizeof (exponent_2), coefficient, - sizeof (coefficient)); + res = ncr_private_key_create_rsa (&private, false, + ALL_INTS_COMMAS); assert (res == CKR_OK); +#undef INT /* Test encryption */ @@ -95,15 +114,33 @@ main (void) sizeof (input)); assert (res != CKR_OK); - dest_size = sizeof (dest); - dest2_size = sizeof (dest2); - res = ncr_public_key_export_rsa (public, dest, &dest_size, dest2, - &dest2_size); +#define INT(X) export_##X##_size = sizeof (export_##X); + PUBLIC_INTS; +#undef INT +#define INT(X) export_##X, &export_##X##_size + res = ncr_public_key_export_rsa (public, PUBLIC_INTS_COMMAS); +#undef INT + assert (res == CKR_OK); +#define INT(X) assert (export_##X##_size == sizeof (X)) + PUBLIC_INTS; +#undef INT +#define INT(X) assert (memcmp (export_##X, (X), export_##X##_size) == 0); + PUBLIC_INTS; +#undef INT + +#define INT(X) export_##X##_size = sizeof (export_##X); + ALL_INTS; +#undef INT +#define INT(X) export_##X, &export_##X##_size + res = ncr_private_key_export_rsa (private, ALL_INTS_COMMAS); +#undef INT assert (res == CKR_OK); - assert (dest_size == sizeof (modulus)); - assert (dest2_size == sizeof (public_exponent)); - assert (memcmp (dest, modulus, dest_size) == 0); - assert (memcmp (dest2, public_exponent, dest2_size) == 0); +#define INT(X) assert (export_##X##_size == sizeof (X)) + ALL_INTS; +#undef INT +#define INT(X) assert (memcmp (export_##X, (X), export_##X##_size) == 0); + ALL_INTS; +#undef INT res = ncr_private_key_destroy (private); assert (res == CKR_OK); -- cgit From 5ad8bc2eff7da90d5f9d3d7475b7c9be06fe10ce Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Fri, 26 Nov 2010 00:42:41 +0100 Subject: Both allocate and free arena in public_key_export callers --- lib/ncrypto_nss.c | 71 ++++++++++++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index a925c48..0c57b0f 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -170,11 +170,10 @@ public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type, return CKR_OK; } -/* The caller is responsible for freeing the arena and der_spki. */ +/* The caller is responsible for freeing der_spki. */ static CK_RV -public_key_export (struct ncr_public_key *key, void **der_key, - size_t *der_key_size, PRArenaPool **arena_ptr, - SECItem **der_spki_ptr) +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 { @@ -197,9 +196,7 @@ public_key_export (struct ncr_public_key *key, void **der_key, }; struct subject_pub_key_info der_output; - PRArenaPool *arena; SECItem *der_spki; - CK_RV res; g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD); @@ -207,20 +204,11 @@ public_key_export (struct ncr_public_key *key, void **der_key, if (der_spki == NULL) return CKR_GENERAL_ERROR; - /* 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) - { - res = CKR_HOST_MEMORY; - goto err_der_spki; - } - if (SEC_QuickDERDecodeItem (arena, &der_output, asn1_template, der_spki) != SECSuccess) { - res = CKR_GENERAL_ERROR; - goto err_arena; + SECITEM_FreeItem (der_spki, PR_TRUE); + return CKR_GENERAL_ERROR; } *der_key = der_output.pub_key.data; @@ -228,15 +216,8 @@ public_key_export (struct ncr_public_key *key, void **der_key, _bits_. */ *der_key_size = (der_output.pub_key.len / 8 + (der_output.pub_key.len % 8 != 0)); - *arena_ptr = arena; *der_spki_ptr = der_spki; return CKR_OK; - - err_arena: - PORT_FreeArena (arena, PR_FALSE); - err_der_spki: - SECITEM_FreeItem (der_spki, PR_TRUE); - return res; } CK_RV @@ -274,30 +255,37 @@ ncr_public_key_export (struct ncr_public_key *key, void *dest, g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD); - res = public_key_export (key, &der_key, &der_key_size, &arena, &der_spki); + /* 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) - return res; + goto end_arena; if (dest == NULL) { *dest_size_ptr = der_key_size; res = CKR_OK; - goto end; + goto end_der_spki; } if (*dest_size_ptr < der_key_size) { *dest_size_ptr = der_key_size; res = CKR_BUFFER_TOO_SMALL; - goto end; + goto end_der_spki; } *dest_size_ptr = der_key_size; memcpy (dest, der_key, der_key_size); res = CKR_OK; - end: - PORT_FreeArena (arena, PR_FALSE); + end_der_spki: SECITEM_FreeItem (der_spki, PR_TRUE); + end_arena: + PORT_FreeArena (arena, PR_FALSE); return res; } @@ -765,16 +753,22 @@ ncr_public_key_export_rsa (struct ncr_public_key *key, void *modulus, g_return_val_if_fail (modulus_size_ptr != NULL, CKR_ARGUMENTS_BAD); g_return_val_if_fail (public_exponent_size_ptr != NULL, CKR_ARGUMENTS_BAD); - res = public_key_export (key, &der_key, &der_key_size, &arena, &der_spki); + /* 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) - return res; + goto end_arena; der_key_item.data = der_key; der_key_item.len = der_key_size; if (der_key_item.len != der_key_size) { res = CKR_GENERAL_ERROR; - goto end; + goto end_der_spki; } /* Setting type to siUnsignedInteger requests removal of leading zeroes. */ der_output.modulus.type = siUnsignedInteger; @@ -783,7 +777,7 @@ ncr_public_key_export_rsa (struct ncr_public_key *key, void *modulus, &der_key_item) != SECSuccess) { res = CKR_GENERAL_ERROR; - goto end; + goto end_der_spki; } if (modulus == NULL || public_exponent == NULL) @@ -791,7 +785,7 @@ ncr_public_key_export_rsa (struct ncr_public_key *key, void *modulus, *modulus_size_ptr = der_output.modulus.len; *public_exponent_size_ptr = der_output.public_exponent.len; res = CKR_OK; - goto end; + goto end_der_spki; } res = CKR_OK; if (*modulus_size_ptr < der_output.modulus.len) @@ -801,15 +795,16 @@ ncr_public_key_export_rsa (struct ncr_public_key *key, void *modulus, res = CKR_BUFFER_TOO_SMALL; *public_exponent_size_ptr = der_output.public_exponent.len; if (res != CKR_OK) - goto end; + goto end_der_spki; memcpy (modulus, der_output.modulus.data, der_output.modulus.len); memcpy (public_exponent, der_output.public_exponent.data, der_output.public_exponent.len); - end: - PORT_FreeArena (arena, PR_FALSE); + end_der_spki: SECITEM_FreeItem (der_spki, PR_TRUE); + end_arena: + PORT_FreeArena (arena, PR_FALSE); return res; } -- cgit From 21c90e0365ac50c57ad5a3493582e996a236d1a3 Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Fri, 26 Nov 2010 00:53:23 +0100 Subject: Use an arena better in private_key_export Both allocate and free the arena in the caller. Use the arena to allocate der_info to make it invisible to the caller. --- lib/ncrypto_nss.c | 72 +++++++++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index 0c57b0f..ac0818b 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -433,20 +433,18 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type, return CKR_GENERAL_ERROR; } -/* The caller is responsible for freeing the arena and der_info. */ static CK_RV -private_key_export (struct ncr_private_key *key, SECItem *der_key, - PRArenaPool **arena_ptr, SECItem *der_info) +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; + SECItem key_item, iv_item, wrapped_item, der_info; PK11SymKey *wrapping_key; PK11Context *ctx; int der_info_len; - PRArenaPool *arena; struct private_key_info der_output; SECStatus ss; CK_RV res; @@ -500,54 +498,44 @@ private_key_export (struct ncr_private_key *key, SECItem *der_key, res = CKR_GENERAL_ERROR; goto err_wrapped_item; } - memset (der_info, 0, sizeof (*der_info)); - if (SECITEM_AllocItem (NULL, der_info, wrapped_item.len) == NULL) + 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, + 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_der_info; + 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); + 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_der_info; - } - der_info->len += der_info_len; - - /* 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) - { - res = CKR_HOST_MEMORY; - goto err_der_info; + 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) + private_key_info_asn1_template, &der_info) != SECSuccess) { res = CKR_GENERAL_ERROR; - goto err_arena; + goto err_wrapped_item; } /* Should we validate the version and algorithm ID here? */ *der_key = der_output.private_key; - *arena_ptr = arena; SECITEM_ZfreeItem (&wrapped_item, PR_FALSE); PK11_FreeSymKey (wrapping_key); @@ -555,10 +543,6 @@ private_key_export (struct ncr_private_key *key, SECItem *der_key, return CKR_OK; - err_arena: - PORT_FreeArena (arena, PR_TRUE); - err_der_info: - SECITEM_ZfreeItem (der_info, PR_FALSE); err_wrapped_item: SECITEM_ZfreeItem (&wrapped_item, PR_FALSE); err_wrapping_key: @@ -611,14 +595,24 @@ ncr_private_key_export (struct ncr_private_key *key, void *dest, size_t *dest_size_ptr) { PRArenaPool *arena; - SECItem der_info, der_key; + 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); - res = private_key_export (key, &der_key, &arena, &der_info); + /* 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) - return res; + goto end; if (dest == NULL) { @@ -639,7 +633,6 @@ ncr_private_key_export (struct ncr_private_key *key, void *dest, end: PORT_FreeArena (arena, PR_TRUE); - SECITEM_ZfreeItem (&der_info, PR_FALSE); return res; } @@ -879,7 +872,7 @@ ncr_private_key_export_rsa (struct ncr_private_key *key, void *modulus, { struct rsa_private_key der_output; PRArenaPool *arena; - SECItem der_info, der_key; + SECItem der_key; CK_RV res; /* This works in C because "INT" is expanded only at the point where ALL_INTS @@ -902,9 +895,15 @@ ncr_private_key_export_rsa (struct ncr_private_key *key, void *modulus, ALL_INTS; #undef INT - res = private_key_export (key, &der_key, &arena, &der_info); + /* 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) - return res; + goto end; /* Setting type to siUnsignedInteger requests removal of leading zeroes. */ der_output.version.type = siUnsignedInteger; @@ -948,7 +947,6 @@ ncr_private_key_export_rsa (struct ncr_private_key *key, void *modulus, end: PORT_FreeArena (arena, PR_TRUE); - SECITEM_ZfreeItem (&der_info, PR_FALSE); return res; #undef DO_INTS } -- cgit From e7fa04556e265d65232d6ef2afc6c0c472198011 Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Fri, 26 Nov 2010 02:00:31 +0100 Subject: Pass MPIs around in arrays, not named parameters --- include/ncrypto/ncrypto.h | 70 ++++++++------ lib/ncrypto_nss.c | 242 +++++++++++++++++++++------------------------- tests/rsa.c | 120 +++++++++++------------ 3 files changed, 204 insertions(+), 228 deletions(-) diff --git a/include/ncrypto/ncrypto.h b/include/ncrypto/ncrypto.h index fe10d9f..16d8258 100644 --- a/include/ncrypto/ncrypto.h +++ b/include/ncrypto/ncrypto.h @@ -86,42 +86,50 @@ CK_RV ncr_private_key_export (struct ncr_private_key *key, void *dest, size_t *dest_size_ptr); CK_RV ncr_private_key_destroy (struct ncr_private_key *key); + /* Multi-precision integers */ + +/* This is used to avoid e.g. 8 separate parameters for RSA private key + passing. */ +struct ncr_mpi +{ + void *data; + size_t size; +}; + /* RSA keys */ +enum + { + NCR_RSA_PUBLIC_MPI_MODULUS, + NCR_RSA_PUBLIC_MPI_PUBLIC_EXPONENT, + NCR_RSA_PUBLIC_NUM_MPIS + }; + +enum + { + NCR_RSA_PRIVATE_MPI_MODULUS, + NCR_RSA_PRIVATE_MPI_PUBLIC_EXPONENT, + NCR_RSA_PRIVATE_MPI_PRIVATE_EXPONENT, + NCR_RSA_PRIVATE_MPI_PRIME_1, + NCR_RSA_PRIVATE_MPI_PRIME_2, + NCR_RSA_PRIVATE_MPI_EXPONENT_1, + NCR_RSA_PRIVATE_MPI_EXPONENT_2, + NCR_RSA_PRIVATE_MPI_COEFFICIENT, + NCR_RSA_PRIVATE_NUM_MPIS + }; + 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); + const struct ncr_mpi + mpis[static NCR_RSA_PUBLIC_NUM_MPIS]); CK_RV ncr_public_key_export_rsa (struct ncr_public_key *key, - void *modulus, size_t *modulus_size_ptr, - void *public_exponent, - size_t *public_exponent_size_ptr); + struct ncr_mpi + mpis [static NCR_RSA_PUBLIC_NUM_MPIS]); CK_RV ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive, - 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); -CK_RV ncr_private_key_export_rsa (struct ncr_private_key *key, void *modulus, - size_t *modulus_size_ptr, - void *public_exponent, - size_t *public_exponent_size_ptr, - void *private_exponent, - size_t *private_exponent_size_ptr, - void *prime_1, size_t *prime_1_size_ptr, - void *prime_2, size_t *prime_2_size_ptr, - void *exponent_1, size_t *exponent_1_size_ptr, - void *exponent_2, size_t *exponent_2_size_ptr, - void *coefficient, - size_t *coefficient_size_ptr); + const struct ncr_mpi + mpis[static NCR_RSA_PRIVATE_NUM_MPIS]); +CK_RV ncr_private_key_export_rsa (struct ncr_private_key *key, + struct ncr_mpi + mpis[static NCR_RSA_PRIVATE_NUM_MPIS]); /* Asymmetric operations */ diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index ac0818b..dfd342c 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -652,20 +652,81 @@ ncr_private_key_destroy (struct ncr_private_key *key) return CKR_OK; } + /* 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 { - SECItem modulus, public_exponent; + SECItem items[NCR_RSA_PUBLIC_NUM_MPIS]; }; static const SEC_ASN1Template rsa_public_key_asn1_template[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct rsa_public_key) }, #define INT(X) \ - { SEC_ASN1_INTEGER, offsetof (struct rsa_public_key, X), NULL, 0, } + { \ + SEC_ASN1_INTEGER, \ + offsetof (struct rsa_public_key, items) + (X) * sizeof (SECItem), NULL, \ + 0 \ + } - INT (modulus), INT (public_exponent), + INT (NCR_RSA_PUBLIC_MPI_MODULUS), INT (NCR_RSA_PUBLIC_MPI_PUBLIC_EXPONENT), #undef INT { 0, 0, NULL, 0 } }; @@ -673,27 +734,34 @@ static const SEC_ASN1Template rsa_public_key_asn1_template[] = struct rsa_private_key { SECItem version; - SECItem modulus, public_exponent, private_exponent, prime_1, prime_2; - SECItem exponent_1, exponent_2, coefficient; + 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, X), NULL, 0 } + { \ + SEC_ASN1_INTEGER, \ + offsetof (struct rsa_private_key, items) + (X) * sizeof (SECItem), 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), + 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 } }; 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) +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; @@ -703,17 +771,10 @@ 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; @@ -728,9 +789,8 @@ ncr_public_key_create_rsa (struct ncr_public_key **key, const void *modulus, } CK_RV -ncr_public_key_export_rsa (struct ncr_public_key *key, void *modulus, - size_t *modulus_size_ptr, void *public_exponent, - size_t *public_exponent_size_ptr) +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; @@ -738,13 +798,13 @@ ncr_public_key_export_rsa (struct ncr_public_key *key, void *modulus, void *der_key; size_t der_key_size; CK_RV res; + size_t i; res = ensure_ncr_is_open (); if (res != CKR_OK) return res; - g_return_val_if_fail (modulus_size_ptr != NULL, CKR_ARGUMENTS_BAD); - g_return_val_if_fail (public_exponent_size_ptr != NULL, CKR_ARGUMENTS_BAD); + 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_* */ @@ -764,8 +824,8 @@ ncr_public_key_export_rsa (struct ncr_public_key *key, void *modulus, goto end_der_spki; } /* Setting type to siUnsignedInteger requests removal of leading zeroes. */ - der_output.modulus.type = siUnsignedInteger; - der_output.public_exponent.type = siUnsignedInteger; + 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) { @@ -773,26 +833,8 @@ ncr_public_key_export_rsa (struct ncr_public_key *key, void *modulus, goto end_der_spki; } - if (modulus == NULL || public_exponent == NULL) - { - *modulus_size_ptr = der_output.modulus.len; - *public_exponent_size_ptr = der_output.public_exponent.len; - res = CKR_OK; - goto end_der_spki; - } - res = CKR_OK; - if (*modulus_size_ptr < der_output.modulus.len) - res = CKR_BUFFER_TOO_SMALL; - *modulus_size_ptr = der_output.modulus.len; - if (*public_exponent_size_ptr < der_output.public_exponent.len) - res = CKR_BUFFER_TOO_SMALL; - *public_exponent_size_ptr = der_output.public_exponent.len; - if (res != CKR_OK) - goto end_der_spki; - - memcpy (modulus, der_output.modulus.data, der_output.modulus.len); - memcpy (public_exponent, der_output.public_exponent.data, - der_output.public_exponent.len); + res = mpi_output_decoded_SECItems(mpis, der_output.items, + NCR_RSA_PUBLIC_NUM_MPIS); end_der_spki: SECITEM_FreeItem (der_spki, PR_TRUE); @@ -803,16 +845,8 @@ ncr_public_key_export_rsa (struct ncr_public_key *key, void *modulus, CK_RV ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive, - 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) + const struct ncr_mpi + mpis[static NCR_RSA_PRIVATE_NUM_MPIS]) { static const uint8_t zero; /* = 0; */ @@ -824,27 +858,14 @@ ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive, 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, @@ -852,48 +873,28 @@ ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive, return CKR_HOST_MEMORY; res = private_key_create (key, CKK_RSA, sensitive, &der_key, - &der_input.modulus); + &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, void *modulus, - size_t *modulus_size_ptr, void *public_exponent, - size_t *public_exponent_size_ptr, - void *private_exponent, - size_t *private_exponent_size_ptr, - void *prime_1, size_t *prime_1_size_ptr, - void *prime_2, size_t *prime_2_size_ptr, - void *exponent_1, size_t *exponent_1_size_ptr, - void *exponent_2, size_t *exponent_2_size_ptr, - void *coefficient, size_t *coefficient_size_ptr) +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; - - /* This works in C because "INT" is expanded only at the point where ALL_INTS - is used. */ -#define ALL_INTS \ - INT (modulus); \ - INT (public_exponent); \ - INT (private_exponent); \ - INT (prime_1); \ - INT (prime_2); \ - INT (exponent_1); \ - INT (exponent_2); \ - INT (coefficient); + size_t i; res = ensure_ncr_is_open (); if (res != CKR_OK) return res; -#define INT(X) g_return_val_if_fail (X##_size_ptr != NULL, CKR_ARGUMENTS_BAD) - ALL_INTS; -#undef INT + 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_* */ @@ -907,9 +908,8 @@ ncr_private_key_export_rsa (struct ncr_private_key *key, void *modulus, /* Setting type to siUnsignedInteger requests removal of leading zeroes. */ der_output.version.type = siUnsignedInteger; -#define INT(X) der_output.X.type = siUnsignedInteger - ALL_INTS; -#undef INT + 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) { @@ -917,38 +917,12 @@ ncr_private_key_export_rsa (struct ncr_private_key *key, void *modulus, goto end; } - if (modulus == NULL || public_exponent == NULL || private_exponent == NULL - || prime_1 == NULL || prime_2 == NULL || exponent_1 == NULL - || exponent_2 == NULL || coefficient == NULL) - { -#define INT(X) *X##_size_ptr = der_output.X.len - ALL_INTS; -#undef INT - res = CKR_OK; - goto end; - } - res = CKR_OK; -#define INT(X) \ - do \ - { \ - if (*X##_size_ptr < der_output.X.len) \ - res = CKR_BUFFER_TOO_SMALL; \ - *X##_size_ptr = der_output.X.len; \ - } \ - while (0) - ALL_INTS; -#undef INT - if (res != CKR_OK) - goto end; - -#define INT(X) memcpy((X), der_output.X.data, der_output.X.len) - ALL_INTS; -#undef INT + res = mpi_output_decoded_SECItems(mpis, der_output.items, + NCR_RSA_PRIVATE_NUM_MPIS); end: PORT_FreeArena (arena, PR_TRUE); return res; -#undef DO_INTS } /* Asymmetric operations */ diff --git a/tests/rsa.c b/tests/rsa.c index 85e1fe6..2eeaa47 100644 --- a/tests/rsa.c +++ b/tests/rsa.c @@ -34,57 +34,61 @@ Red Hat author: Miloslav Trmač */ #include #include -static const uint8_t modulus[64] = "\xB8\xC7\x54\x15\x90\xCF\x91\x7A\xF3\x4C\x45\x53\xC2\x0A\xDA\x84\x4C\x09\x48\x10\x06\x41\xC5\x97\x57\x02\xDA\x0E\x7E\x64\x46\xBD\xC6\x75\x42\xCD\x32\x23\x0C\xEC\x2B\x1C\x60\x03\x68\x1E\x4F\x28\x78\xD8\xB0\xC1\xAC\xA7\x21\xE4\x15\x74\x65\x16\x1C\x59\xC8\x85"; -static const uint8_t public_exponent[3] = "\x01\x00\x01"; -static const uint8_t private_exponent[64] = "\x7B\xD6\xC3\xC8\xEC\x53\xE1\x09\xC9\x13\xDE\x06\xE3\xAE\xC8\x83\x10\x3E\xCC\x38\x49\x29\x3D\x97\x4F\x6E\x8E\xDC\x55\xE3\x38\xF1\x03\xEB\xC1\x09\x80\x16\xB8\x9F\xE1\xC0\x21\x77\xD4\xEE\xF7\x30\xD1\x85\x2B\x1F\x4F\xFE\xD1\x01\xCD\x35\x78\x4A\x97\x6F\x38\x65"; -static const uint8_t prime_1[32] = "\xF5\x7E\xFA\xED\xE0\xEC\x9C\x4E\x6F\xDF\xED\x64\x58\xEC\x18\xA9\x8E\x60\x2E\x49\x7E\xDF\x8E\xCF\x9F\xA5\x4A\x32\xA3\x27\x7E\x1B"; -static const uint8_t prime_2[32] = "\xC0\xAF\x49\x15\x49\x8D\x88\xFB\x28\x7D\x33\x25\x07\x37\xE0\x99\x2C\xA8\x6D\x46\x4F\x7D\x7D\x6E\x01\x95\x6B\x2B\x18\x1B\xBD\xDF"; -static const uint8_t exponent_1[32] = "\xC3\x34\x0F\xB4\xBC\x87\x87\x95\xFA\xF1\x14\x63\x19\x2D\xCA\x42\x70\x5A\x5C\x13\xC6\x95\x5E\x8A\x0B\x08\x34\x22\x65\x87\x0E\x87"; -static const uint8_t exponent_2[32] = "\x27\x3B\x89\x85\xEC\x14\x05\x70\x1E\x2E\x5F\xDB\x8A\x3C\xB6\x5E\x79\xD9\x51\x66\x9F\x88\xCD\xA1\x38\x71\x54\x00\xD2\x47\xD3\xC1"; -static const uint8_t coefficient[32] = "\x39\x09\x3A\x43\xCF\xE3\x65\x63\x2F\x5F\x11\xED\x2C\x42\x88\xEF\xCA\x26\x1E\x08\x96\xCF\x0A\x8F\xCB\x88\x45\x50\xEF\x6A\x38\x07"; + +static const struct ncr_mpi import_mpis[NCR_RSA_PRIVATE_NUM_MPIS] = + { +#define INT(NAME, VAL) \ + [NCR_RSA_PRIVATE_MPI_##NAME] = { (void *)(VAL), sizeof (VAL) - 1 } + + INT (MODULUS, + "\xB8\xC7\x54\x15\x90\xCF\x91\x7A\xF3\x4C\x45\x53\xC2\x0A\xDA\x84\x4C\x09\x48\x10\x06\x41\xC5\x97\x57\x02\xDA\x0E\x7E\x64\x46\xBD\xC6\x75\x42\xCD\x32\x23\x0C\xEC\x2B\x1C\x60\x03\x68\x1E\x4F\x28\x78\xD8\xB0\xC1\xAC\xA7\x21\xE4\x15\x74\x65\x16\x1C\x59\xC8\x85"), + INT (PUBLIC_EXPONENT, "\x01\x00\x01"), + INT (PRIVATE_EXPONENT, "\x7B\xD6\xC3\xC8\xEC\x53\xE1\x09\xC9\x13\xDE\x06\xE3\xAE\xC8\x83\x10\x3E\xCC\x38\x49\x29\x3D\x97\x4F\x6E\x8E\xDC\x55\xE3\x38\xF1\x03\xEB\xC1\x09\x80\x16\xB8\x9F\xE1\xC0\x21\x77\xD4\xEE\xF7\x30\xD1\x85\x2B\x1F\x4F\xFE\xD1\x01\xCD\x35\x78\x4A\x97\x6F\x38\x65"), + INT (PRIME_1, "\xF5\x7E\xFA\xED\xE0\xEC\x9C\x4E\x6F\xDF\xED\x64\x58\xEC\x18\xA9\x8E\x60\x2E\x49\x7E\xDF\x8E\xCF\x9F\xA5\x4A\x32\xA3\x27\x7E\x1B"), + INT (PRIME_2, "\xC0\xAF\x49\x15\x49\x8D\x88\xFB\x28\x7D\x33\x25\x07\x37\xE0\x99\x2C\xA8\x6D\x46\x4F\x7D\x7D\x6E\x01\x95\x6B\x2B\x18\x1B\xBD\xDF"), + INT (EXPONENT_1, "\xC3\x34\x0F\xB4\xBC\x87\x87\x95\xFA\xF1\x14\x63\x19\x2D\xCA\x42\x70\x5A\x5C\x13\xC6\x95\x5E\x8A\x0B\x08\x34\x22\x65\x87\x0E\x87"), + INT (EXPONENT_2, "\x27\x3B\x89\x85\xEC\x14\x05\x70\x1E\x2E\x5F\xDB\x8A\x3C\xB6\x5E\x79\xD9\x51\x66\x9F\x88\xCD\xA1\x38\x71\x54\x00\xD2\x47\xD3\xC1"), + INT (COEFFICIENT, "\x39\x09\x3A\x43\xCF\xE3\x65\x63\x2F\x5F\x11\xED\x2C\x42\x88\xEF\xCA\x26\x1E\x08\x96\xCF\x0A\x8F\xCB\x88\x45\x50\xEF\x6A\x38\x07") +#undef INT + }; static const uint8_t input[] = "\x00\x01\x02\x03\x04\x05"; +static void +validate_mpis (const struct ncr_mpi *mpis, size_t num_mpis) +{ + size_t i; + + for (i = 0; i < num_mpis; i++) + assert (mpis[i].size == import_mpis[i].size); + for (i = 0; i < num_mpis; i++) + assert (memcmp (mpis[i].data, import_mpis[i].data, mpis[i].size) == 0); +} + int main (void) { - /* This works in C because "INT" is expanded only at the point where the other - macros are used. */ -#define PUBLIC_INTS_COMMAS INT (modulus), INT (public_exponent) -#define PUBLIC_INTS \ - INT (modulus); \ - INT (public_exponent); -#define ALL_INTS_COMMAS \ - INT (modulus), INT (public_exponent), INT (private_exponent), INT (prime_1), \ - INT (prime_2), INT (exponent_1), INT (exponent_2), INT (coefficient) -#define ALL_INTS \ - INT (modulus); \ - INT (public_exponent); \ - INT (private_exponent); \ - INT (prime_1); \ - INT (prime_2); \ - INT (exponent_1); \ - INT (exponent_2); \ - INT (coefficient); - struct ncr_public_key *public; struct ncr_private_key *private; - uint8_t dest[4096]; - size_t src_size, dest_size; -#define INT(X) uint8_t export_##X[256]; size_t export_##X##_size - ALL_INTS; -#undef INT + struct ncr_mpi dest_mpis[NCR_RSA_PRIVATE_NUM_MPIS]; + uint8_t dest[4096], mpi_dest[NCR_RSA_PRIVATE_NUM_MPIS][256]; + size_t src_size, dest_size, i; CK_RV res; + /* We took a few shortcuts... validate them now. Note that these are NOT + guaranteed by the API. */ + assert ((size_t)NCR_RSA_PUBLIC_NUM_MPIS <= (size_t)NCR_RSA_PRIVATE_NUM_MPIS); + assert ((size_t)NCR_RSA_PUBLIC_MPI_MODULUS + == (size_t)NCR_RSA_PRIVATE_MPI_MODULUS); + assert ((size_t)NCR_RSA_PUBLIC_MPI_PUBLIC_EXPONENT + == (size_t)NCR_RSA_PRIVATE_MPI_PUBLIC_EXPONENT); + + /* Test key loading. Should we test the generic version as well? */ -#define INT(X) X, sizeof (X) - res = ncr_public_key_create_rsa (&public, - PUBLIC_INTS_COMMAS); + res = ncr_public_key_create_rsa (&public, import_mpis); assert (res == CKR_OK); - res = ncr_private_key_create_rsa (&private, false, - ALL_INTS_COMMAS); + res = ncr_private_key_create_rsa (&private, false, import_mpis); assert (res == CKR_OK); -#undef INT /* Test encryption */ @@ -114,33 +118,23 @@ main (void) sizeof (input)); assert (res != CKR_OK); -#define INT(X) export_##X##_size = sizeof (export_##X); - PUBLIC_INTS; -#undef INT -#define INT(X) export_##X, &export_##X##_size - res = ncr_public_key_export_rsa (public, PUBLIC_INTS_COMMAS); -#undef INT + for (i = 0; i < NCR_RSA_PUBLIC_NUM_MPIS; i++) + { + dest_mpis[i].data = mpi_dest[i]; + dest_mpis[i].size = sizeof (mpi_dest[i]); + } + res = ncr_public_key_export_rsa (public, dest_mpis); assert (res == CKR_OK); -#define INT(X) assert (export_##X##_size == sizeof (X)) - PUBLIC_INTS; -#undef INT -#define INT(X) assert (memcmp (export_##X, (X), export_##X##_size) == 0); - PUBLIC_INTS; -#undef INT - -#define INT(X) export_##X##_size = sizeof (export_##X); - ALL_INTS; -#undef INT -#define INT(X) export_##X, &export_##X##_size - res = ncr_private_key_export_rsa (private, ALL_INTS_COMMAS); -#undef INT + validate_mpis (dest_mpis, NCR_RSA_PUBLIC_NUM_MPIS); + + for (i = 0; i < NCR_RSA_PRIVATE_NUM_MPIS; i++) + { + dest_mpis[i].data = mpi_dest[i]; + dest_mpis[i].size = sizeof (mpi_dest[i]); + } + res = ncr_private_key_export_rsa (private, dest_mpis); assert (res == CKR_OK); -#define INT(X) assert (export_##X##_size == sizeof (X)) - ALL_INTS; -#undef INT -#define INT(X) assert (memcmp (export_##X, (X), export_##X##_size) == 0); - ALL_INTS; -#undef INT + validate_mpis (dest_mpis, NCR_RSA_PRIVATE_NUM_MPIS); res = ncr_private_key_destroy (private); assert (res == CKR_OK); -- cgit From cb0170516856f563e12d9ff79ad3333f641a2850 Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Mon, 29 Nov 2010 16:38:22 +0100 Subject: Add RSA key generation --- include/ncrypto/ncrypto.h | 5 +++ lib/ncrypto_nss.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++ tests/rsa.c | 87 ++++++++++++++++++++++++++++++----------- 3 files changed, 168 insertions(+), 23 deletions(-) diff --git a/include/ncrypto/ncrypto.h b/include/ncrypto/ncrypto.h index 16d8258..d9508bf 100644 --- a/include/ncrypto/ncrypto.h +++ b/include/ncrypto/ncrypto.h @@ -130,6 +130,11 @@ CK_RV ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive, CK_RV ncr_private_key_export_rsa (struct ncr_private_key *key, struct ncr_mpi mpis[static NCR_RSA_PRIVATE_NUM_MPIS]); +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); /* Asymmetric operations */ diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index dfd342c..818091d 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -33,6 +33,7 @@ Red Hat author: Miloslav Trmač */ #include #include #include +#include #include @@ -652,6 +653,52 @@ ncr_private_key_destroy (struct ncr_private_key *key) return CKR_OK; } +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; + + /* FIXME: propagate "sensitive" here? */ + priv->key = PK11_GenerateKeyPair(slot, mech, params, &pub->key, + PR_FALSE /* isPerm */, + PR_FALSE /* 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 */ @@ -925,6 +972,58 @@ ncr_private_key_export_rsa (struct ncr_private_key *key, 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 diff --git a/tests/rsa.c b/tests/rsa.c index 2eeaa47..16f6012 100644 --- a/tests/rsa.c +++ b/tests/rsa.c @@ -65,32 +65,13 @@ validate_mpis (const struct ncr_mpi *mpis, size_t num_mpis) assert (memcmp (mpis[i].data, import_mpis[i].data, mpis[i].size) == 0); } -int -main (void) +static void +test_key_pair (struct ncr_public_key *public, struct ncr_private_key *private) { - struct ncr_public_key *public; - struct ncr_private_key *private; - struct ncr_mpi dest_mpis[NCR_RSA_PRIVATE_NUM_MPIS]; - uint8_t dest[4096], mpi_dest[NCR_RSA_PRIVATE_NUM_MPIS][256]; - size_t src_size, dest_size, i; + uint8_t dest[4096]; + size_t src_size, dest_size; CK_RV res; - /* We took a few shortcuts... validate them now. Note that these are NOT - guaranteed by the API. */ - assert ((size_t)NCR_RSA_PUBLIC_NUM_MPIS <= (size_t)NCR_RSA_PRIVATE_NUM_MPIS); - assert ((size_t)NCR_RSA_PUBLIC_MPI_MODULUS - == (size_t)NCR_RSA_PRIVATE_MPI_MODULUS); - assert ((size_t)NCR_RSA_PUBLIC_MPI_PUBLIC_EXPONENT - == (size_t)NCR_RSA_PRIVATE_MPI_PUBLIC_EXPONENT); - - - /* Test key loading. Should we test the generic version as well? */ - res = ncr_public_key_create_rsa (&public, import_mpis); - assert (res == CKR_OK); - res = ncr_private_key_create_rsa (&private, false, import_mpis); - assert (res == CKR_OK); - - /* Test encryption */ dest_size = sizeof (dest); res = ncr_public_key_encrypt (CKM_RSA_PKCS, public, dest, &dest_size, input, @@ -117,7 +98,36 @@ main (void) res = ncr_public_key_verify (CKM_RSA_PKCS, public, dest, dest_size, input, sizeof (input)); assert (res != CKR_OK); +} + +int +main (void) +{ + struct ncr_public_key *public; + struct ncr_private_key *private; + struct ncr_mpi dest_mpis[NCR_RSA_PRIVATE_NUM_MPIS]; + uint8_t mpi_dest[NCR_RSA_PRIVATE_NUM_MPIS][256]; + size_t i; + CK_RV res; + + /* We took a few shortcuts... validate them now. Note that these are NOT + guaranteed by the API. */ + assert ((size_t)NCR_RSA_PUBLIC_NUM_MPIS <= (size_t)NCR_RSA_PRIVATE_NUM_MPIS); + assert ((size_t)NCR_RSA_PUBLIC_MPI_MODULUS + == (size_t)NCR_RSA_PRIVATE_MPI_MODULUS); + assert ((size_t)NCR_RSA_PUBLIC_MPI_PUBLIC_EXPONENT + == (size_t)NCR_RSA_PRIVATE_MPI_PUBLIC_EXPONENT); + + + /* Test key loading. Should we test the generic version as well? */ + res = ncr_public_key_create_rsa (&public, import_mpis); + assert (res == CKR_OK); + res = ncr_private_key_create_rsa (&private, false, import_mpis); + assert (res == CKR_OK); + test_key_pair (public, private); + + /* Test key export. */ for (i = 0; i < NCR_RSA_PUBLIC_NUM_MPIS; i++) { dest_mpis[i].data = mpi_dest[i]; @@ -142,6 +152,37 @@ main (void) res = ncr_public_key_destroy (public); assert (res == CKR_OK); + + /* Test key generation. */ + res = ncr_key_pair_generate_rsa (&public, &private, CKM_RSA_PKCS_KEY_PAIR_GEN, + false, 1024, NULL); + assert (res == CKR_OK); + + test_key_pair (public, private); + + /* Test key export - only test that it succeeds. */ + for (i = 0; i < NCR_RSA_PUBLIC_NUM_MPIS; i++) + { + dest_mpis[i].data = mpi_dest[i]; + dest_mpis[i].size = sizeof (mpi_dest[i]); + } + res = ncr_public_key_export_rsa (public, dest_mpis); + assert (res == CKR_OK); + + for (i = 0; i < NCR_RSA_PRIVATE_NUM_MPIS; i++) + { + dest_mpis[i].data = mpi_dest[i]; + dest_mpis[i].size = sizeof (mpi_dest[i]); + } + res = ncr_private_key_export_rsa (private, dest_mpis); + assert (res == CKR_OK); + + res = ncr_private_key_destroy (private); + assert (res == CKR_OK); + + res = ncr_public_key_destroy (public); + assert (res == CKR_OK); + /* Test reference counting */ res = ncr_open (); assert (res == CKR_OK); -- cgit From 233b3d9dbc1e756d09be2c6901a341588020fa49 Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Mon, 29 Nov 2010 17:00:14 +0100 Subject: Add private key sensitivity test --- Makefile.am | 7 ++- tests/private_keys.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 tests/private_keys.c diff --git a/Makefile.am b/Makefile.am index 0e6c301..7019a5f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -35,8 +35,8 @@ AM_CPPFLAGS = -I $(top_srcdir)/include $(GLIB_CFLAGS) $(NSS_CFLAGS) \ ## Targets lib_LTLIBRARIES = lib/libncrypto.la pkginclude_HEADERS = include/ncrypto/ncrypto.h -TESTS = tests/digests tests/rsa tests/symm_ciphers tests/symm_keys \ - tests/symm_signatures +TESTS = tests/digests tests/private_keys tests/rsa \ + tests/symm_ciphers tests/symm_keys tests/symm_signatures ## Rules noinst_PROGRAMS = $(TESTS) @@ -48,6 +48,9 @@ lib_libncrypto_la_LDFLAGS = -version-info 0:0:0 $(NSS_LIBS) $(OPENSSL_LIBS) tests_digests_LDADD = lib/libncrypto.la $(GLIB_LIBS) tests_digests_LDFLAGS = -no-install +tests_private_keys_LDADD = lib/libncrypto.la $(GLIB_LIBS) +tests_private_keys_LDFLAGS = -no-install + tests_rsa_LDADD = lib/libncrypto.la $(GLIB_LIBS) tests_rsa_LDFLAGS = -no-install diff --git a/tests/private_keys.c b/tests/private_keys.c new file mode 100644 index 0000000..083d37f --- /dev/null +++ b/tests/private_keys.c @@ -0,0 +1,162 @@ +/* ncr_private_key_* tests. + +Copyright 2010 Red Hat, Inc. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +Red Hat author: Miloslav Trmač */ + +#include +#include +#include +#include +#include + +#include +#include + +static const struct ncr_mpi import_mpis[NCR_RSA_PRIVATE_NUM_MPIS] = + { +#define INT(NAME, VAL) \ + [NCR_RSA_PRIVATE_MPI_##NAME] = { (void *)(VAL), sizeof (VAL) - 1 } + + INT (MODULUS, + "\xB8\xC7\x54\x15\x90\xCF\x91\x7A\xF3\x4C\x45\x53\xC2\x0A\xDA\x84\x4C\x09\x48\x10\x06\x41\xC5\x97\x57\x02\xDA\x0E\x7E\x64\x46\xBD\xC6\x75\x42\xCD\x32\x23\x0C\xEC\x2B\x1C\x60\x03\x68\x1E\x4F\x28\x78\xD8\xB0\xC1\xAC\xA7\x21\xE4\x15\x74\x65\x16\x1C\x59\xC8\x85"), + INT (PUBLIC_EXPONENT, "\x01\x00\x01"), + INT (PRIVATE_EXPONENT, "\x7B\xD6\xC3\xC8\xEC\x53\xE1\x09\xC9\x13\xDE\x06\xE3\xAE\xC8\x83\x10\x3E\xCC\x38\x49\x29\x3D\x97\x4F\x6E\x8E\xDC\x55\xE3\x38\xF1\x03\xEB\xC1\x09\x80\x16\xB8\x9F\xE1\xC0\x21\x77\xD4\xEE\xF7\x30\xD1\x85\x2B\x1F\x4F\xFE\xD1\x01\xCD\x35\x78\x4A\x97\x6F\x38\x65"), + INT (PRIME_1, "\xF5\x7E\xFA\xED\xE0\xEC\x9C\x4E\x6F\xDF\xED\x64\x58\xEC\x18\xA9\x8E\x60\x2E\x49\x7E\xDF\x8E\xCF\x9F\xA5\x4A\x32\xA3\x27\x7E\x1B"), + INT (PRIME_2, "\xC0\xAF\x49\x15\x49\x8D\x88\xFB\x28\x7D\x33\x25\x07\x37\xE0\x99\x2C\xA8\x6D\x46\x4F\x7D\x7D\x6E\x01\x95\x6B\x2B\x18\x1B\xBD\xDF"), + INT (EXPONENT_1, "\xC3\x34\x0F\xB4\xBC\x87\x87\x95\xFA\xF1\x14\x63\x19\x2D\xCA\x42\x70\x5A\x5C\x13\xC6\x95\x5E\x8A\x0B\x08\x34\x22\x65\x87\x0E\x87"), + INT (EXPONENT_2, "\x27\x3B\x89\x85\xEC\x14\x05\x70\x1E\x2E\x5F\xDB\x8A\x3C\xB6\x5E\x79\xD9\x51\x66\x9F\x88\xCD\xA1\x38\x71\x54\x00\xD2\x47\xD3\xC1"), + INT (COEFFICIENT, "\x39\x09\x3A\x43\xCF\xE3\x65\x63\x2F\x5F\x11\xED\x2C\x42\x88\xEF\xCA\x26\x1E\x08\x96\xCF\x0A\x8F\xCB\x88\x45\x50\xEF\x6A\x38\x07") +#undef INT + }; + +static void +log_silent (const gchar *log_domain, GLogLevelFlags log_level, + const gchar *message, gpointer user_data) +{ + (void)log_domain; + (void)log_level; + (void)message; + (void)user_data; +} + +static void +check_set_sentitive_failure (struct ncr_private_key *key) +{ + uint8_t dest[4096]; + size_t dest_size; + CK_RV res; + + /* Extraction of a sensitive value is a programming error, so we complain to + stderr. Hide this in the test output. */ + + g_log_set_default_handler (log_silent, NULL); + + dest_size = sizeof (dest); + res = ncr_private_key_export (key, dest, &dest_size); + assert (res == CKR_ATTRIBUTE_SENSITIVE); + + g_log_set_default_handler (g_log_default_handler, NULL); +} + +int +main (void) +{ + uint8_t dest[4096]; + size_t dest_size; + struct ncr_public_key *public; + struct ncr_private_key *key; + CK_RV res; + + /* Test handling of loaded, non-sensitive keys. */ + res = ncr_private_key_create_rsa (&key, false, import_mpis); + assert (res == CKR_OK); + + dest_size = sizeof (dest); + res = ncr_private_key_export (key, dest, &dest_size); + assert (res == CKR_OK); + + res = ncr_private_key_set_sensitive (key); + assert (res == CKR_OK); + + res = ncr_private_key_set_sensitive (key); + assert (res == CKR_OK); + + check_set_sentitive_failure (key); + + res = ncr_private_key_destroy (key); + assert (res == CKR_OK); + + + /* Test handling of loaded, sensitive keys. */ + res = ncr_private_key_create_rsa (&key, true, import_mpis); + assert (res == CKR_OK); + + check_set_sentitive_failure (key); + + res = ncr_private_key_destroy (key); + assert (res == CKR_OK); + + + /* Test handling of generated, non-sensitive keys. */ + res = ncr_key_pair_generate_rsa (&public, &key, CKM_RSA_PKCS_KEY_PAIR_GEN, + false, 1024, NULL); + assert (res == CKR_OK); + res = ncr_public_key_destroy (public); + assert (res == CKR_OK); + + dest_size = sizeof (dest); + res = ncr_private_key_export (key, dest, &dest_size); + assert (res == CKR_OK); + + res = ncr_private_key_set_sensitive (key); + assert (res == CKR_OK); + + res = ncr_private_key_set_sensitive (key); + assert (res == CKR_OK); + + check_set_sentitive_failure (key); + + res = ncr_private_key_destroy (key); + assert (res == CKR_OK); + + + /* Test handling of generated, sensitive keys. */ + res = ncr_key_pair_generate_rsa (&public, &key, CKM_RSA_PKCS_KEY_PAIR_GEN, + true, 1024, NULL); + assert (res == CKR_OK); + res = ncr_public_key_destroy (public); + assert (res == CKR_OK); + + check_set_sentitive_failure (key); + + res = ncr_private_key_destroy (key); + assert (res == CKR_OK); + + /* Close the implicit reference, primarily to shut up valgrind. */ + res = ncr_close (); + assert (res == CKR_OK); + + return EXIT_SUCCESS; +} -- cgit From cd4794e966303075633d6ac28e98279282734fd7 Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Mon, 29 Nov 2010 17:12:42 +0100 Subject: Make private key sensitivity visible to NSS --- lib/ncrypto_nss.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index 818091d..4737fc2 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -407,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); @@ -580,13 +580,25 @@ ncr_private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type, 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; } @@ -679,10 +691,8 @@ key_pair_generate (struct ncr_public_key **public_key, if (slot == NULL) goto err_priv; - /* FIXME: propagate "sensitive" here? */ priv->key = PK11_GenerateKeyPair(slot, mech, params, &pub->key, - PR_FALSE /* isPerm */, - PR_FALSE /* sensitive */, NULL); + PR_FALSE /* isPerm */, sensitive, NULL); PK11_FreeSlot (slot); if (priv->key == NULL) goto err_priv; -- cgit