diff options
-rw-r--r-- | include/ncrypto/ncrypto.h | 5 | ||||
-rw-r--r-- | lib/ncrypto_nss.c | 191 |
2 files changed, 89 insertions, 107 deletions
diff --git a/include/ncrypto/ncrypto.h b/include/ncrypto/ncrypto.h index d9508bf..3938b45 100644 --- a/include/ncrypto/ncrypto.h +++ b/include/ncrypto/ncrypto.h @@ -71,8 +71,9 @@ 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); diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index 4737fc2..e22c65a 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; } @@ -821,7 +768,7 @@ ncr_public_key_create_rsa (struct ncr_public_key **key, 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 +780,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, + 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; - res = public_key_create (key, CKK_RSA, &der_key); - PORT_Free (der_key.data); + 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, &spki); + + SECOID_DestroyAlgorithmID (&spki.algorithm, PR_FALSE); + end_subjectPublicKey: + PORT_Free (spki.subjectPublicKey.data); return res; } @@ -849,11 +815,15 @@ CK_RV ncr_public_key_export_rsa (struct ncr_public_key *key, struct ncr_mpi mpis[static NCR_RSA_PUBLIC_NUM_MPIS]) { + static const uint8_t asn1_null[] = { SEC_ASN1_NULL, 0 }; + static const SECItem asn1_null_item + = { 0, (void *)&asn1_null, sizeof (asn1_null) }; + struct rsa_public_key der_output; + CERTSubjectPublicKeyInfo *spki; + const SECOidData *oid; 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 +831,53 @@ 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; + + oid = SECOID_FindOIDByTag (SEC_OID_PKCS1_RSA_ENCRYPTION); + if (oid == NULL + || !SECITEM_ItemsAreEqual(&spki->algorithm.algorithm, &oid->oid) + || !SECITEM_ItemsAreEqual(&spki->algorithm.parameters, &asn1_null_item)) + { + res = CKR_GENERAL_ERROR; + 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; } |