From 9f8c85856ca06788c4eedb16d37f375491948a54 Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Tue, 30 Nov 2010 21:58:21 +0100 Subject: Use PKCS#8 privateKeyInfo for private keys in DER form --- include/ncrypto/ncrypto.h | 3 +- lib/ncrypto_nss.c | 177 ++++++++++++++++++++++++---------------------- 2 files changed, 94 insertions(+), 86 deletions(-) diff --git a/include/ncrypto/ncrypto.h b/include/ncrypto/ncrypto.h index 3938b45..07e57be 100644 --- a/include/ncrypto/ncrypto.h +++ b/include/ncrypto/ncrypto.h @@ -77,7 +77,8 @@ CK_RV ncr_public_key_create (struct ncr_public_key **key, const void *der, 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, diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c index 4c5ac06..afdc5b0 100644 --- a/lib/ncrypto_nss.c +++ b/lib/ncrypto_nss.c @@ -254,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); @@ -333,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; @@ -359,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; @@ -374,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, }; */ @@ -393,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; @@ -471,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); @@ -500,6 +475,27 @@ 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; + + 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, @@ -555,7 +551,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 (); @@ -570,25 +566,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: @@ -895,7 +891,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 (); @@ -907,19 +903,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; } @@ -928,9 +935,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; @@ -946,7 +953,7 @@ 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; @@ -955,7 +962,7 @@ 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; -- cgit