diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2010-06-16 12:11:01 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2010-06-17 20:49:05 +0200 |
commit | fac33709478cfbd1657aa502ea6ea1acb12ecc2d (patch) | |
tree | 429a26482407e34e4ac3e1873e63557cc048e21e | |
parent | a1e2f414b46deb9d746ba03fb337ef0c95d46f7a (diff) | |
download | cryptodev-linux-fac33709478cfbd1657aa502ea6ea1acb12ecc2d.tar.gz cryptodev-linux-fac33709478cfbd1657aa502ea6ea1acb12ecc2d.tar.xz cryptodev-linux-fac33709478cfbd1657aa502ea6ea1acb12ecc2d.zip |
Initial attempts to allow wrapping keys with out of band data such as flags, key ids etc.
-rw-r--r-- | cryptodev_main.c | 1 | ||||
-rw-r--r-- | ncr-key-wrap.c | 149 | ||||
-rw-r--r-- | ncr-key.c | 4 | ||||
-rw-r--r-- | ncr.c | 35 | ||||
-rw-r--r-- | ncr.h | 23 | ||||
-rw-r--r-- | ncr_int.h | 11 |
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; +} @@ -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; @@ -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); @@ -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 */ @@ -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) { |