diff options
Diffstat (limited to 'lib/ncrypto_nss.c')
-rw-r--r-- | lib/ncrypto_nss.c | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index dc250cd..a430c3f 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -1041,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 |