diff options
-rw-r--r-- | Makefile.am | 5 | ||||
-rw-r--r-- | include/ncrypto/ncrypto.h | 55 | ||||
-rw-r--r-- | lib/ncrypto_nss.c | 736 | ||||
-rw-r--r-- | tests/dsa.c | 195 |
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, ¶ms); } + /* 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, ¶ms, &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, ¶ms); + 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, ¶ms, &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, ¶ms); + 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, ¶ms); +} + /* 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; +} |