summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cryptodev_main.c1
-rw-r--r--ncr-key-wrap.c149
-rw-r--r--ncr-key.c4
-rw-r--r--ncr.c35
-rw-r--r--ncr.h23
-rw-r--r--ncr_int.h11
6 files changed, 212 insertions, 11 deletions
diff --git a/cryptodev_main.c b/cryptodev_main.c
index 185d894..0797986 100644
--- a/cryptodev_main.c
+++ b/cryptodev_main.c
@@ -748,6 +748,7 @@ cryptodev_register(void)
int rc;
ncr_limits_init();
+ ncr_master_key_reset();
rc = misc_register (&cryptodev);
if (unlikely(rc)) {
diff --git a/ncr-key-wrap.c b/ncr-key-wrap.c
index b6987af..db0374e 100644
--- a/ncr-key-wrap.c
+++ b/ncr-key-wrap.c
@@ -34,12 +34,43 @@ typedef uint8_t val64_t[8];
static const val64_t initA = "\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6";
-void val64_zero( val64_t * val)
+static int key_from_storage_data(struct key_item_st* key, const void* data, size_t data_size);
+static int key_to_storage_data( uint8_t** data, size_t * data_size, const struct key_item_st *key);
+
+static int _wrap_aes_rfc5649(void* kdata, size_t kdata_size, struct key_item_st* key,
+ struct data_item_st* data, const void* iv, size_t iv_size);
+static int _unwrap_aes_rfc5649(void* kdata, size_t *kdata_size, struct key_item_st* key,
+ struct data_item_st *data, const void* iv, size_t iv_size);
+
+
+static int wrap_aes_rfc5649(struct key_item_st* tobewrapped, struct key_item_st *kek,
+ struct data_item_st* output, const void* iv, size_t iv_size)
+{
+ if (tobewrapped->type != NCR_KEY_TYPE_SECRET) {
+ err();
+ return -EINVAL;
+ }
+
+ return _wrap_aes_rfc5649(tobewrapped->key.secret.data, tobewrapped->key.secret.size,
+ kek, output, iv, iv_size);
+
+}
+
+static int unwrap_aes_rfc5649(struct key_item_st* output, struct key_item_st *kek,
+ struct data_item_st* wrapped, const void* iv, size_t iv_size)
+{
+ output->type = NCR_KEY_TYPE_SECRET;
+
+ return _unwrap_aes_rfc5649(output->key.secret.data, &output->key.secret.size, kek, wrapped, iv, iv_size);
+}
+
+
+static void val64_zero( val64_t * val)
{
memset(val, 0, sizeof(*val));
}
-void val64_xor( val64_t * val, uint32_t x)
+static void val64_xor( val64_t * val, uint32_t x)
{
(*val)[7] ^= x & 0xff;
(*val)[6] ^= (x >> 8) & 0xff;
@@ -257,7 +288,6 @@ int ret;
return -EPERM;
}
- /* FIXME: allow alternative IV */
key = ncr_key_item_get( key_lst, wrap.key.key);
if (key == NULL) {
err();
@@ -278,6 +308,9 @@ int ret;
case NCR_WALG_AES_RFC3394:
ret = wrap_aes(wkey, key, data, wrap.key.params.cipher.iv, wrap.key.params.cipher.iv_size);
break;
+ case NCR_WALG_AES_RFC5649:
+ ret = wrap_aes_rfc5649(wkey, key, data, wrap.key.params.cipher.iv, wrap.key.params.cipher.iv_size);
+ break;
default:
err();
ret = -EINVAL;
@@ -324,12 +357,15 @@ int ret;
goto fail;
}
- wkey->flags = data_flags_to_key(wkey->flags) | NCR_KEY_FLAG_WRAPPABLE;
+ wkey->flags = data_flags_to_key(data->flags) | NCR_KEY_FLAG_WRAPPABLE;
switch(wrap.algorithm) {
case NCR_WALG_AES_RFC3394:
ret = unwrap_aes(wkey, key, data, wrap.key.params.cipher.iv, wrap.key.params.cipher.iv_size);
break;
+ case NCR_WALG_AES_RFC5649:
+ ret = unwrap_aes_rfc5649(wkey, key, data, wrap.key.params.cipher.iv, wrap.key.params.cipher.iv_size);
+ break;
default:
err();
ret = -EINVAL;
@@ -342,3 +378,108 @@ fail:
return ret;
}
+
+int ncr_key_storage_wrap(struct list_sem_st* key_lst, struct list_sem_st* data_lst, void __user* arg)
+{
+struct ncr_key_storage_wrap_st wrap;
+struct key_item_st* wkey = NULL;
+struct data_item_st * data = NULL;
+uint8_t * sdata = NULL;
+size_t sdata_size = 0;
+int ret;
+
+ copy_from_user( &wrap, arg, sizeof(wrap));
+
+ wkey = ncr_key_item_get( key_lst, wrap.keytowrap);
+ if (wkey == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ if (!(wkey->flags & NCR_KEY_FLAG_WRAPPABLE)) {
+ err();
+ return -EPERM;
+ }
+
+ data = ncr_data_item_get(data_lst, wrap.data);
+ if (data == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ data->flags = key_flags_to_data(wkey->flags) | NCR_DATA_FLAG_EXPORTABLE;
+
+ ret = key_to_storage_data(&sdata, &sdata_size, wkey);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ret = _wrap_aes_rfc5649(sdata, sdata_size, &master_key, data, NULL, 0);
+
+fail:
+ if (wkey != NULL) _ncr_key_item_put(wkey);
+ if (data != NULL) _ncr_data_item_put(data);
+ if (sdata != NULL) kfree(sdata);
+
+ return ret;
+}
+
+/* Unwraps keys. All keys unwrapped are not accessible by
+ * userspace.
+ */
+int ncr_key_storage_unwrap(struct list_sem_st* key_lst, struct list_sem_st* data_lst, void __user* arg)
+{
+struct ncr_key_wrap_st wrap;
+struct key_item_st* wkey = NULL;
+struct data_item_st * data = NULL;
+uint8_t * sdata = NULL;
+size_t sdata_size = 0;
+int ret;
+
+ copy_from_user( &wrap, arg, sizeof(wrap));
+
+ wkey = ncr_key_item_get( key_lst, wrap.keytowrap);
+ if (wkey == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ data = ncr_data_item_get(data_lst, wrap.data);
+ if (data == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ sdata_size = data->data_size;
+ sdata = kmalloc(sdata_size, GFP_KERNEL);
+ if (sdata == NULL) {
+ err();
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ wkey->flags = data_flags_to_key(data->flags) | NCR_KEY_FLAG_WRAPPABLE;
+
+ ret = _unwrap_aes_rfc5649(sdata, &sdata_size, &master_key, data, NULL, 0);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ret = key_from_storage_data(wkey, sdata, sdata_size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+
+fail:
+ if (wkey != NULL) _ncr_key_item_put(wkey);
+ if (data != NULL) _ncr_data_item_put(data);
+ if (sdata != NULL) kfree(sdata);
+
+ return ret;
+}
diff --git a/ncr-key.c b/ncr-key.c
index b60cb8e..fd5b489 100644
--- a/ncr-key.c
+++ b/ncr-key.c
@@ -260,7 +260,7 @@ int ret;
memcpy(item->key_id, data.key_id, data.key_id_size);
- if (ditem->data_size > MAX_KEY_SIZE) {
+ if (ditem->data_size > NCR_CIPHER_MAX_KEY_LEN) {
err();
ret = -EINVAL;
goto fail;
@@ -320,7 +320,7 @@ size_t size;
size = gen.params.params.secret.bits/8;
if ((gen.params.params.secret.bits % 8 != 0) ||
- (size > MAX_KEY_SIZE)) {
+ (size > NCR_CIPHER_MAX_KEY_LEN)) {
err();
ret = -EINVAL;
goto fail;
diff --git a/ncr.c b/ncr.c
index 3e246ba..da2144b 100644
--- a/ncr.c
+++ b/ncr.c
@@ -30,6 +30,10 @@
#include "ncr.h"
#include "ncr_int.h"
+/* This is the master wrapping key for storage of keys
+ */
+struct key_item_st master_key;
+
void* ncr_init_lists(void)
{
struct ncr_lists *lst;
@@ -64,6 +68,29 @@ void ncr_deinit_lists(struct ncr_lists *lst)
}
}
+void ncr_master_key_reset(void)
+{
+ memset(&master_key, 0, sizeof(master_key));
+}
+
+static int ncr_master_key_set(void* __user arg)
+{
+struct ncr_master_key_st st;
+ copy_from_user(&st, arg, sizeof(st));
+
+ if (st.key_size > sizeof(master_key.key.secret.data)) {
+ err();
+ return -EINVAL;
+ }
+
+ master_key.type = NCR_KEY_TYPE_SECRET;
+
+ memcpy(master_key.key.secret.data, st.key, st.key_size);
+ master_key.key.secret.size = st.key_size;
+
+ return 0;
+}
+
int
ncr_ioctl(struct ncr_lists* lst, struct file *filp,
unsigned int cmd, unsigned long arg)
@@ -98,6 +125,10 @@ ncr_ioctl(struct ncr_lists* lst, struct file *filp,
return ncr_key_wrap(&lst->key, &lst->data, (void*)arg);
case NCRIO_KEY_UNWRAP:
return ncr_key_unwrap(&lst->key, &lst->data, (void*)arg);
+ case NCRIO_KEY_STORAGE_WRAP:
+ return ncr_key_storage_wrap(&lst->key, &lst->data, (void*)arg);
+ case NCRIO_KEY_STORAGE_UNWRAP:
+ return ncr_key_storage_unwrap(&lst->key, &lst->data, (void*)arg);
case NCRIO_SESSION_INIT:
return ncr_session_init(lst, (void*)arg);
case NCRIO_SESSION_UPDATE:
@@ -105,7 +136,9 @@ ncr_ioctl(struct ncr_lists* lst, struct file *filp,
case NCRIO_SESSION_FINAL:
return ncr_session_final(lst, (void*)arg);
case NCRIO_SESSION_ONCE:
- return ncr_session_once(lst, (void*)arg);
+ return ncr_session_once(lst, (void*)arg);
+ case NCRIO_MASTER_KEY_SET:
+ return ncr_master_key_set((void*)arg);
#if 0
case NCRIO_KEY_GENERATE_PAIR:
return ncr_key_generate_pair(&lst->key, (void*)arg);
diff --git a/ncr.h b/ncr.h
index aa7f3c1..a4d7835 100644
--- a/ncr.h
+++ b/ncr.h
@@ -6,7 +6,9 @@
#endif
#define NCR_CIPHER_MAX_BLOCK_LEN 32
+#define NCR_CIPHER_MAX_KEY_LEN 64
#define NCR_HASH_MAX_OUTPUT_SIZE 64
+
typedef enum {
NCR_ALG_NONE,
NCR_ALG_3DES_CBC=2,
@@ -37,7 +39,8 @@ typedef enum {
typedef enum {
- NCR_WALG_AES_RFC3394,
+ NCR_WALG_AES_RFC3394, /* for secret keys only */
+ NCR_WALG_AES_RFC5649, /* can wrap arbitrary key */
} ncr_wrap_algorithm_t;
typedef enum {
@@ -280,6 +283,24 @@ struct ncr_key_wrap_st {
#define NCRIO_KEY_WRAP _IOR ('c', 250, struct ncr_key_wrap_st)
#define NCRIO_KEY_UNWRAP _IOR ('c', 251, struct ncr_key_wrap_st)
+/* Internal ops */
+struct ncr_master_key_st {
+ uint8_t key[NCR_CIPHER_MAX_KEY_LEN];
+ uint16_t key_size;
+};
+
+#define NCRIO_MASTER_KEY_SET _IOR ('c', 260, struct ncr_master_key_st)
+
+/* These are similar to key_wrap and unwrap except that will store some extra
+ * fields to be able to recover a key */
+struct ncr_key_storage_wrap_st {
+ ncr_key_t keytowrap;
+ ncr_data_t data; /* encrypted keytowrap */
+};
+
+#define NCRIO_KEY_STORAGE_WRAP _IOR ('c', 261, struct ncr_key_storage_wrap_st)
+#define NCRIO_KEY_STORAGE_UNWRAP _IOR ('c', 262, struct ncr_key_storage_wrap_st)
+
/* Crypto Operations ioctls
*/
diff --git a/ncr_int.h b/ncr_int.h
index ec4aac1..7ab6d8f 100644
--- a/ncr_int.h
+++ b/ncr_int.h
@@ -36,8 +36,6 @@ struct data_item_st {
ncr_data_t desc;
};
-#define MAX_KEY_SIZE 32 /* in bytes */
-
struct key_item_st {
struct list_head list;
/* This object is also not protected from concurrent access.
@@ -50,7 +48,7 @@ struct key_item_st {
union {
struct {
- uint8_t data[MAX_KEY_SIZE];
+ uint8_t data[NCR_CIPHER_MAX_KEY_LEN];
size_t size;
} secret;
} key;
@@ -122,6 +120,8 @@ ncr_key_type_t ncr_algorithm_to_key_type(ncr_algorithm_t algo);
int ncr_key_wrap(struct list_sem_st* keys, struct list_sem_st* data, void __user* arg);
int ncr_key_unwrap(struct list_sem_st*, struct list_sem_st* data, void __user* arg);
+int ncr_key_storage_wrap(struct list_sem_st* key_lst, struct list_sem_st* data_lst, void __user* arg);
+int ncr_key_storage_unwrap(struct list_sem_st*, struct list_sem_st* data, void __user* arg);
/* sessions */
struct session_item_st* ncr_session_new(struct list_sem_st* lst);
@@ -134,6 +134,11 @@ int ncr_session_update(struct ncr_lists* lists, void __user* arg);
int ncr_session_final(struct ncr_lists* lists, void __user* arg);
int ncr_session_once(struct ncr_lists* lists, void __user* arg);
+/* master key */
+extern struct key_item_st master_key;
+
+void ncr_master_key_reset(void);
+
/* misc helper macros */
inline static unsigned int key_flags_to_data(unsigned int key_flags)
{