[gnome-keyring/dbus-api] [pkcs11] Implement AES key wrapping.



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]