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