summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/ncrypto/ncrypto.h8
-rw-r--r--lib/ncrypto_nss.c223
2 files changed, 199 insertions, 32 deletions
diff --git a/include/ncrypto/ncrypto.h b/include/ncrypto/ncrypto.h
index 9f5a3f4..47ca5df 100644
--- a/include/ncrypto/ncrypto.h
+++ b/include/ncrypto/ncrypto.h
@@ -76,10 +76,14 @@ CK_RV ncr_public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type,
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. */
CK_RV ncr_private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
- const void *der, size_t der_size,
+ _Bool sensitive, const void *der, size_t der_size,
const void *public_value,
size_t public_value_size);
+CK_RV ncr_private_key_set_sensitive (struct ncr_private_key *key);
+CK_RV ncr_private_key_export (struct ncr_private_key *key, void *dest,
+ size_t *dest_size_ptr);
CK_RV ncr_private_key_destroy (struct ncr_private_key *key);
/* RSA keys */
@@ -92,7 +96,7 @@ CK_RV ncr_public_key_export_rsa (struct ncr_public_key *key,
void *modulus, size_t *modulus_size_ptr,
void *public_exponent,
size_t *public_exponent_size_ptr);
-CK_RV ncr_private_key_create_rsa (struct ncr_private_key **key,
+CK_RV ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive,
const void *modulus, size_t modulus_size,
const void *public_exponent,
size_t public_exponent_size,
diff --git a/lib/ncrypto_nss.c b/lib/ncrypto_nss.c
index d6ded4f..48d2e47 100644
--- a/lib/ncrypto_nss.c
+++ b/lib/ncrypto_nss.c
@@ -27,6 +27,7 @@ Red Hat author: Miloslav Trmač <mitr@redhat.com> */
#include <config.h>
#include <pthread.h>
+#include <stdbool.h>
#include <glib.h>
#include <keyhi.h>
@@ -122,8 +123,32 @@ struct ncr_public_key
struct ncr_private_key
{
SECKEYPrivateKey *key;
+ bool sensitive;
};
+struct private_key_info
+{
+ SECItem version;
+ SECAlgorithmID algorithm;
+ SECItem private_key;
+};
+
+static const SEC_ASN1Template private_key_info_asn1_template[] =
+ {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct private_key_info) },
+ { SEC_ASN1_INTEGER, offsetof (struct private_key_info, version), NULL, 0 },
+ {
+ SEC_ASN1_INLINE, offsetof (struct private_key_info, algorithm),
+ SECOID_AlgorithmIDTemplate, 0
+ },
+ {
+ SEC_ASN1_OCTET_STRING, offsetof (struct private_key_info, private_key),
+ NULL, 0
+ },
+ /* Attributes are optional and we never use them. */
+ { 0, 0, NULL, 0 }
+ };
+
static CK_RV
public_key_create (struct ncr_public_key **key, CK_KEY_TYPE type,
const SECItem *der_key)
@@ -295,36 +320,15 @@ ncr_public_key_destroy (struct ncr_public_key *key)
static CK_RV
private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
- const SECItem *der_key, const SECItem *public_value)
+ bool sensitive, const SECItem *der_key,
+ const SECItem *public_value)
{
- struct priv_key_info
- {
- SECItem version;
- SECAlgorithmID algorithm;
- SECItem private_key;
- };
-
- static const SEC_ASN1Template asn1_template[] =
- {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (struct priv_key_info) },
- { SEC_ASN1_INTEGER, offsetof (struct priv_key_info, version), NULL, 0, },
- {
- SEC_ASN1_INLINE, offsetof (struct priv_key_info, algorithm),
- SECOID_AlgorithmIDTemplate, 0,
- },
- {
- SEC_ASN1_OCTET_STRING, offsetof (struct priv_key_info, private_key),
- NULL, 0,
- },
- /* Attributes are optional and we never use them. */
- { 0, 0, NULL, 0 }
- };
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 priv_key_info der_input;
+ struct private_key_info der_input;
PK11SlotInfo *slot;
SECItem der_info, *der_res, key_item, iv_item, wrapped_item;
SECOidTag alg_tag;
@@ -361,7 +365,8 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
der_info.data = NULL;
der_info.len = 0;
- der_res = SEC_ASN1EncodeItem (NULL, &der_info, &der_input, asn1_template);
+ der_res = SEC_ASN1EncodeItem (NULL, &der_info, &der_input,
+ private_key_info_asn1_template);
SECOID_DestroyAlgorithmID (&der_input.algorithm, PR_FALSE);
@@ -423,6 +428,7 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
if (k->key == NULL)
goto err_k;
+ k->sensitive = sensitive;
*key = k;
return CKR_OK;
@@ -442,7 +448,7 @@ private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
/* 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,
- const void *der, size_t der_size,
+ _Bool sensitive, const void *der, size_t der_size,
const void *public_value, size_t public_value_size)
{
SECItem der_key;
@@ -460,7 +466,162 @@ ncr_private_key_create (struct ncr_private_key **key, CK_KEY_TYPE type,
der_key.len = der_size;
public.data = (void *)public_value;
public.len = public_value_size;
- return private_key_create (key, type, &der_key, &public);
+ return private_key_create (key, type, sensitive, &der_key, &public);
+}
+
+CK_RV
+ncr_private_key_set_sensitive (struct ncr_private_key *key)
+{
+ CK_RV res;
+
+ res = ensure_ncr_is_open ();
+ if (res != CKR_OK)
+ return res;
+
+ g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID);
+ key->sensitive = true;
+ return CKR_OK;
+}
+
+CK_RV
+ncr_private_key_export (struct ncr_private_key *key, void *dest,
+ size_t *dest_size_ptr)
+{
+ static const uint8_t wrap_key[32]; /* = { 0, }; */
+ static const uint8_t wrap_iv[16]; /* = { 0, }; */
+
+ PK11SlotInfo *slot;
+ SECItem key_item, iv_item, wrapped_item, der_info;
+ PK11SymKey *wrapping_key;
+ PK11Context *ctx;
+ int der_info_len;
+ PRArenaPool *arena;
+ struct private_key_info der_output;
+ SECStatus ss;
+ CK_RV res;
+
+ g_return_val_if_fail (key != NULL, CKR_KEY_HANDLE_INVALID);
+ g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD);
+
+ g_return_val_if_fail (!key->sensitive, CKR_ATTRIBUTE_SENSITIVE);
+
+ slot = PK11_GetBestSlot (CKM_AES_CBC_PAD, NULL);
+ if (slot == NULL)
+ return CKR_GENERAL_ERROR;
+
+ key_item.data = (void *)wrap_key;
+ key_item.len = sizeof (wrap_key);
+ wrapping_key = PK11_ImportSymKeyWithFlags (slot, CKM_AES_CBC_PAD,
+ PK11_OriginUnwrap, CKA_FLAGS_ONLY,
+ &key_item,
+ CKF_ENCRYPT | CKF_UNWRAP,
+ PR_FALSE /* isPerm */, NULL);
+ if (wrapping_key == NULL)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end_slot;
+ }
+ iv_item.data = (void *)wrap_iv;
+ iv_item.len = sizeof (wrap_iv);
+
+ memset (&wrapped_item, 0, sizeof (wrapped_item));
+ if (PK11_WrapPrivKey(slot, wrapping_key, key->key, CKM_AES_CBC_PAD, &iv_item,
+ &wrapped_item, NULL) != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end_wrapping_key;
+ }
+ if (SECITEM_AllocItem (NULL, &wrapped_item, wrapped_item.len) == NULL)
+ {
+ res = CKR_HOST_MEMORY;
+ goto end_wrapping_key;
+ }
+ if (PK11_WrapPrivKey(slot, wrapping_key, key->key, CKM_AES_CBC_PAD, &iv_item,
+ &wrapped_item, NULL) != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end_wrapped_item;
+ }
+
+ ctx = PK11_CreateContextBySymKey (CKM_AES_CBC_PAD, CKA_DECRYPT, wrapping_key,
+ &iv_item);
+ if (ctx == NULL)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end_wrapped_item;
+ }
+ memset (&der_info, 0, sizeof (der_info));
+ if (SECITEM_AllocItem (NULL, &der_info, wrapped_item.len) == NULL)
+ {
+ PK11_DestroyContext (ctx, PR_TRUE);
+ res = CKR_HOST_MEMORY;
+ goto end_wrapped_item;
+ }
+ if (PK11_CipherOp (ctx, der_info.data, &der_info_len, der_info.len,
+ wrapped_item.data, wrapped_item.len) != SECSuccess)
+ {
+ PK11_DestroyContext (ctx, PR_TRUE);
+ res = CKR_GENERAL_ERROR;
+ goto end_der_info;
+ }
+ /* C_DecryptFinal is only available through this function. "Nice.". */
+ ss = PK11_DigestFinal (ctx, der_info.data + der_info_len,
+ &der_info.len, der_info.len - der_info_len);
+ PK11_DestroyContext (ctx, PR_TRUE);
+ if (ss != SECSuccess)
+ {
+ res = CKR_GENERAL_ERROR;
+ goto end_der_info;
+ }
+ der_info.len += der_info_len;
+
+ /* 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_der_info;
+ }
+
+ /* "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 end_arena;
+ }
+
+ /* Should we validate the version and algorithm ID here? */
+
+ if (dest == NULL)
+ {
+ *dest_size_ptr = der_output.private_key.len;
+ return CKR_OK;
+ }
+ if (*dest_size_ptr < der_output.private_key.len)
+ {
+ *dest_size_ptr = der_output.private_key.len;
+ return CKR_BUFFER_TOO_SMALL;
+ }
+ *dest_size_ptr = der_output.private_key.len;
+
+ memcpy (dest, der_output.private_key.data, der_output.private_key.len);
+ res = CKR_OK;
+
+ end_arena:
+ PORT_FreeArena (arena, PR_TRUE);
+ end_der_info:
+ SECITEM_ZfreeItem (&der_info, PR_FALSE);
+ end_wrapped_item:
+ SECITEM_ZfreeItem (&wrapped_item, PR_FALSE);
+ end_wrapping_key:
+ PK11_FreeSymKey (wrapping_key);
+ end_slot:
+ PK11_FreeSlot (slot);
+ return res;
}
CK_RV
@@ -608,8 +769,9 @@ ncr_public_key_export_rsa (struct ncr_public_key *key, void *modulus,
}
CK_RV
-ncr_private_key_create_rsa (struct ncr_private_key **key, const void *modulus,
- size_t modulus_size, const void *public_exponent,
+ncr_private_key_create_rsa (struct ncr_private_key **key, _Bool sensitive,
+ const void *modulus, size_t modulus_size,
+ const void *public_exponent,
size_t public_exponent_size,
const void *private_exponent,
size_t private_exponent_size, const void *prime_1,
@@ -673,7 +835,8 @@ ncr_private_key_create_rsa (struct ncr_private_key **key, const void *modulus,
if (SEC_ASN1EncodeItem (NULL, &der_key, &der_input, asn1_template) == NULL)
return CKR_HOST_MEMORY;
- res = private_key_create (key, CKK_RSA, &der_key, &der_input.modulus);
+ res = private_key_create (key, CKK_RSA, sensitive, &der_key,
+ &der_input.modulus);
PORT_Free (der_key.data);
return res;