[gnome-keyring/dbus-api] [pkcs11] Implement AES key wrapping.
- From: Stefan Walter <stefw src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-keyring/dbus-api] [pkcs11] Implement AES key wrapping.
- Date: Thu, 19 Nov 2009 18:13:51 +0000 (UTC)
commit 7051e4fdced6bf4ce44285e11c9389e2f7ad91cf
Author: Stef Walter <stef memberwebs com>
Date: Thu Nov 19 15:19:53 2009 +0000
[pkcs11] Implement AES key wrapping.
Implement CKM_AES_CBC_PAD mechanism for wrapping secret keys.
Any key that has a simple CKA_VALUE can be wrapped.
pkcs11/gck/Makefile.am | 2 +-
pkcs11/gck/gck-aes-key.c | 62 +++++++++---
pkcs11/gck/gck-aes-key.h | 7 ++
pkcs11/gck/gck-aes-mechanism.c | 223 ++++++++++++++++++++++++++++++++++++++++
pkcs11/gck/gck-aes-mechanism.h | 25 ++++-
pkcs11/gck/gck-crypto.c | 52 +++++++++-
pkcs11/gck/gck-crypto.h | 16 +++
pkcs11/gck/gck-module.c | 9 ++-
pkcs11/gck/gck-session.c | 69 ++++++++++--
9 files changed, 434 insertions(+), 31 deletions(-)
---
diff --git a/pkcs11/gck/Makefile.am b/pkcs11/gck/Makefile.am
index 9802eae..8fa04b0 100644
--- a/pkcs11/gck/Makefile.am
+++ b/pkcs11/gck/Makefile.am
@@ -18,7 +18,7 @@ BUILT_SOURCES = \
libgck_la_SOURCES = \
gck-aes-key.c gck-aes-key.h \
- gck-aes-mechanism.h \
+ gck-aes-mechanism.c gck-aes-mechanism.h \
gck-attributes.c gck-attributes.h \
gck-certificate.c gck-certificate.h \
gck-certificate-key.c gck-certificate-key.h \
diff --git a/pkcs11/gck/gck-aes-key.c b/pkcs11/gck/gck-aes-key.c
index ee97b2c..ea14086 100644
--- a/pkcs11/gck/gck-aes-key.c
+++ b/pkcs11/gck/gck-aes-key.c
@@ -23,6 +23,7 @@
#include "pkcs11/pkcs11.h"
+#include "gck-aes-mechanism.h"
#include "gck-attributes.h"
#include "gck-crypto.h"
#include "gck-aes-key.h"
@@ -64,7 +65,6 @@ attribute_set_check_value (GckAesKey *self, CK_ATTRIBUTE *attr)
{
gcry_cipher_hd_t cih;
gcry_error_t gcry;
- int algorithm;
gpointer data;
CK_RV rv;
@@ -77,19 +77,9 @@ attribute_set_check_value (GckAesKey *self, CK_ATTRIBUTE *attr)
return CKR_OK;
}
- algorithm = algorithm_for_length (self->n_value);
- g_return_val_if_fail (algorithm != 0, CKR_GENERAL_ERROR);
-
- gcry = gcry_cipher_open (&cih, algorithm, GCRY_CIPHER_MODE_ECB, 0);
- if (gcry != 0) {
- g_warning ("couldn't open %s cipher in ECB mode: %s",
- gcry_cipher_algo_name (algorithm), gcry_strerror (gcry));
+ cih = gck_aes_key_get_cipher (self, GCRY_CIPHER_MODE_ECB);
+ if (cih == NULL)
return CKR_FUNCTION_FAILED;
- }
-
- /* Setup the key */
- gcry = gcry_cipher_setkey (cih, self->value, self->n_value);
- g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
/* Buffer of zeros */
data = g_malloc0 (self->n_value);
@@ -151,6 +141,10 @@ gck_aes_key_real_get_attribute (GckObject *base, GckSession *session, CK_ATTRIBU
case CKA_KEY_TYPE:
return gck_attribute_set_ulong (attr, CKK_AES);
+ case CKA_UNWRAP:
+ case CKA_WRAP:
+ return gck_attribute_set_bool (attr, CK_TRUE);
+
case CKA_VALUE:
return gck_attribute_set_data (attr, self->value, self->n_value);
@@ -161,7 +155,8 @@ gck_aes_key_real_get_attribute (GckObject *base, GckSession *session, CK_ATTRIBU
return attribute_set_check_value (self, attr);
case CKA_ALLOWED_MECHANISMS:
- return gck_attribute_set_empty (attr);
+ return gck_attribute_set_data (attr, (CK_VOID_PTR)GCK_AES_MECHANISMS,
+ sizeof (GCK_AES_MECHANISMS));
};
return GCK_OBJECT_CLASS (gck_aes_key_parent_class)->get_attribute (base, session, attr);
@@ -224,3 +219,42 @@ gck_aes_key_get_factory (void)
return &factory;
}
+
+gsize
+gck_aes_key_get_block_size (GckAesKey *self)
+{
+ int algorithm;
+
+ g_return_val_if_fail (GCK_IS_AES_KEY (self), 0);
+
+ algorithm = algorithm_for_length (self->n_value);
+ g_return_val_if_fail (algorithm != 0, 0);
+
+ return self->n_value;
+}
+
+gcry_cipher_hd_t
+gck_aes_key_get_cipher (GckAesKey *self, int mode)
+{
+ gcry_cipher_hd_t cih;
+ gcry_error_t gcry;
+ int algorithm;
+
+ g_return_val_if_fail (GCK_IS_AES_KEY (self), NULL);
+
+ algorithm = algorithm_for_length (self->n_value);
+ g_return_val_if_fail (algorithm != 0, NULL);
+
+ gcry = gcry_cipher_open (&cih, algorithm, mode, 0);
+ if (gcry != 0) {
+ g_warning ("couldn't open %s cipher: %s",
+ gcry_cipher_algo_name (algorithm), gcry_strerror (gcry));
+ return NULL;
+ }
+
+ /* Setup the key */
+ gcry = gcry_cipher_setkey (cih, self->value, self->n_value);
+ g_return_val_if_fail (gcry == 0, NULL);
+
+ return cih;
+}
diff --git a/pkcs11/gck/gck-aes-key.h b/pkcs11/gck/gck-aes-key.h
index 168485e..f9c7726 100644
--- a/pkcs11/gck/gck-aes-key.h
+++ b/pkcs11/gck/gck-aes-key.h
@@ -27,6 +27,8 @@
#include "gck-secret-key.h"
#include "gck-types.h"
+#include <gcrypt.h>
+
#define GCK_FACTORY_AES_KEY (gck_aes_key_get_factory ())
#define GCK_TYPE_AES_KEY (gck_aes_key_get_type ())
@@ -47,4 +49,9 @@ GType gck_aes_key_get_type (void);
GckFactory* gck_aes_key_get_factory (void);
+gsize gck_aes_key_get_block_size (GckAesKey *self);
+
+gcry_cipher_hd_t gck_aes_key_get_cipher (GckAesKey *self,
+ int mode);
+
#endif /* __GCK_AES_KEY_H__ */
diff --git a/pkcs11/gck/gck-aes-mechanism.c b/pkcs11/gck/gck-aes-mechanism.c
new file mode 100644
index 0000000..b3bb8f1
--- /dev/null
+++ b/pkcs11/gck/gck-aes-mechanism.c
@@ -0,0 +1,223 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2009 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gck-aes-key.h"
+#include "gck-aes-mechanism.h"
+#include "gck-padding.h"
+#include "gck-session.h"
+#include "gck-util.h"
+
+#include "egg/egg-libgcrypt.h"
+#include "egg/egg-secure-memory.h"
+
+static gboolean
+retrieve_length (GckSession *session, GckObject *wrapped, gsize *length)
+{
+ CK_ATTRIBUTE attr;
+
+ attr.type = CKA_VALUE;
+ attr.pValue = NULL;
+ attr.ulValueLen = 0;
+
+ if (gck_object_get_attribute (wrapped, session, &attr) != CKR_OK)
+ return FALSE;
+
+ *length = attr.ulValueLen;
+ return TRUE;
+}
+
+static gpointer
+retrieve_value (GckSession *session, GckObject *wrapped, gsize *n_value)
+{
+ CK_ATTRIBUTE attr;
+
+ if (!retrieve_length (session, wrapped, n_value))
+ return NULL;
+
+ attr.type = CKA_VALUE;
+ attr.pValue = egg_secure_alloc (*n_value);
+ attr.ulValueLen = *n_value;
+
+ if (gck_object_get_attribute (wrapped, session, &attr) != CKR_OK) {
+ egg_secure_free (attr.pValue);
+ return NULL;
+ }
+
+ return attr.pValue;
+}
+
+CK_RV
+gck_aes_mechanism_wrap (GckSession *session, CK_MECHANISM_PTR mech,
+ GckObject *wrapper, GckObject *wrapped,
+ CK_BYTE_PTR output, CK_ULONG_PTR n_output)
+{
+ gcry_cipher_hd_t cih;
+ gcry_error_t gcry;
+ GckAesKey *key;
+ gpointer value, padded;
+ gsize n_value, n_padded;
+ gsize block, pos;
+ gboolean ret;
+ CK_RV rv;
+
+ g_return_val_if_fail (GCK_IS_SESSION (session), CKR_GENERAL_ERROR);
+ g_return_val_if_fail (mech, CKR_GENERAL_ERROR);
+ g_return_val_if_fail (mech->mechanism == CKM_AES_CBC_PAD, CKR_GENERAL_ERROR);
+ g_return_val_if_fail (GCK_IS_OBJECT (wrapped), CKR_GENERAL_ERROR);
+ g_return_val_if_fail (n_output, CKR_GENERAL_ERROR);
+
+ if (!GCK_IS_AES_KEY (wrapper))
+ return CKR_WRAPPING_KEY_TYPE_INCONSISTENT;
+ key = GCK_AES_KEY (wrapper);
+
+ block = gck_aes_key_get_block_size (key);
+ g_return_val_if_fail (block != 0, CKR_GENERAL_ERROR);
+
+ /* They just want the length */
+ if (!output) {
+ if (!retrieve_length (session, wrapped, &n_value))
+ return CKR_KEY_NOT_WRAPPABLE;
+ if (!gck_padding_pkcs7_pad (NULL, block, NULL, n_value, NULL, &n_padded))
+ return CKR_KEY_SIZE_RANGE;
+ *n_output = n_padded;
+ return CKR_OK;
+ }
+
+ cih = gck_aes_key_get_cipher (key, GCRY_CIPHER_MODE_CBC);
+ if (cih == NULL)
+ return CKR_FUNCTION_FAILED;
+
+ if (!mech->pParameter || gcry_cipher_setiv (cih, mech->pParameter, mech->ulParameterLen) != 0) {
+ gcry_cipher_close (cih);
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+
+ value = retrieve_value (session, wrapped, &n_value);
+ if (value == NULL) {
+ gcry_cipher_close (cih);
+ return CKR_KEY_NOT_WRAPPABLE;
+ }
+
+ ret = gck_padding_pkcs7_pad (egg_secure_realloc, block, value, n_value, &padded, &n_padded);
+ egg_secure_free (value);
+
+ if (ret == FALSE) {
+ gcry_cipher_close (cih);
+ return CKR_KEY_SIZE_RANGE;
+ }
+
+ /* In place encryption */
+ for (pos = 0; pos < n_padded; pos += block) {
+ gcry = gcry_cipher_encrypt (cih, (guchar*)padded + pos, block, NULL, 0);
+ g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+ }
+
+ gcry_cipher_close (cih);
+
+ rv = gck_util_return_data (output, n_output, padded, n_padded);
+ egg_secure_free (padded);
+ return rv;
+}
+
+CK_RV
+gck_aes_mechanism_unwrap (GckSession *session, CK_MECHANISM_PTR mech,
+ GckObject *wrapper, CK_VOID_PTR input, CK_ULONG n_input,
+ CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs,
+ GckObject **unwrapped)
+{
+ gcry_cipher_hd_t cih;
+ gcry_error_t gcry;
+ CK_ATTRIBUTE attr;
+ GArray *array;
+ GckAesKey *key;
+ gpointer padded, value;
+ gsize n_padded, n_value;
+ gsize block, pos;
+ gboolean ret;
+ CK_RV rv;
+
+ g_return_val_if_fail (GCK_IS_SESSION (session), CKR_GENERAL_ERROR);
+ g_return_val_if_fail (mech, CKR_GENERAL_ERROR);
+ g_return_val_if_fail (mech->mechanism == CKM_AES_CBC_PAD, CKR_GENERAL_ERROR);
+ g_return_val_if_fail (GCK_IS_OBJECT (wrapper), CKR_GENERAL_ERROR);
+
+ if (!GCK_IS_AES_KEY (wrapper))
+ return CKR_WRAPPING_KEY_TYPE_INCONSISTENT;
+ key = GCK_AES_KEY (wrapper);
+
+ block = gck_aes_key_get_block_size (key);
+ g_return_val_if_fail (block != 0, CKR_GENERAL_ERROR);
+
+ if (n_input == 0 || n_input % block != 0)
+ return CKR_WRAPPED_KEY_LEN_RANGE;
+
+ cih = gck_aes_key_get_cipher (key, GCRY_CIPHER_MODE_CBC);
+ if (cih == NULL)
+ return CKR_FUNCTION_FAILED;
+
+ if (!mech->pParameter || gcry_cipher_setiv (cih, mech->pParameter, mech->ulParameterLen) != 0) {
+ gcry_cipher_close (cih);
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+
+ padded = egg_secure_alloc (n_input);
+ memcpy (padded, input, n_input);
+ n_padded = n_input;
+
+ /* In place decryption */
+ for (pos = 0; pos < n_padded; pos += block) {
+ gcry = gcry_cipher_decrypt (cih, (guchar*)padded + pos, block, NULL, 0);
+ g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+ }
+
+ gcry_cipher_close (cih);
+
+ /* Unpad the resulting value */
+ ret = gck_padding_pkcs7_unpad (egg_secure_realloc, block, padded, n_padded, &value, &n_value);
+ egg_secure_free (padded);
+
+ /* TODO: This is dubious, there doesn't seem to be an rv for 'bad decrypt' */
+ if (ret == FALSE)
+ return CKR_WRAPPED_KEY_INVALID;
+
+ /* Now setup the attributes with our new value */
+ array = g_array_new (FALSE, FALSE, sizeof (CK_ATTRIBUTE));
+
+ /* Prepend the value */
+ attr.type = CKA_VALUE;
+ attr.pValue = value;
+ attr.ulValueLen = n_value;
+ g_array_append_val (array, attr);
+
+ /* Add the remainder of the attributes */
+ g_array_append_vals (array, attrs, n_attrs);
+
+ /* Now create an object with these attributes */
+ rv = gck_session_create_object_for_attributes (session, (CK_ATTRIBUTE_PTR)array->data,
+ array->len, unwrapped);
+
+ egg_secure_free (value);
+ g_array_free (array, TRUE);
+
+ return rv;
+}
diff --git a/pkcs11/gck/gck-aes-mechanism.h b/pkcs11/gck/gck-aes-mechanism.h
index 1f1dd66..de9c982 100644
--- a/pkcs11/gck/gck-aes-mechanism.h
+++ b/pkcs11/gck/gck-aes-mechanism.h
@@ -1,7 +1,7 @@
/*
* gnome-keyring
*
- * Copyright (C) 2008 Stefan Walter
+ * Copyright (C) 2009 Stefan Walter
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General License as
@@ -28,6 +28,27 @@
#include <glib.h>
-#define GCK_AES_MECHANISM_KEY_LENGTH 16
+#define GCK_AES_MECHANISM_MIN_LENGTH 16
+#define GCK_AES_MECHANISM_MAX_LENGTH 32
+
+static const CK_MECHANISM_TYPE GCK_AES_MECHANISMS[] = {
+ CKM_AES_CBC_PAD
+};
+
+CK_RV gck_aes_mechanism_wrap (GckSession *session,
+ CK_MECHANISM_PTR mech,
+ GckObject *wrapper,
+ GckObject *wrapped,
+ CK_BYTE_PTR output,
+ CK_ULONG_PTR n_output);
+
+CK_RV gck_aes_mechanism_unwrap (GckSession *session,
+ CK_MECHANISM_PTR mech,
+ GckObject *wrapper,
+ CK_VOID_PTR input,
+ CK_ULONG n_input,
+ CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs,
+ GckObject **unwrapped);
#endif /* GCK_AES_MECHANISM_H_ */
diff --git a/pkcs11/gck/gck-crypto.c b/pkcs11/gck/gck-crypto.c
index 1d2a9c3..422cd44 100644
--- a/pkcs11/gck/gck-crypto.c
+++ b/pkcs11/gck/gck-crypto.c
@@ -434,6 +434,56 @@ gck_crypto_derive_key (GckSession *session, CK_MECHANISM_PTR mech, GckObject *ba
}
}
+CK_RV
+gck_crypto_wrap_key (GckSession *session, CK_MECHANISM_PTR mech, GckObject *wrapper,
+ GckObject *wrapped, CK_BYTE_PTR output, CK_ULONG_PTR n_output)
+{
+ g_return_val_if_fail (GCK_IS_SESSION (session), CKR_GENERAL_ERROR);
+ g_return_val_if_fail (GCK_IS_OBJECT (wrapper), CKR_GENERAL_ERROR);
+ g_return_val_if_fail (GCK_IS_OBJECT (wrapped), CKR_GENERAL_ERROR);
+ g_return_val_if_fail (mech, CKR_GENERAL_ERROR);
+ g_return_val_if_fail (n_output, CKR_GENERAL_ERROR);
+
+ if (!gck_object_has_attribute_ulong (wrapper, session, CKA_ALLOWED_MECHANISMS, mech->mechanism))
+ return CKR_KEY_TYPE_INCONSISTENT;
+
+ if (!gck_object_has_attribute_boolean (wrapper, session, CKA_WRAP, TRUE))
+ return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+ switch (mech->mechanism) {
+ case CKM_AES_CBC_PAD:
+ return gck_aes_mechanism_wrap (session, mech, wrapper, wrapped,
+ output, n_output);
+ default:
+ return CKR_MECHANISM_INVALID;
+ }
+}
+
+CK_RV
+gck_crypto_unwrap_key (GckSession *session, CK_MECHANISM_PTR mech, GckObject *wrapper,
+ CK_VOID_PTR input, CK_ULONG n_input, CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs, GckObject **unwrapped)
+{
+ g_return_val_if_fail (GCK_IS_SESSION (session), CKR_GENERAL_ERROR);
+ g_return_val_if_fail (GCK_IS_OBJECT (wrapper), CKR_GENERAL_ERROR);
+ g_return_val_if_fail (mech, CKR_GENERAL_ERROR);
+ g_return_val_if_fail (unwrapped, CKR_GENERAL_ERROR);
+
+ if (!gck_object_has_attribute_ulong (wrapper, session, CKA_ALLOWED_MECHANISMS, mech->mechanism))
+ return CKR_KEY_TYPE_INCONSISTENT;
+
+ if (!gck_object_has_attribute_boolean (wrapper, session, CKA_UNWRAP, TRUE))
+ return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+ switch (mech->mechanism) {
+ case CKM_AES_CBC_PAD:
+ return gck_aes_mechanism_unwrap (session, mech, wrapper, input,
+ n_input, attrs, n_attrs, unwrapped);
+ default:
+ return CKR_MECHANISM_INVALID;
+ }
+}
+
/* ----------------------------------------------------------------------------
* PREPARE FUNCTIONS
*/
@@ -486,7 +536,7 @@ gck_crypto_secret_key_length (CK_KEY_TYPE type)
{
switch (type) {
case CKK_AES:
- return GCK_AES_MECHANISM_KEY_LENGTH;
+ return GCK_AES_MECHANISM_MIN_LENGTH;
default:
return 0;
}
diff --git a/pkcs11/gck/gck-crypto.h b/pkcs11/gck/gck-crypto.h
index b4c40d3..9921ee5 100644
--- a/pkcs11/gck/gck-crypto.h
+++ b/pkcs11/gck/gck-crypto.h
@@ -135,6 +135,22 @@ CK_RV gck_crypto_derive_key (GckSessi
CK_ULONG n_attrs,
GckObject **derived);
+CK_RV gck_crypto_wrap_key (GckSession *session,
+ CK_MECHANISM_PTR mech,
+ GckObject *wrapper,
+ GckObject *wrapped,
+ CK_BYTE_PTR output,
+ CK_ULONG_PTR n_output);
+
+CK_RV gck_crypto_unwrap_key (GckSession *session,
+ CK_MECHANISM_PTR mech,
+ GckObject *wrapper,
+ CK_VOID_PTR input,
+ CK_ULONG n_input,
+ CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs,
+ GckObject **unwrapped);
+
gulong gck_crypto_secret_key_length (CK_KEY_TYPE type);
#endif /* GCKCRYPTO_H_ */
diff --git a/pkcs11/gck/gck-module.c b/pkcs11/gck/gck-module.c
index 3301cd2..88e5479 100644
--- a/pkcs11/gck/gck-module.c
+++ b/pkcs11/gck/gck-module.c
@@ -26,6 +26,7 @@
#include "pkcs11/pkcs11i.h"
#include "gck-aes-key.h"
+#include "gck-aes-mechanism.h"
#include "gck-attributes.h"
#include "gck-certificate.h"
#include "gck-credential.h"
@@ -160,7 +161,13 @@ static const MechanismAndInfo mechanism_list[] = {
* CKM_DH_PKCS_DERIVE
* For DH derivation the min and max are sizes of prime in bits.
*/
- { CKM_DH_PKCS_DERIVE, { 768, 8192, CKF_DERIVE } }
+ { CKM_DH_PKCS_DERIVE, { 768, 8192, CKF_DERIVE } },
+
+ /*
+ * CKM_AES_CBC_PAD
+ * For AES the min and max are sizes of key in bytes.
+ */
+ { CKM_AES_CBC_PAD, { GCK_AES_MECHANISM_MIN_LENGTH, GCK_AES_MECHANISM_MAX_LENGTH, CKF_WRAP | CKF_UNWRAP } },
};
/* Hidden function that you should not use */
diff --git a/pkcs11/gck/gck-session.c b/pkcs11/gck/gck-session.c
index f321cb3..87e8c76 100644
--- a/pkcs11/gck/gck-session.c
+++ b/pkcs11/gck/gck-session.c
@@ -1539,8 +1539,30 @@ gck_session_C_WrapKey (GckSession* self, CK_MECHANISM_PTR mechanism,
CK_OBJECT_HANDLE wrapping_key, CK_OBJECT_HANDLE key,
CK_BYTE_PTR wrapped_key, CK_ULONG_PTR wrapped_key_len)
{
- /* TODO: We need to implement this */
- return CKR_FUNCTION_NOT_SUPPORTED;
+ GckObject *wrapper = NULL;
+ GckObject *wrapped = NULL;
+ CK_RV rv;
+
+ g_return_val_if_fail (GCK_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
+ if (!mechanism)
+ return CKR_ARGUMENTS_BAD;
+ if (!wrapped_key_len)
+ return CKR_ARGUMENTS_BAD;
+
+ rv = gck_session_lookup_readable_object (self, wrapping_key, &wrapper);
+ if (rv == CKR_OBJECT_HANDLE_INVALID)
+ return CKR_WRAPPING_KEY_HANDLE_INVALID;
+ else if (rv != CKR_OK)
+ return rv;
+
+ rv = gck_session_lookup_readable_object (self, key, &wrapped);
+ if (rv == CKR_OBJECT_HANDLE_INVALID)
+ return CKR_KEY_HANDLE_INVALID;
+ else if (rv != CKR_OK)
+ return rv;
+
+ return gck_crypto_wrap_key (self, mechanism, wrapper, wrapped,
+ wrapped_key, wrapped_key_len);
}
CK_RV
@@ -1549,8 +1571,39 @@ gck_session_C_UnwrapKey (GckSession* self, CK_MECHANISM_PTR mechanism,
CK_ULONG wrapped_key_len, CK_ATTRIBUTE_PTR template,
CK_ULONG count, CK_OBJECT_HANDLE_PTR key)
{
- /* TODO: We need to implement this */
- return CKR_FUNCTION_NOT_SUPPORTED;
+ GckObject *wrapper = NULL;
+ GckObject *unwrapped = NULL;
+ CK_RV rv;
+
+ g_return_val_if_fail (GCK_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
+ if (!mechanism)
+ return CKR_ARGUMENTS_BAD;
+ if (!(!count || template))
+ return CKR_ARGUMENTS_BAD;
+ if (!key)
+ return CKR_ARGUMENTS_BAD;
+
+ rv = gck_session_lookup_readable_object (self, unwrapping_key, &wrapper);
+ if (rv == CKR_OBJECT_HANDLE_INVALID)
+ return CKR_WRAPPING_KEY_HANDLE_INVALID;
+ else if (rv != CKR_OK)
+ return rv;
+
+ /*
+ * Duplicate the memory for the attributes (but not values) so we
+ * can 'consume' in the generator and create object functions.
+ */
+ template = g_memdup (template, count * sizeof (CK_ATTRIBUTE));
+
+ rv = gck_crypto_unwrap_key (self, mechanism, wrapper, wrapped_key,
+ wrapped_key_len, template, count, &unwrapped);
+
+ g_free (template);
+
+ if (rv == CKR_OK)
+ *key = gck_object_get_handle (unwrapped);
+
+ return rv;
}
CK_RV
@@ -1558,7 +1611,6 @@ gck_session_C_DeriveKey (GckSession* self, CK_MECHANISM_PTR mechanism,
CK_OBJECT_HANDLE base_key, CK_ATTRIBUTE_PTR template,
CK_ULONG count, CK_OBJECT_HANDLE_PTR key)
{
- GckTransaction *transaction;
GckObject *base = NULL;
GckObject *derived = NULL;
CK_RV rv;
@@ -1580,19 +1632,12 @@ gck_session_C_DeriveKey (GckSession* self, CK_MECHANISM_PTR mechanism,
* can 'consume' in the generator and create object functions.
*/
template = g_memdup (template, count * sizeof (CK_ATTRIBUTE));
- transaction = gck_transaction_new ();
/* Actually do the object creation */
rv = gck_crypto_derive_key (self, mechanism, base, template, count, &derived);
- if (rv != CKR_OK)
- gck_transaction_fail (transaction, rv);
g_free (template);
- gck_transaction_complete (transaction);
- rv = gck_transaction_get_result (transaction);
- g_object_unref (transaction);
-
if (rv == CKR_OK)
*key = gck_object_get_handle (derived);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]