summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiloslav Trmač <mitr@redhat.com>2010-11-30 22:05:18 +0100
committerMiloslav Trmač <mitr@redhat.com>2010-11-30 22:05:18 +0100
commit24c1c8a9e044cc7fe1c5c9343c0cdaaf57da9aa6 (patch)
treee57d3d908692475e7bc327d1bdedfffc5d657e2d
parent642c97ec86ff47d83f2492e3969b05ef1cb86f03 (diff)
parenta2dd3a2b9045b5a787e0981bef2f378ab148ac1f (diff)
downloadncrypto-24c1c8a9e044cc7fe1c5c9343c0cdaaf57da9aa6.tar.gz
ncrypto-24c1c8a9e044cc7fe1c5c9343c0cdaaf57da9aa6.tar.xz
ncrypto-24c1c8a9e044cc7fe1c5c9343c0cdaaf57da9aa6.zip
Merge branch 'local'
-rw-r--r--Makefile.am5
-rw-r--r--include/ncrypto/ncrypto.h55
-rw-r--r--lib/ncrypto_nss.c736
-rw-r--r--tests/dsa.c195
4 files changed, 796 insertions, 195 deletions
diff --git a/Makefile.am b/Makefile.am
index fd2eaf2..0d1c6aa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,7 +35,7 @@ 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/private_keys tests/rsa \
+TESTS = tests/digests tests/dsa tests/private_keys tests/rsa \
tests/symm_ciphers tests/symm_keys tests/symm_signatures
## Rules
@@ -45,6 +45,9 @@ lib_libncrypto_la_SOURCES = lib/internal.h lib/ncrypto.c lib/ncrypto_alg.c \
lib/ncrypto_local.c lib/ncrypto_nss.c
lib_libncrypto_la_LDFLAGS = -version-info 0:0:0 $(NSS_LIBS) $(OPENSSL_LIBS)
+tests_dsa_LDADD = lib/libncrypto.la $(GLIB_LIBS)
+tests_dsa_LDFLAGS = -no-install
+
tests_digests_LDADD = lib/libncrypto.la $(GLIB_LIBS)
tests_digests_LDFLAGS = -no-install
diff --git a/include/ncrypto/ncrypto.h b/include/ncrypto/ncrypto.h
index d9508bf..ff20d8c 100644
--- a/include/ncrypto/ncrypto.h
+++ b/include/ncrypto/ncrypto.h
@@ -71,12 +71,14 @@ CK_RV ncr_symm_key_destroy (struct ncr_symm_key *key);
struct ncr_public_key;
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);
+/* The X.509v3 subjectPublicKeyInfo structure is used for public keys. */
+CK_RV ncr_public_key_create (struct ncr_public_key **key, 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. */
+/* The PKCS#8 privateKeyInfo structure is used for private keys. "Sensitive"
+ corresponds to CKA_SENSITIVE. */
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,
@@ -136,6 +138,53 @@ CK_RV ncr_key_pair_generate_rsa (struct ncr_public_key **public_key,
CK_ULONG modulus_bits,
const struct ncr_mpi *public_exponent);
+ /* DSA keys */
+
+enum
+ {
+ NCR_DSA_PUBLIC_MPI_PRIME,
+ NCR_DSA_PUBLIC_MPI_SUBPRIME,
+ NCR_DSA_PUBLIC_MPI_BASE,
+ NCR_DSA_PUBLIC_MPI_VALUE,
+ NCR_DSA_PUBLIC_NUM_MPIS
+ };
+
+enum
+ {
+ NCR_DSA_PRIVATE_MPI_PRIME,
+ NCR_DSA_PRIVATE_MPI_SUBPRIME,
+ NCR_DSA_PRIVATE_MPI_BASE,
+ NCR_DSA_PRIVATE_MPI_VALUE,
+ NCR_DSA_PRIVATE_NUM_MPIS
+ };
+
+enum
+ {
+ NCR_DSA_GEN_MPI_PRIME,
+ NCR_DSA_GEN_MPI_SUBPRIME,
+ NCR_DSA_GEN_MPI_BASE,
+ NCR_DSA_GEN_NUM_MPIS
+ };
+
+CK_RV ncr_public_key_create_dsa (struct ncr_public_key **key,
+ const struct ncr_mpi
+ mpis[static NCR_DSA_PUBLIC_NUM_MPIS]);
+CK_RV ncr_public_key_export_dsa (struct ncr_public_key *key,
+ struct ncr_mpi
+ mpis [static NCR_DSA_PUBLIC_NUM_MPIS]);
+CK_RV ncr_private_key_create_dsa (struct ncr_private_key **key, _Bool sensitive,
+ const struct ncr_mpi
+ mpis[static NCR_DSA_PRIVATE_NUM_MPIS],
+ const struct ncr_mpi *public_value);
+CK_RV ncr_private_key_export_dsa (struct ncr_private_key *key,
+ struct ncr_mpi
+ mpis[static NCR_DSA_PRIVATE_NUM_MPIS]);
+CK_RV ncr_key_pair_generate_dsa (struct ncr_public_key **public_key,
+ struct ncr_private_key **private_key,
+ CK_MECHANISM_TYPE mech, _Bool sensitive,
+ const struct ncr_mpi
+ mpis[static NCR_DSA_GEN_NUM_MPIS]);
+
/* Asymmetric operations */
CK_RV ncr_public_key_encrypt (CK_MECHANISM_TYPE mech,
diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c
index 4737fc2..a430c3f 100644
--- a/lib/ncrypto_nss.c
+++ b/lib/ncrypto_nss.c
@@ -151,8 +151,7 @@ static const SEC_ASN1Template private_key_info_asn1_template[] =
};
static CK_RV
-public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type,
- const SECItem *der_key)
+public_key_create (struct ncr_public_key **key, CERTSubjectPublicKeyInfo *spki)
{
struct ncr_public_key *k;
@@ -160,7 +159,7 @@ public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type,
if (k == NULL)
return CKR_HOST_MEMORY;
- k->key = SECKEY_ImportDERPublicKey((SECItem *)der_key, type);
+ k->key = SECKEY_ExtractPublicKey (spki);
if (k->key == NULL)
{
free (k);
@@ -171,62 +170,13 @@ 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)
+ncr_public_key_create (struct ncr_public_key **key, const void *der,
+ size_t der_size)
{
- CK_RV res;
+ CERTSubjectPublicKeyInfo *spki;
SECItem der_key;
+ CK_RV res;
res = ensure_ncr_is_open ();
if (res != CKR_OK)
@@ -237,56 +187,53 @@ ncr_public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type,
der_key.data = (void *)der;
der_key.len = der_size;
- return public_key_create (key, type, &der_key);
+ spki = SECKEY_DecodeDERSubjectPublicKeyInfo (&der_key);
+ if (spki == NULL)
+ return CKR_GENERAL_ERROR;
+
+ res = public_key_create (key, spki);
+
+ SECKEY_DestroySubjectPublicKeyInfo (spki);
+ 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;
+ SECItem *der;
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);
- /* 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 = SECKEY_EncodeDERSubjectPublicKeyInfo (key->key);
+ if (der == NULL)
+ return CKR_GENERAL_ERROR;
if (dest == NULL)
{
- *dest_size_ptr = der_key_size;
+ *dest_size_ptr = der->len;
res = CKR_OK;
- goto end_der_spki;
+ goto end_der;
}
- if (*dest_size_ptr < der_key_size)
+ if (*dest_size_ptr < der->len)
{
- *dest_size_ptr = der_key_size;
+ *dest_size_ptr = der->len;
res = CKR_BUFFER_TOO_SMALL;
- goto end_der_spki;
+ goto end_der;
}
- *dest_size_ptr = der_key_size;
+ *dest_size_ptr = der->len;
- memcpy (dest, der_key, der_key_size);
+ memcpy (dest, der->data, der->len);
res = CKR_OK;
- end_der_spki:
- SECITEM_FreeItem (der_spki, PR_TRUE);
- end_arena:
- PORT_FreeArena (arena, PR_FALSE);
+ end_der:
+ SECITEM_FreeItem (der, PR_TRUE);
return res;
}
@@ -307,67 +254,30 @@ ncr_public_key_destroy (struct ncr_public_key *key)
return CKR_OK;
}
+/* Create a private key based on a PKCS#8 privateKeyInfo DER_PKI. */
static CK_RV
private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
- bool sensitive, const SECItem *der_key,
+ bool sensitive, const SECItem *der_pki,
const SECItem *public_value)
{
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 private_key_info der_input;
PK11SlotInfo *slot;
- SECItem der_info, *der_res, key_item, iv_item, wrapped_item;
- SECOidTag alg_tag;
+ SECItem key_item, iv_item, wrapped_item;
SECStatus ss;
PK11SymKey *wrapping_key;
PK11Context *ctx;
int wrapped_len;
- switch (type)
- {
- case CKK_RSA:
- alg_tag = SEC_OID_PKCS1_RSA_ENCRYPTION;
- break;
-
- default:
- g_return_val_if_reached (CKR_ARGUMENTS_BAD);
- }
-
k = malloc (sizeof (*k));
if (k == NULL)
return CKR_HOST_MEMORY;
- 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)
- {
- free (k);
- return CKR_GENERAL_ERROR;
- }
- der_input.private_key = *der_key;
-
- der_info.data = NULL;
- der_info.len = 0;
- der_res = SEC_ASN1EncodeItem (NULL, &der_info, &der_input,
- private_key_info_asn1_template);
-
- SECOID_DestroyAlgorithmID (&der_input.algorithm, PR_FALSE);
-
- if (der_res == NULL)
- {
- free (k);
- return CKR_HOST_MEMORY;
- }
-
slot = PK11_GetBestSlot (CKM_AES_CBC_PAD, NULL);
if (slot == NULL)
- goto err_der_info;
+ return CKR_GENERAL_ERROR;
key_item.data = (void *)wrap_key;
key_item.len = sizeof (wrap_key);
@@ -386,13 +296,13 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
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)
+ if (SECITEM_AllocItem (NULL, &wrapped_item, der_pki->len + 16) == NULL)
{
PK11_DestroyContext (ctx, PR_TRUE);
goto err_wrapping_key;
}
if (PK11_CipherOp (ctx, wrapped_item.data, &wrapped_len, wrapped_item.len,
- der_info.data, der_info.len) != SECSuccess)
+ der_pki->data, der_pki->len) != SECSuccess)
{
PK11_DestroyContext (ctx, PR_TRUE);
goto err_wrapped_item;
@@ -412,7 +322,6 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
SECITEM_ZfreeItem (&wrapped_item, PR_FALSE);
PK11_FreeSymKey (wrapping_key);
PK11_FreeSlot (slot);
- PORT_Free (der_info.data);
if (k->key == NULL)
goto err_k;
@@ -427,16 +336,47 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
PK11_FreeSymKey (wrapping_key);
err_slot:
PK11_FreeSlot (slot);
- err_der_info:
- PORT_Free (der_info.data);
err_k:
free (k);
return CKR_GENERAL_ERROR;
}
+/* Create a private key based on INPUT_PKI.
+ PKI->version is ignored. */
+static CK_RV
+private_key_create_components (struct ncr_private_key **key, CK_KEY_TYPE type,
+ bool sensitive,
+ const struct private_key_info *input_pki,
+ const SECItem *public_value)
+{
+ static const uint8_t zero; /* = 0; */
+
+ struct private_key_info pki;
+ SECItem der_pki;
+ CK_RV res;
+
+ pki.version.type = siUnsignedInteger;
+ pki.version.data = (void *)&zero;
+ pki.version.len = sizeof (zero);
+ pki.algorithm = input_pki->algorithm;
+ pki.private_key = input_pki->private_key;
+
+ der_pki.data = NULL;
+ der_pki.len = 0;
+ if (SEC_ASN1EncodeItem (NULL, &der_pki, &pki, private_key_info_asn1_template)
+ == NULL)
+ return CKR_HOST_MEMORY;
+
+ res = private_key_create (key, type, sensitive, &der_pki, public_value);
+
+ SECITEM_ZfreeItem (&der_pki, PR_FALSE);
+ return res;
+}
+
+/* Set DER_PKI to a PKCS#8 privateKeyInfo describing KEY. */
static CK_RV
private_key_export (struct ncr_private_key *key, PRArenaPool *arena,
- SECItem *der_key)
+ SECItem *der_pki)
{
static const uint8_t wrap_key[32]; /* = { 0, }; */
static const uint8_t wrap_iv[16]; /* = { 0, }; */
@@ -446,7 +386,6 @@ private_key_export (struct ncr_private_key *key, PRArenaPool *arena,
PK11SymKey *wrapping_key;
PK11Context *ctx;
int der_info_len;
- struct private_key_info der_output;
SECStatus ss;
CK_RV res;
@@ -524,25 +463,8 @@ private_key_export (struct ncr_private_key *key, PRArenaPool *arena,
}
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;
+ *der_pki = der_info;
+ res = CKR_OK;
err_wrapped_item:
SECITEM_ZfreeItem (&wrapped_item, PR_FALSE);
@@ -553,6 +475,30 @@ private_key_export (struct ncr_private_key *key, PRArenaPool *arena,
return res;
}
+/* Fill PKI with info from KEY. */
+static CK_RV
+private_key_export_components (struct ncr_private_key *key, PRArenaPool *arena,
+ struct private_key_info *pki)
+{
+ SECItem der_pki;
+ CK_RV res;
+
+ res = private_key_export (key, arena, &der_pki);
+ if (res != CKR_OK)
+ return res;
+
+ /* "type" is accessed by the decoder for ASN1_INTEGER */
+ pki->version.type = siUnsignedInteger;
+ if (SEC_QuickDERDecodeItem (arena, pki, private_key_info_asn1_template,
+ &der_pki) != SECSuccess)
+ return CKR_GENERAL_ERROR;
+
+ if (pki->version.len != 1 || pki->version.data[0] != 0)
+ return CKR_GENERAL_ERROR;
+
+ return CKR_OK;
+}
+
/* 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,
@@ -608,7 +554,7 @@ ncr_private_key_export (struct ncr_private_key *key, void *dest,
size_t *dest_size_ptr)
{
PRArenaPool *arena;
- SECItem der_key;
+ SECItem der_pki;
CK_RV res;
res = ensure_ncr_is_open ();
@@ -623,25 +569,25 @@ ncr_private_key_export (struct ncr_private_key *key, void *dest,
if (arena == NULL)
return CKR_HOST_MEMORY;
- res = private_key_export (key, arena, &der_key);
+ res = private_key_export (key, arena, &der_pki);
if (res != CKR_OK)
goto end;
if (dest == NULL)
{
- *dest_size_ptr = der_key.len;
+ *dest_size_ptr = der_pki.len;
res = CKR_OK;
goto end;
}
- if (*dest_size_ptr < der_key.len)
+ if (*dest_size_ptr < der_pki.len)
{
- *dest_size_ptr = der_key.len;
+ *dest_size_ptr = der_pki.len;
res = CKR_BUFFER_TOO_SMALL;
goto end;
}
- *dest_size_ptr = der_key.len;
+ *dest_size_ptr = der_pki.len;
- memcpy (dest, der_key.data, der_key.len);
+ memcpy (dest, der_pki.data, der_pki.len);
res = CKR_OK;
end:
@@ -815,13 +761,29 @@ static const SEC_ASN1Template rsa_private_key_asn1_template[] =
{ 0, 0, NULL, 0 }
};
+static CK_RV
+rsa_validate_algorithm_id (const SECAlgorithmID *id)
+{
+ static const uint8_t asn1_null[] = { SEC_ASN1_NULL, 0 };
+ static const SECItem asn1_null_item
+ = { 0, (void *)&asn1_null, sizeof (asn1_null) };
+
+ const SECOidData *oid;
+
+ oid = SECOID_FindOIDByTag (SEC_OID_PKCS1_RSA_ENCRYPTION);
+ if (oid == NULL || !SECITEM_ItemsAreEqual(&id->algorithm, &oid->oid)
+ || !SECITEM_ItemsAreEqual(&id->parameters, &asn1_null_item))
+ return CKR_GENERAL_ERROR;
+ return CKR_OK;
+}
+
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;
+ CERTSubjectPublicKeyInfo spki;
CK_RV res;
res = ensure_ncr_is_open ();
@@ -833,14 +795,33 @@ ncr_public_key_create_rsa (struct ncr_public_key **key,
if (res != CKR_OK)
return res;
- der_key.data = NULL;
- der_key.len = 0;
- if (SEC_ASN1EncodeItem(NULL, &der_key, &der_input,
- rsa_public_key_asn1_template) == NULL)
+ spki.subjectPublicKey.data = NULL;
+ spki.subjectPublicKey.len = 0;
+ if (SEC_ASN1EncodeItem (NULL, &spki.subjectPublicKey, &der_input,
+ rsa_public_key_asn1_template) == NULL)
return CKR_HOST_MEMORY;
+ /* spki->subjectPublicKey is encoded as BIT_STRING, so "len" needs to be a
+ number of _bits_. */
+ if (spki.subjectPublicKey.len > UINT_MAX / 8)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end_subjectPublicKey;
+ }
+ spki.subjectPublicKey.len *= 8;
+
+ memset (&spki.algorithm, 0, sizeof (spki.algorithm));
+ if (SECOID_SetAlgorithmID (NULL, &spki.algorithm,
+ SEC_OID_PKCS1_RSA_ENCRYPTION, NULL) != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end_subjectPublicKey;
+ }
- res = public_key_create (key, CKK_RSA, &der_key);
- PORT_Free (der_key.data);
+ res = public_key_create (key, &spki);
+
+ SECOID_DestroyAlgorithmID (&spki.algorithm, PR_FALSE);
+ end_subjectPublicKey:
+ PORT_Free (spki.subjectPublicKey.data);
return res;
}
@@ -850,10 +831,9 @@ 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;
+ CERTSubjectPublicKeyInfo *spki;
PRArenaPool *arena;
- SECItem *der_spki, der_key_item;
- void *der_key;
- size_t der_key_size;
+ SECItem key_item;
CK_RV res;
size_t i;
@@ -861,42 +841,48 @@ ncr_public_key_export_rsa (struct ncr_public_key *key,
if (res != CKR_OK)
return res;
+ g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD);
g_return_val_if_fail (mpis != NULL, CKR_ARGUMENTS_BAD);
+ spki = SECKEY_CreateSubjectPublicKeyInfo(key->key);
+ if (spki == NULL)
+ return CKR_GENERAL_ERROR;
+
+ res = rsa_validate_algorithm_id (&spki->algorithm);
+ if (res != CKR_OK)
+ goto end_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)
- 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_der_spki;
+ res = CKR_HOST_MEMORY;
+ goto end_spki;
}
+
+ /* spki->subjectPublicKey is encoded as BIT_STRING, so "len" is a number of
+ _bits_. */
+ key_item.data = spki->subjectPublicKey.data;
+ key_item.len = (spki->subjectPublicKey.len / 8
+ + (spki->subjectPublicKey.len % 8 != 0));
/* 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)
+ &key_item) != SECSuccess)
{
res = CKR_GENERAL_ERROR;
- goto end_der_spki;
+ goto end_arena;
}
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);
+ end_spki:
+ SECKEY_DestroySubjectPublicKeyInfo (spki);
return res;
}
@@ -908,7 +894,7 @@ ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive,
static const uint8_t zero; /* = 0; */
struct rsa_private_key der_input;
- SECItem der_key;
+ struct private_key_info pki;
CK_RV res;
res = ensure_ncr_is_open ();
@@ -920,19 +906,30 @@ ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive,
if (res != CKR_OK)
return res;
+ memset (&pki.algorithm, 0, sizeof (pki.algorithm));
+ if (SECOID_SetAlgorithmID (NULL, &pki.algorithm, SEC_OID_PKCS1_RSA_ENCRYPTION,
+ NULL) != SECSuccess)
+ return CKR_GENERAL_ERROR;
+
der_input.version.type = siUnsignedInteger;
der_input.version.data = (void *)&zero;
der_input.version.len = sizeof (zero);
- der_key.data = NULL;
- der_key.len = 0;
- if (SEC_ASN1EncodeItem (NULL, &der_key, &der_input,
+ pki.private_key.data = NULL;
+ pki.private_key.len = 0;
+ if (SEC_ASN1EncodeItem (NULL, &pki.private_key, &der_input,
rsa_private_key_asn1_template) == NULL)
- return CKR_HOST_MEMORY;
+ {
+ res = CKR_HOST_MEMORY;
+ goto end_algorithm;
+ }
- res = private_key_create (key, CKK_RSA, sensitive, &der_key,
- &der_input.items[NCR_RSA_PRIVATE_MPI_MODULUS]);
- PORT_Free (der_key.data);
+ res = private_key_create_components
+ (key, CKK_RSA, sensitive, &pki,
+ &der_input.items[NCR_RSA_PRIVATE_MPI_MODULUS]);
+ SECITEM_ZfreeItem (&pki.private_key, PR_FALSE);
+ end_algorithm:
+ SECOID_DestroyAlgorithmID (&pki.algorithm, PR_FALSE);
return res;
}
@@ -941,9 +938,9 @@ ncr_private_key_export_rsa (struct ncr_private_key *key,
struct ncr_mpi
mpis[static NCR_RSA_PRIVATE_NUM_MPIS])
{
+ struct private_key_info pki;
struct rsa_private_key der_output;
PRArenaPool *arena;
- SECItem der_key;
CK_RV res;
size_t i;
@@ -959,7 +956,11 @@ ncr_private_key_export_rsa (struct ncr_private_key *key,
if (arena == NULL)
return CKR_HOST_MEMORY;
- res = private_key_export (key, arena, &der_key);
+ res = private_key_export_components (key, arena, &pki);
+ if (res != CKR_OK)
+ goto end;
+
+ res = rsa_validate_algorithm_id (&pki.algorithm);
if (res != CKR_OK)
goto end;
@@ -968,7 +969,13 @@ ncr_private_key_export_rsa (struct ncr_private_key *key,
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)
+ &pki.private_key) != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end;
+ }
+
+ if (der_output.version.len != 1 || der_output.version.data[0] != 0)
{
res = CKR_GENERAL_ERROR;
goto end;
@@ -1034,6 +1041,353 @@ ncr_key_pair_generate_rsa (struct ncr_public_key **public_key,
return key_pair_generate (public_key, private_key, mech, sensitive, &params);
}
+ /* DSA keys */
+
+/* Contains both the "key" and domain parameters */
+struct dsa_public_values
+{
+ SECItem items[NCR_DSA_PUBLIC_NUM_MPIS];
+};
+
+static const SEC_ASN1Template dsa_public_values_params_asn1_template[] =
+ {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct dsa_public_values) },
+#define INT(X) \
+ { \
+ SEC_ASN1_INTEGER, \
+ offsetof (struct dsa_public_values, items) + (X) * sizeof (SECItem), \
+ NULL, 0 \
+ }
+
+ INT (NCR_DSA_PUBLIC_MPI_PRIME), INT (NCR_DSA_PUBLIC_MPI_SUBPRIME),
+ INT (NCR_DSA_PUBLIC_MPI_BASE),
+#undef INT
+ { 0, 0, NULL, 0 }
+ };
+
+static const SEC_ASN1Template dsa_public_values_key_asn1_template[] =
+ {
+ {
+ SEC_ASN1_INTEGER,
+ offsetof (struct dsa_public_values, items)
+ + NCR_DSA_PUBLIC_MPI_VALUE * sizeof (SECItem), NULL, 0
+ }
+ };
+
+/* Contains both the "key" and domain parameters */
+struct dsa_private_values
+{
+ SECItem items[NCR_DSA_PRIVATE_NUM_MPIS];
+};
+
+static const SEC_ASN1Template dsa_private_values_params_asn1_template[] =
+ {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct dsa_private_values) },
+#define INT(X) \
+ { \
+ SEC_ASN1_INTEGER, \
+ offsetof (struct dsa_private_values, items) + (X) * sizeof (SECItem), \
+ NULL, 0 \
+ }
+
+ INT (NCR_DSA_PRIVATE_MPI_PRIME), INT (NCR_DSA_PRIVATE_MPI_SUBPRIME),
+ INT (NCR_DSA_PRIVATE_MPI_BASE),
+#undef INT
+ { 0, 0, NULL, 0 }
+ };
+
+static const SEC_ASN1Template dsa_private_values_key_asn1_template[] =
+ {
+ {
+ SEC_ASN1_INTEGER,
+ offsetof (struct dsa_private_values, items)
+ + NCR_DSA_PRIVATE_MPI_VALUE * sizeof (SECItem), NULL, 0
+ }
+ };
+
+static CK_RV
+dsa_validate_algorithm_id (const SECAlgorithmID *id)
+{
+ const SECOidData *oid;
+
+ oid = SECOID_FindOIDByTag (SEC_OID_ANSIX9_DSA_SIGNATURE);
+ if (oid == NULL || !SECITEM_ItemsAreEqual(&id->algorithm, &oid->oid))
+ return CKR_GENERAL_ERROR;
+ return CKR_OK;
+}
+
+CK_RV
+ncr_public_key_create_dsa (struct ncr_public_key **key,
+ const struct ncr_mpi
+ mpis[static NCR_DSA_PUBLIC_NUM_MPIS])
+{
+ struct dsa_public_values der_input;
+ CERTSubjectPublicKeyInfo spki;
+ SECItem params;
+ SECStatus ss;
+ CK_RV res;
+
+ res = ensure_ncr_is_open ();
+ if (res != CKR_OK)
+ return res;
+
+ res = mpi_create_SECItems_for_encoding (der_input.items, mpis,
+ NCR_DSA_PUBLIC_NUM_MPIS);
+ if (res != CKR_OK)
+ return res;
+
+ spki.subjectPublicKey.data = NULL;
+ spki.subjectPublicKey.len = 0;
+ if (SEC_ASN1EncodeItem (NULL, &spki.subjectPublicKey, &der_input,
+ dsa_public_values_key_asn1_template) == NULL)
+ return CKR_HOST_MEMORY;
+ /* spki->subjectPublicKey is encoded as BIT_STRING, so "len" needs to be a
+ number of _bits_. */
+ if (spki.subjectPublicKey.len > UINT_MAX / 8)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end_subjectPublicKey;
+ }
+ spki.subjectPublicKey.len *= 8;
+
+ params.data = NULL;
+ params.len = 0;
+ if (SEC_ASN1EncodeItem (NULL, &params, &der_input,
+ dsa_public_values_params_asn1_template) == NULL)
+ {
+ res = CKR_HOST_MEMORY;
+ goto end_subjectPublicKey;
+ }
+ memset (&spki.algorithm, 0, sizeof (spki.algorithm));
+ ss = SECOID_SetAlgorithmID (NULL, &spki.algorithm,
+ SEC_OID_ANSIX9_DSA_SIGNATURE, &params);
+ PORT_Free (params.data);
+ if (ss != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end_subjectPublicKey;
+ }
+
+ res = public_key_create (key, &spki);
+
+ SECOID_DestroyAlgorithmID (&spki.algorithm, PR_FALSE);
+ end_subjectPublicKey:
+ PORT_Free (spki.subjectPublicKey.data);
+
+ return res;
+}
+
+CK_RV
+ncr_public_key_export_dsa (struct ncr_public_key *key,
+ struct ncr_mpi
+ mpis [static NCR_DSA_PUBLIC_NUM_MPIS])
+{
+ struct dsa_public_values der_output;
+ CERTSubjectPublicKeyInfo *spki;
+ PRArenaPool *arena;
+ SECItem key_item;
+ CK_RV res;
+ size_t i;
+
+ 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 (mpis != NULL, CKR_ARGUMENTS_BAD);
+
+ spki = SECKEY_CreateSubjectPublicKeyInfo(key->key);
+ if (spki == NULL)
+ return CKR_GENERAL_ERROR;
+
+ res = dsa_validate_algorithm_id (&spki->algorithm);
+ if (res != CKR_OK)
+ goto end_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)
+ {
+ res = CKR_HOST_MEMORY;
+ goto end_spki;
+ }
+
+ /* Setting type to siUnsignedInteger requests removal of leading zeroes. */
+ for (i = 0; i < NCR_DSA_PUBLIC_NUM_MPIS; i++)
+ der_output.items[i].type = siUnsignedInteger;
+
+ if (SEC_QuickDERDecodeItem (arena, &der_output,
+ dsa_public_values_params_asn1_template,
+ &spki->algorithm.parameters) != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end_arena;
+ }
+ /* spki->subjectPublicKey is encoded as BIT_STRING, so "len" is a number of
+ _bits_. */
+ key_item.data = spki->subjectPublicKey.data;
+ key_item.len = (spki->subjectPublicKey.len / 8
+ + (spki->subjectPublicKey.len % 8 != 0));
+ if (SEC_QuickDERDecodeItem (arena, &der_output,
+ dsa_public_values_key_asn1_template, &key_item)
+ != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end_arena;
+ }
+
+ res = mpi_output_decoded_SECItems(mpis, der_output.items,
+ NCR_DSA_PUBLIC_NUM_MPIS);
+
+ end_arena:
+ PORT_FreeArena (arena, PR_FALSE);
+ end_spki:
+ SECKEY_DestroySubjectPublicKeyInfo (spki);
+ return res;
+}
+
+CK_RV
+ncr_private_key_create_dsa (struct ncr_private_key **key, _Bool sensitive,
+ const struct ncr_mpi
+ mpis[static NCR_DSA_PRIVATE_NUM_MPIS],
+ const struct ncr_mpi *public_value)
+{
+ struct dsa_private_values der_input;
+ SECItem public_item, params;
+ struct private_key_info pki;
+ SECStatus ss;
+ CK_RV res;
+
+ res = ensure_ncr_is_open ();
+ if (res != CKR_OK)
+ return res;
+
+ res = mpi_create_SECItems_for_encoding (der_input.items, mpis,
+ NCR_DSA_PRIVATE_NUM_MPIS);
+ if (res != CKR_OK)
+ return res;
+ res = mpi_create_SECItems_for_encoding (&public_item, public_value, 1);
+ if (res != CKR_OK)
+ return res;
+
+ params.data = NULL;
+ params.len = 0;
+ if (SEC_ASN1EncodeItem (NULL, &params, &der_input,
+ dsa_private_values_params_asn1_template) == NULL)
+ return CKR_HOST_MEMORY;
+ memset (&pki.algorithm, 0, sizeof (pki.algorithm));
+ ss = SECOID_SetAlgorithmID (NULL, &pki.algorithm,
+ SEC_OID_ANSIX9_DSA_SIGNATURE, &params);
+ PORT_Free (params.data);
+ if (ss != SECSuccess)
+ return CKR_GENERAL_ERROR;
+
+ pki.private_key.data = NULL;
+ pki.private_key.len = 0;
+ if (SEC_ASN1EncodeItem (NULL, &pki.private_key, &der_input,
+ dsa_private_values_key_asn1_template) == NULL)
+ {
+ res = CKR_HOST_MEMORY;
+ goto end_algorithm;
+ }
+
+ res = private_key_create_components (key, CKK_DSA, sensitive, &pki,
+ &public_item);
+ SECITEM_ZfreeItem (&pki.private_key, PR_FALSE);
+
+ end_algorithm:
+ SECOID_DestroyAlgorithmID (&pki.algorithm, PR_FALSE);
+ return res;
+}
+
+CK_RV
+ncr_private_key_export_dsa (struct ncr_private_key *key,
+ struct ncr_mpi
+ mpis[static NCR_DSA_PRIVATE_NUM_MPIS])
+{
+ struct private_key_info pki;
+ struct dsa_private_values der_output;
+ PRArenaPool *arena;
+ 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_components (key, arena, &pki);
+ if (res != CKR_OK)
+ goto end;
+
+ res = dsa_validate_algorithm_id (&pki.algorithm);
+ if (res != CKR_OK)
+ goto end;
+
+ /* Setting type to siUnsignedInteger requests removal of leading zeroes. */
+ for (i = 0; i < NCR_DSA_PRIVATE_NUM_MPIS; i++)
+ der_output.items[i].type = siUnsignedInteger;
+ if (SEC_QuickDERDecodeItem (arena, &der_output,
+ dsa_private_values_params_asn1_template,
+ &pki.algorithm.parameters) != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end;
+ }
+ if (SEC_QuickDERDecodeItem (arena, &der_output,
+ dsa_private_values_key_asn1_template,
+ &pki.private_key) != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end;
+ }
+
+ res = mpi_output_decoded_SECItems(mpis, der_output.items,
+ NCR_DSA_PRIVATE_NUM_MPIS);
+
+ end:
+ PORT_FreeArena (arena, PR_TRUE);
+ return res;
+}
+
+CK_RV
+ncr_key_pair_generate_dsa (struct ncr_public_key **public_key,
+ struct ncr_private_key **private_key,
+ CK_MECHANISM_TYPE mech, _Bool sensitive,
+ const struct ncr_mpi
+ mpis[static NCR_DSA_GEN_NUM_MPIS])
+{
+ SECKEYPQGParams params;
+ size_t i;
+ CK_RV res;
+
+ res = ensure_ncr_is_open ();
+ if (res != CKR_OK)
+ return res;
+
+ g_return_val_if_fail (mech == CKM_DSA_KEY_PAIR_GEN, CKR_MECHANISM_INVALID);
+ g_return_val_if_fail (mpis != NULL, CKR_ARGUMENTS_BAD);
+ for (i = 0; i < NCR_DSA_GEN_NUM_MPIS; i++)
+ g_return_val_if_fail (mpis[i].data != NULL, CKR_ARGUMENTS_BAD);
+
+ params.prime.data = mpis[NCR_DSA_GEN_MPI_PRIME].data;
+ params.prime.len = mpis[NCR_DSA_GEN_MPI_PRIME].size;
+ params.subPrime.data = mpis[NCR_DSA_GEN_MPI_SUBPRIME].data;
+ params.subPrime.len = mpis[NCR_DSA_GEN_MPI_SUBPRIME].size;
+ params.base.data = mpis[NCR_DSA_GEN_MPI_BASE].data;
+ params.base.len = mpis[NCR_DSA_GEN_MPI_BASE].size;
+
+ return key_pair_generate (public_key, private_key, mech, sensitive, &params);
+}
+
/* Asymmetric operations */
CK_RV
diff --git a/tests/dsa.c b/tests/dsa.c
new file mode 100644
index 0000000..952407e
--- /dev/null
+++ b/tests/dsa.c
@@ -0,0 +1,195 @@
+/* DSA 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>
+
+#define MPI_PRIME "\xD1\x58\x93\x91\x4F\x33\x5C\xB1\x44\xD0\x5E\x44\x5D\xD8\xC6\x8A\xD8\x48\x0F\x18\xF4\x9C\x58\xDB\x65\x9E\x24\x75\x45\x59\x83\xF5\xA4\x67\x2B\x63\xF6\x14\xFE\x2F\xE0\x1E\x2E\x32\x1E\xA0\xAA\xFB\x62\x4C\xEE\xFF\xBF\x3A\x39\x05\x04\x6A\xFF\xF8\x7F\x2B\x3C\x56\xD4\x56\x61\x3E\xB9\x29\x26\x43\x20\x71\xA4\xD3\x48\x30\x9E\xC3\x61\x0C\xDB\x41\x00\xCF\xFF\x48\x33\xB0\xB3\xA4\xCE\x9B\x05\x25\x7C\xF3\x66\x40\x00\x3E\x39\x7C\x74\x86\x72\xA9\xE8\x4F\xE6\xD9\x7B\x48\x0E\x13\xAC\x39\xE4\xD8\x3E\x71\x92\x51\xD5\xA0\x5C\x01"
+#define MPI_SUBPRIME "\x96\x30\x8F\xD6\x53\x32\xDB\x77\x02\xFC\x78\x57\xF8\x5E\xA0\x4C\x34\xCC\xF3\xC5"
+#define MPI_BASE "\x89\x85\x3F\x3C\x68\xE1\x8D\x1A\xEA\xE9\x96\x5B\xF5\x64\x64\x82\xEC\xC4\x13\xFC\xD3\xDA\xB8\xE9\xEB\x81\x96\x82\xFE\x2E\xF7\xA1\x91\x20\x01\xAF\x76\xB7\xA8\x0C\x30\x14\x6D\x3C\x31\xDA\x30\x41\x60\xE8\x5E\x0F\x1B\xD4\x58\xA0\xD3\xC9\x0F\x36\x93\xB4\xFB\x93\x69\xB3\xFF\xD1\x96\x40\x9D\xC8\x2E\x89\x5A\x5C\xB2\xD0\x6B\x43\xCE\x0E\x2D\x03\x79\x39\xA4\x3C\xE9\x84\xDB\x78\x93\x81\x28\xB3\x75\x82\x39\xC3\xF1\x83\x18\x29\x25\x14\xDF\xD2\x94\xFC\x1B\x42\x7E\x2B\x7F\x16\x3B\xDD\x80\xB1\x5E\xB4\x3C\xE6\x9A\xA0\x3F\x0F"
+
+static const struct ncr_mpi generate_mpis[NCR_DSA_GEN_NUM_MPIS] =
+ {
+#define INT(NAME, VAL) \
+ [NCR_DSA_GEN_MPI_##NAME] = { (void *)(VAL), sizeof (VAL) - 1 }
+
+ INT (PRIME, MPI_PRIME), INT (SUBPRIME, MPI_SUBPRIME), INT (BASE, MPI_BASE)
+#undef INT
+ };
+
+static const struct ncr_mpi public_import_mpis[NCR_DSA_PUBLIC_NUM_MPIS] =
+ {
+#define INT(NAME, VAL) \
+ [NCR_DSA_PUBLIC_MPI_##NAME] = { (void *)(VAL), sizeof (VAL) - 1 }
+
+ INT (PRIME, MPI_PRIME), INT (SUBPRIME, MPI_SUBPRIME), INT (BASE, MPI_BASE),
+ INT (VALUE, "\x0D\x91\xC1\x82\xC1\x3C\x1B\x18\xBC\x98\xFE\x67\x23\x74\x2E\xD4\x5F\xA9\xFE\x55\x56\x44\x77\x2D\x72\x50\xF7\x68\x8F\xBD\x9A\xB1\x3F\xE0\x34\x12\xCB\xE8\x1E\x5E\xC2\x13\xD2\xB2\xBC\xFC\x55\xAC\x86\x83\x59\x7F\xCD\xEA\x99\x40\xA3\xB7\xC5\x9A\xA7\x7E\xD5\xEC\x0A\xC5\x8C\xD6\x36\x38\x62\xAE\x0B\x5D\xD1\x73\xCE\x33\x4D\x96\xA1\xE2\xB9\x54\x6B\xDB\xED\xE3\x2C\x07\x03\xC7\x5A\x36\x24\x69\xA8\x51\xD5\xD9\xF7\x2E\x2F\x56\xB7\xBD\x16\x5C\x53\x5F\xAC\x90\xE6\xC1\x7A\x58\xFC\x69\x9F\xAA\xEB\xB3\x24\xEC\xB7\x42\x8E\x8C")
+#undef INT
+ };
+
+static const struct ncr_mpi private_import_mpis[NCR_DSA_PRIVATE_NUM_MPIS] =
+ {
+#define INT(NAME, VAL) \
+ [NCR_DSA_PRIVATE_MPI_##NAME] = { (void *)(VAL), sizeof (VAL) - 1 }
+
+ INT (PRIME, MPI_PRIME), INT (SUBPRIME, MPI_SUBPRIME), INT (BASE, MPI_BASE),
+ INT (VALUE, "\x3E\x72\xDF\x63\xA9\xE0\x3A\x30\xE5\x3E\x1E\x7D\x53\xAD\x8D\x51\xC7\xB2\x2B\x33")
+#undef INT
+ };
+
+static const uint8_t input[20] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13";
+
+static void
+validate_mpis (const struct ncr_mpi *a, const struct ncr_mpi *b,
+ size_t num_mpis)
+{
+ size_t i;
+
+ for (i = 0; i < num_mpis; i++)
+ assert (a[i].size == b[i].size);
+ for (i = 0; i < num_mpis; i++)
+ assert (memcmp (a[i].data, b[i].data, a[i].size) == 0);
+}
+
+static void
+test_key_pair (struct ncr_public_key *public, struct ncr_private_key *private)
+{
+ uint8_t dest[4096];
+ size_t dest_size;
+ CK_RV res;
+
+ /* Test signatures */
+ dest_size = sizeof (dest);
+ res = ncr_private_key_sign (CKM_DSA, private, dest, &dest_size, input,
+ sizeof (input));
+ assert (res == CKR_OK);
+ res = ncr_public_key_verify (CKM_DSA, public, dest, dest_size, input,
+ sizeof (input));
+ assert (res == CKR_OK);
+ dest[0]++;
+ res = ncr_public_key_verify (CKM_DSA, 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[MAX ((int)NCR_DSA_PUBLIC_NUM_MPIS,
+ (int)NCR_DSA_PRIVATE_NUM_MPIS)];
+ uint8_t mpi_dest[MAX ((int)NCR_DSA_PUBLIC_NUM_MPIS,
+ (int)NCR_DSA_PRIVATE_NUM_MPIS)][256];
+ size_t i;
+ CK_RV res;
+
+ /* Test key loading. Should we test the generic version as well? */
+ res = ncr_public_key_create_dsa (&public, public_import_mpis);
+ assert (res == CKR_OK);
+ res = ncr_private_key_create_dsa
+ (&private, false, private_import_mpis,
+ &public_import_mpis[NCR_DSA_PUBLIC_MPI_VALUE]);
+ assert (res == CKR_OK);
+
+ test_key_pair (public, private);
+
+ /* Test key export. */
+ for (i = 0; i < NCR_DSA_PUBLIC_NUM_MPIS; i++)
+ {
+ dest_mpis[i].data = mpi_dest[i];
+ dest_mpis[i].size = sizeof (mpi_dest[i]);
+ }
+ res = ncr_public_key_export_dsa (public, dest_mpis);
+ assert (res == CKR_OK);
+ validate_mpis (dest_mpis, public_import_mpis, NCR_DSA_PUBLIC_NUM_MPIS);
+
+ for (i = 0; i < NCR_DSA_PRIVATE_NUM_MPIS; i++)
+ {
+ dest_mpis[i].data = mpi_dest[i];
+ dest_mpis[i].size = sizeof (mpi_dest[i]);
+ }
+ res = ncr_private_key_export_dsa (private, dest_mpis);
+ assert (res == CKR_OK);
+ validate_mpis (dest_mpis, private_import_mpis, NCR_DSA_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_dsa (&public, &private, CKM_DSA_KEY_PAIR_GEN,
+ false, generate_mpis);
+ assert (res == CKR_OK);
+
+ test_key_pair (public, private);
+
+ /* Test key export - only test that it succeeds. */
+ for (i = 0; i < NCR_DSA_PUBLIC_NUM_MPIS; i++)
+ {
+ dest_mpis[i].data = mpi_dest[i];
+ dest_mpis[i].size = sizeof (mpi_dest[i]);
+ }
+ res = ncr_public_key_export_dsa (public, dest_mpis);
+ assert (res == CKR_OK);
+
+ for (i = 0; i < NCR_DSA_PRIVATE_NUM_MPIS; i++)
+ {
+ dest_mpis[i].data = mpi_dest[i];
+ dest_mpis[i].size = sizeof (mpi_dest[i]);
+ }
+ res = ncr_private_key_export_dsa (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);
+ res = ncr_close ();
+ assert (res == CKR_OK);
+ /* Close the implicit reference */
+ res = ncr_close ();
+ assert (res == CKR_OK);
+ /* Check further closes are invalid */
+ res = ncr_close ();
+ assert (res == CKR_GENERAL_ERROR);
+
+ return EXIT_SUCCESS;
+}