diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2010-05-31 13:22:09 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2010-06-17 20:47:38 +0200 |
commit | 1b3ea65db78ef3dcc8200812117171531c62fe8b (patch) | |
tree | 54f66c970e6376ebda7a923d7f561702e2b19d8c | |
parent | d3c211c2e46125ea98a45f2dad9af4669c347fa6 (diff) | |
download | kernel-crypto-1b3ea65db78ef3dcc8200812117171531c62fe8b.tar.gz kernel-crypto-1b3ea65db78ef3dcc8200812117171531c62fe8b.tar.xz kernel-crypto-1b3ea65db78ef3dcc8200812117171531c62fe8b.zip |
Added ncr_key_import/export, generate and info. Those work with secret keys.
Added test program for those.
-rw-r--r-- | examples/Makefile | 6 | ||||
-rw-r--r-- | examples/new-key.c | 235 | ||||
-rw-r--r-- | ncr-data.c | 7 | ||||
-rw-r--r-- | ncr-key.c | 237 | ||||
-rw-r--r-- | ncr.c | 38 | ||||
-rw-r--r-- | ncr.h | 24 | ||||
-rw-r--r-- | ncr_int.h | 18 | ||||
-rw-r--r-- | userspace/ncrypto.h | 8 |
8 files changed, 554 insertions, 19 deletions
diff --git a/examples/Makefile b/examples/Makefile index 3190c4ade56..a3fe416b756 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -1,14 +1,16 @@ KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build -hostprogs := cipher hmac new +hostprogs := cipher hmac new new-key example-cipher-objs := cipher.o example-hmac-objs := hmac.o new-objs := new.o +new-key-objs := new-key.c check: $(hostprogs) + ./new-key ./new ./cipher ./hmac clean: - rm -f *.o *~ hmac cipher new + rm -f *.o *~ hmac cipher new new-key diff --git a/examples/new-key.c b/examples/new-key.c new file mode 100644 index 00000000000..2a5faa4c0f1 --- /dev/null +++ b/examples/new-key.c @@ -0,0 +1,235 @@ +/* + * Demo on how to use /dev/crypto device for HMAC. + * + * Placed under public domain. + * + */ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +#include <sys/ioctl.h> +#include "../ncr.h" +#include <stdlib.h> + +#define DATA_SIZE 16 + +static void randomize_data(uint8_t * data, size_t data_size) +{ +int i; + + srand(time(0)*getpid()); + for (i=0;i<data_size;i++) { + data[i] = rand() & 0xff; + } +} + +static int +test_ncr_data(int cfd) +{ + struct ncr_data_init_st dinit; + struct ncr_key_generate_st kgen; + ncr_key_t key; + struct ncr_key_data_st keydata; + struct ncr_data_st kdata; + uint8_t data[DATA_SIZE]; + uint8_t data_bak[DATA_SIZE]; + int i; + + /* test 1: generate a key in userspace import it + * to kernel via data and export it. + */ + randomize_data(data, sizeof(data)); + memcpy(data_bak, data, sizeof(data)); + + dinit.max_object_size = DATA_SIZE; + dinit.flags = NCR_DATA_FLAG_EXPORTABLE; + dinit.initial_data = data; + dinit.initial_data_size = sizeof(data); + + if (ioctl(cfd, NCRIO_DATA_INIT, &dinit)) { + perror("ioctl(NCRIO_DATA_INIT)"); + return 1; + } + + /* convert it to key */ + if (ioctl(cfd, NCRIO_KEY_INIT, &key)) { + perror("ioctl(NCRIO_KEY_INIT)"); + return 1; + } + + keydata.key_id[0] = 'a'; + keydata.key_id[2] = 'b'; + keydata.key_id_size = 2; + keydata.key = key; + keydata.data = dinit.desc; + + if (ioctl(cfd, NCRIO_KEY_IMPORT, &keydata)) { + perror("ioctl(NCRIO_KEY_IMPORT)"); + return 1; + } + + /* now try to read it */ + if (ioctl(cfd, NCRIO_DATA_DEINIT, &dinit.desc)) { + perror("ioctl(NCRIO_DATA_DEINIT)"); + return 1; + } + + dinit.max_object_size = DATA_SIZE; + dinit.flags = NCR_DATA_FLAG_EXPORTABLE; + dinit.initial_data = NULL; + dinit.initial_data_size = 0; + + if (ioctl(cfd, NCRIO_DATA_INIT, &dinit)) { + perror("ioctl(NCRIO_DATA_INIT)"); + return 1; + } + + memset(&keydata, 0, sizeof(keydata)); + keydata.key = key; + keydata.data = dinit.desc; + + if (ioctl(cfd, NCRIO_KEY_EXPORT, &keydata)) { + perror("ioctl(NCRIO_KEY_IMPORT)"); + return 1; + } + + /* now read data */ + memset(data, 0, sizeof(data)); + + kdata.desc = dinit.desc; + kdata.data = data; + kdata.data_size = sizeof(data); + kdata.append_flag = 0; + + if (ioctl(cfd, NCRIO_DATA_GET, &kdata)) { + perror("ioctl(NCRIO_DATA_GET)"); + return 1; + } + + if (memcmp(data, data_bak, sizeof(data))!=0) { + fprintf(stderr, "data returned but differ!\n"); + return 1; + } + + if (ioctl(cfd, NCRIO_KEY_DEINIT, &key)) { + perror("ioctl(NCRIO_KEY_DEINIT)"); + return 1; + } + + /* finished, we keep data for next test */ + + /* test 2: generate a key in kernel space and + * export it. + */ + + /* convert it to key */ + if (ioctl(cfd, NCRIO_KEY_INIT, &key)) { + perror("ioctl(NCRIO_KEY_INIT)"); + return 1; + } + + kgen.desc = key; + kgen.params.algorithm = NCR_ALG_AES_CBC; + kgen.params.keyflags = NCR_KEY_FLAG_EXPORTABLE; + kgen.params.params.secret.bits = 128; /* 16 bytes */ + + if (ioctl(cfd, NCRIO_KEY_GENERATE, &kgen)) { + perror("ioctl(NCRIO_KEY_IMPORT)"); + return 1; + } + + memset(&keydata, 0, sizeof(keydata)); + keydata.key = key; + keydata.data = dinit.desc; + + if (ioctl(cfd, NCRIO_KEY_EXPORT, &keydata)) { + perror("ioctl(NCRIO_KEY_IMPORT)"); + return 1; + } + + /* now read data */ + memset(data, 0, sizeof(data)); + + kdata.desc = dinit.desc; + kdata.data = data; + kdata.data_size = sizeof(data); + kdata.append_flag = 0; + + if (ioctl(cfd, NCRIO_DATA_GET, &kdata)) { + perror("ioctl(NCRIO_DATA_GET)"); + return 1; + } + + fprintf(stderr, "Generated key: %.2x.%.2x.%.2x.%.2x.%.2x.%.2x.%.2x.%.2x." + "%.2x.%.2x.%.2x.%.2x.%.2x.%.2x.%.2x.%.2x\n", data[0], data[1], + data[2], data[3], data[4], data[5], data[6], data[7], data[8], + data[9], data[10], data[11], data[12], data[13], data[14], + data[15]); + + if (ioctl(cfd, NCRIO_KEY_DEINIT, &key)) { + perror("ioctl(NCRIO_KEY_DEINIT)"); + return 1; + } + + /* test 3: generate an unexportable key in kernel space and + * try to export it. + */ + + if (ioctl(cfd, NCRIO_KEY_INIT, &key)) { + perror("ioctl(NCRIO_KEY_INIT)"); + return 1; + } + + kgen.desc = key; + kgen.params.algorithm = NCR_ALG_AES_CBC; + kgen.params.keyflags = 0; + kgen.params.params.secret.bits = 128; /* 16 bytes */ + + if (ioctl(cfd, NCRIO_KEY_GENERATE, &kgen)) { + perror("ioctl(NCRIO_KEY_IMPORT)"); + return 1; + } + + memset(&keydata, 0, sizeof(keydata)); + keydata.key = key; + keydata.data = dinit.desc; + + if (ioctl(cfd, NCRIO_KEY_EXPORT, &keydata)==0) { + fprintf(stderr, "Error: Allowed key exporting!\n"); + return 1; + } + + if (ioctl(cfd, NCRIO_KEY_DEINIT, &key)) { + perror("ioctl(NCRIO_KEY_DEINIT)"); + return 1; + } + + return 0; +} + +int +main() +{ + int fd = -1; + + /* Open the crypto device */ + fd = open("/dev/crypto", O_RDWR, 0); + if (fd < 0) { + perror("open(/dev/crypto)"); + return 1; + } + + /* Run the test itself */ + if (test_ncr_data(fd)) + return 1; + + /* Close the original descriptor */ + if (close(fd)) { + perror("close(fd)"); + return 1; + } + + return 0; +} diff --git a/ncr-data.c b/ncr-data.c index 90986bca21d..2c4c3ac032d 100644 --- a/ncr-data.c +++ b/ncr-data.c @@ -22,7 +22,6 @@ #include <linux/crypto.h> #include <linux/mm.h> #include <linux/highmem.h> -#include <linux/random.h> #include "cryptodev.h" #include <asm/uaccess.h> #include <asm/ioctl.h> @@ -32,8 +31,6 @@ #define err() printk(KERN_DEBUG"ncr: %s: %d\n", __func__, __LINE__) -static void _ncr_data_item_put( struct data_item* item); - void ncr_data_list_deinit(struct list_sem_st* lst) { if(lst) { @@ -66,7 +63,7 @@ int mx = 0; } /* returns the data item corresponding to desc */ -static struct data_item* ncr_data_item_get( struct list_sem_st* lst, ncr_data_t desc) +struct data_item* ncr_data_item_get( struct list_sem_st* lst, ncr_data_t desc) { struct data_item* item; @@ -94,7 +91,7 @@ static void* data_alloc(size_t size) return kmalloc(size, GFP_KERNEL); } -static void _ncr_data_item_put( struct data_item* item) +void _ncr_data_item_put( struct data_item* item) { if (atomic_dec_and_test(&item->refcnt)) { ncr_limits_remove(item->filp, LIMIT_TYPE_DATA); diff --git a/ncr-key.c b/ncr-key.c index 65a5525894b..56d88f7c470 100644 --- a/ncr-key.c +++ b/ncr-key.c @@ -152,3 +152,240 @@ int ncr_key_deinit(struct list_sem_st* lst, void __user* arg) return 0; } + +/* "exports" a key to a data item. If the key is not exportable + * to userspace then the data item will also not be. + */ +int ncr_key_export(struct list_sem_st* data_lst, + struct list_sem_st* key_lst, void __user* arg) +{ +struct ncr_key_data_st data; +struct key_item* item = NULL; +struct data_item* ditem = NULL; +int ret; + + copy_from_user( &data, arg, sizeof(data)); + + item = ncr_key_item_get( key_lst, data.key); + if (item == NULL) { + err(); + return -EINVAL; + } + + ditem = ncr_data_item_get( data_lst, data.data); + if (ditem == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + + switch (item->type) { + case NCR_KEY_TYPE_SECRET: + if (item->key.secret.size > ditem->max_data_size) { + err(); + ret = -EINVAL; + goto fail; + } + + /* found */ + ditem->flags = 0; + if ((item->flags & NCR_KEY_FLAG_EXPORTABLE)) { + ditem->flags |= NCR_DATA_FLAG_EXPORTABLE; + } + + if (item->key.secret.size > 0) { + memcpy(ditem->data, item->key.secret.data, item->key.secret.size); + } + ditem->data_size = item->key.secret.size; + break; + case NCR_KEY_TYPE_PUBLIC: /* FIXME: export in a blob -ASN.1? */ + case NCR_KEY_TYPE_PRIVATE: /* FIXME export in a blob -ASN.1? */ + default: + err(); + ret = -EINVAL; + goto fail; + } + + _ncr_key_item_put( item); + _ncr_data_item_put( ditem); + + return 0; + +fail: + if (item) + _ncr_key_item_put(item); + if (ditem) + _ncr_data_item_put(ditem); + return ret; + +} + +/* "imports" a key from a data item. If the key is not exportable + * to userspace then the key item will also not be. + */ +int ncr_key_import(struct list_sem_st* data_lst, + struct list_sem_st* key_lst, void __user* arg) +{ +struct ncr_key_data_st data; +struct key_item* item = NULL; +struct data_item* ditem = NULL; +int ret; + + copy_from_user( &data, arg, sizeof(data)); + + item = ncr_key_item_get( key_lst, data.key); + if (item == NULL) { + err(); + return -EINVAL; + } + + ditem = ncr_data_item_get( data_lst, data.data); + if (ditem == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + + item->type = data.type; + item->algorithm = data.algorithm; + item->flags = data.flags; + /* if data cannot be exported then the flags above + * should be overriden */ + if ((ditem->flags & NCR_DATA_FLAG_EXPORTABLE)) { + item->flags |= NCR_KEY_FLAG_EXPORTABLE; + } + + switch(item->type) { + case NCR_KEY_TYPE_SECRET: + + if (data.key_id_size > MAX_KEY_ID_SIZE) { + err(); + ret = -EINVAL; + goto fail; + } + item->key_id_size = data.key_id_size; + if (data.key_id_size > 0) + memcpy(item->key_id, data.key_id, data.key_id_size); + + + if (ditem->data_size > MAX_KEY_SIZE) { + err(); + ret = -EINVAL; + goto fail; + } + + memcpy(item->key.secret.data, ditem->data, ditem->data_size); + item->key.secret.size = ditem->data_size; + break; + case NCR_KEY_TYPE_PRIVATE: /* FIXME */ + case NCR_KEY_TYPE_PUBLIC: /* FIXME */ + default: + err(); + ret = -EINVAL; + goto fail; + } + + _ncr_key_item_put( item); + _ncr_data_item_put( ditem); + + return 0; + +fail: + if (item) + _ncr_key_item_put(item); + if (ditem) + _ncr_data_item_put(ditem); + return ret; +} + +/* Generate a secret key + */ +int ncr_key_generate(struct list_sem_st* lst, void __user* arg) +{ +struct ncr_key_generate_st gen; +struct key_item* item = NULL; +int ret; +size_t size; + + copy_from_user( &gen, arg, sizeof(gen)); + + item = ncr_key_item_get( lst, gen.desc); + if (item == NULL) { + err(); + return -EINVAL; + } + + /* we generate only secret keys */ + item->type = ncr_algorithm_to_key_type(gen.params.algorithm); + if (item->type != NCR_KEY_TYPE_SECRET) { + err(); + ret = -EINVAL; + goto fail; + } + + item->flags = gen.params.keyflags; + item->algorithm = /* arbitrary */ NCR_ALG_AES_CBC; + + size = gen.params.params.secret.bits/8; + if ((gen.params.params.secret.bits % 8 != 0) || + (size > MAX_KEY_SIZE)) { + err(); + ret = -EINVAL; + goto fail; + } + + get_random_bytes(item->key.secret.data, size); + item->key.secret.size = size; + + /* generate random key id */ + item->key_id_size = 5; + get_random_bytes(item->key_id, item->key_id_size); + + _ncr_key_item_put( item); + + return 0; + +fail: + if (item) + _ncr_key_item_put(item); + return ret; +} + +int ncr_key_info(struct list_sem_st* lst, void __user* arg) +{ +struct ncr_key_info_st info; +struct key_item* item = NULL; + + copy_from_user( &info, arg, sizeof(info)); + + item = ncr_key_item_get( lst, info.key); + if (item == NULL) { + err(); + return -EINVAL; + } + + info.flags = item->flags; + info.type = item->type; + info.algorithm = item->algorithm; + + _ncr_key_item_put( item); + + return 0; +} + +/* FIXME those require public key subsystem */ +int ncr_key_generate_pair(struct list_sem_st* lst, void __user* arg) +{ + return -EINVAL; +} + +int ncr_key_derive(struct list_sem_st* lst, void __user* arg) +{ + return -EINVAL; +} + +int ncr_key_get_public(struct list_sem_st* lst, void __user* arg) +{ + return -EINVAL; +} + @@ -82,21 +82,24 @@ ncr_ioctl(struct ncr_lists* lst, struct file *filp, return ncr_data_set(&lst->data, (void*)arg); case NCRIO_DATA_DEINIT: return ncr_data_deinit(&lst->data, (void*)arg); + case NCRIO_KEY_INIT: return ncr_key_init(filp, &lst->key, (void*)arg); case NCRIO_KEY_DEINIT: return ncr_key_deinit(&lst->key, (void*)arg); -#if 0 case NCRIO_KEY_GENERATE: return ncr_key_generate(&lst->key, (void*)arg); + case NCRIO_KEY_EXPORT: + return ncr_key_export(&lst->data, &lst->key, (void*)arg); + case NCRIO_KEY_IMPORT: + return ncr_key_import(&lst->data, &lst->key, (void*)arg); + case NCRIO_KEY_GET_INFO: + return ncr_key_info(&lst->key, (void*)arg); +#if 0 case NCRIO_KEY_GENERATE_PAIR: return ncr_key_generate_pair(&lst->key, (void*)arg); case NCRIO_KEY_DERIVE: return ncr_key_derive(&lst->key, (void*)arg); - case NCRIO_KEY_EXPORT: - return ncr_key_export(&lst->key, (void*)arg); - case NCRIO_KEY_IMPORT: - return ncr_key_import(&lst->key, (void*)arg); case NCRIO_KEY_GET_PUBLIC: return ncr_key_get_public(&lst->key, (void*)arg); #endif @@ -105,5 +108,30 @@ ncr_ioctl(struct ncr_lists* lst, struct file *filp, } } +/* Returns NCR_KEY_TYPE_SECRET if a secret key algorithm or MAC is given, + * and NCR_KEY_TYPE_PUBLIC if a public key algorithm is given. + */ +ncr_key_type_t ncr_algorithm_to_key_type(ncr_algorithm_t algo) +{ + switch(algo) { + case NCR_ALG_3DES_CBC: + case NCR_ALG_AES_CBC: + case NCR_ALG_CAMELLIA_CBC: + case NCR_ALG_ARCFOUR: + case NCR_ALG_HMAC_SHA1: + case NCR_ALG_HMAC_MD5: + case NCR_ALG_HMAC_SHA2_224: + case NCR_ALG_HMAC_SHA2_256: + case NCR_ALG_HMAC_SHA2_384: + case NCR_ALG_HMAC_SHA2_512: + return NCR_KEY_TYPE_SECRET; + case NCR_ALG_RSA: + case NCR_ALG_DSA: + return NCR_KEY_TYPE_PUBLIC; + default: + return NCR_KEY_TYPE_INVALID; + } + +} @@ -24,10 +24,14 @@ typedef enum { NCR_ALG_HMAC_SHA2_256, NCR_ALG_HMAC_SHA2_384, NCR_ALG_HMAC_SHA2_512, + + NCR_ALG_RSA=140, + NCR_ALG_DSA, } ncr_algorithm_t; typedef enum { + NCR_KEY_TYPE_INVALID, NCR_KEY_TYPE_SECRET=1, NCR_KEY_TYPE_PUBLIC=2, NCR_KEY_TYPE_PRIVATE=3, @@ -79,12 +83,14 @@ typedef int ncr_key_t; #define NCR_KEY_FLAG_SIGN (1<<3) struct ncr_key_generate_params_st { - ncr_algorithm_t algorithm; + ncr_algorithm_t algorithm; /* just a cipher algorithm when + * generating secret keys + */ unsigned int keyflags; union { struct { unsigned int bits; - } cipher; + } secret; struct { unsigned int bits; void* e; @@ -143,6 +149,12 @@ struct ncr_key_info_st { struct ncr_key_data_st { ncr_key_t key; ncr_data_t data; + /* in case of import this will be used as key id */ + uint8_t key_id[MAX_KEY_ID_SIZE]; + size_t key_id_size; + ncr_key_type_t type; + unsigned int flags; + ncr_algorithm_t algorithm; /* valid for public/private keys */ }; struct ncr_public_key_params_st @@ -180,13 +192,21 @@ struct ncr_public_key_params_st }; #define NCRIO_KEY_INIT _IOW ('c', 204, ncr_key_t) +/* generate a secret key */ #define NCRIO_KEY_GENERATE _IOR ('c', 205, struct ncr_key_generate_st) +/* generate a public key pair */ #define NCRIO_KEY_GENERATE_PAIR _IOR ('c', 206, struct ncr_key_generate_st) +/* derive a new key from an old one */ #define NCRIO_KEY_DERIVE _IOR ('c', 207, struct ncr_key_params_st) +/* return information on a key */ #define NCRIO_KEY_GET_INFO _IOWR('c', 208, struct ncr_key_info_st) +/* export a secret key */ #define NCRIO_KEY_EXPORT _IOWR('c', 209, struct ncr_key_data_st) +/* import a secret key */ #define NCRIO_KEY_IMPORT _IOWR('c', 210, struct ncr_key_data_st) +/* return/set public /private paramters */ #define NCRIO_KEY_GET_PUBLIC _IOWR('c', 211, struct ncr_public_key_params_st) + #define NCRIO_KEY_DEINIT _IOR ('c', 212, ncr_key_t) diff --git a/ncr_int.h b/ncr_int.h index 58fda2255cd..1b4954031ef 100644 --- a/ncr_int.h +++ b/ncr_int.h @@ -73,16 +73,22 @@ int ncr_data_get(struct list_sem_st*, void __user* arg); int ncr_data_deinit(struct list_sem_st*, void __user* arg); int ncr_data_init(struct file* filp, struct list_sem_st*, void __user* arg); void ncr_data_list_deinit(struct list_sem_st*); +struct data_item* ncr_data_item_get( struct list_sem_st* lst, ncr_data_t desc); +void _ncr_data_item_put( struct data_item* item); int ncr_key_init(struct file* filp, struct list_sem_st*, void __user* arg); -int ncr_key_generate(struct list_sem_st*, void __user* arg); +int ncr_key_deinit(struct list_sem_st*, void __user* arg); +int ncr_key_export(struct list_sem_st* data_lst, + struct list_sem_st* key_lst,void __user* arg); +int ncr_key_import(struct list_sem_st* data_lst, + struct list_sem_st* key_lst,void __user* arg); +void ncr_key_list_deinit(struct list_sem_st* lst); +int ncr_key_generate(struct list_sem_st* data_lst, void __user* arg); +int ncr_key_info(struct list_sem_st*, void __user* arg); + int ncr_key_generate_pair(struct list_sem_st* lst, void __user* arg); int ncr_key_derive(struct list_sem_st*, void __user* arg); -int ncr_key_export(struct list_sem_st*, void __user* arg); -int ncr_key_import(struct list_sem_st*, void __user* arg); int ncr_key_get_public(struct list_sem_st* lst, void __user* arg); -int ncr_key_deinit(struct list_sem_st*, void __user* arg); -void ncr_key_list_deinit(struct list_sem_st* lst); typedef enum { LIMIT_TYPE_KEY, @@ -93,4 +99,6 @@ void ncr_limits_remove(struct file *filp, limits_type_t type); int ncr_limits_add_and_check(struct file *filp, limits_type_t type); void ncr_limits_init(void); +ncr_key_type_t ncr_algorithm_to_key_type(ncr_algorithm_t algo); + #endif diff --git a/userspace/ncrypto.h b/userspace/ncrypto.h index 77f8263b069..546b6ba6640 100644 --- a/userspace/ncrypto.h +++ b/userspace/ncrypto.h @@ -48,6 +48,14 @@ int ncr_key_import(ncr_key_t key, ncr_data_t obj); /* ioctl KEY_IMPORT */ int ncr_key_get_id(ncr_key_t, void* id, size_t* id_size); /* KEY_GET_INFO */ void ncr_key_deinit(ncr_key_t); /* ioctl KEY_DEINIT */ +typedef enum { + NCR_RSA_MODULUS, + NCR_RSA_EXPONENT, + NCR_DSA_P, + NCR_DSA_Q, + NCR_DSA_Y, +} ncr_public_param_t; + int ncr_key_get_public_param(ncr_key_t key, ncr_public_param_t, void* output, size_t* output_size); /* store keys */ |