summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--cryptodev_main.c53
-rw-r--r--ncr.c141
-rw-r--r--ncr.h325
-rw-r--r--ncr_int.h27
5 files changed, 529 insertions, 19 deletions
diff --git a/Makefile b/Makefile
index af7d38d..9b8d965 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
KERNEL_DIR = /lib/modules/$(shell uname -r)/build
VERSION = 0.1
-cryptodev-objs = cryptodev_main.o cryptodev_cipher.o
+cryptodev-objs = cryptodev_main.o cryptodev_cipher.o ncr.o
obj-m += cryptodev.o
diff --git a/cryptodev_main.c b/cryptodev_main.c
index 9a1f918..9a6cb1c 100644
--- a/cryptodev_main.c
+++ b/cryptodev_main.c
@@ -39,6 +39,7 @@
#include <asm/ioctl.h>
#include <linux/scatterlist.h>
#include "cryptodev_int.h"
+#include "ncr_int.h"
MODULE_AUTHOR("Nikos Mavrogiannopoulos <nmav@gnutls.org>");
MODULE_DESCRIPTION("CryptoDev driver");
@@ -61,6 +62,15 @@ MODULE_PARM_DESC(enable_stats, "collect statictics about cryptodev usage");
#endif
/* ====== CryptoAPI ====== */
+struct fcrypt {
+ struct list_head list;
+ struct semaphore sem;
+};
+
+struct crypt_priv {
+ void * ncr;
+ struct fcrypt fcrypt;
+};
#define FILL_SG(sg,ptr,len) \
do { \
@@ -85,11 +95,6 @@ struct csession {
#endif
};
-struct fcrypt {
- struct list_head list;
- struct semaphore sem;
-};
-
/* Prepare session for future use. */
static int
crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
@@ -494,27 +499,36 @@ out_unlock:
static int
cryptodev_open(struct inode *inode, struct file *filp)
{
- struct fcrypt *fcr;
+ struct crypt_priv *pcr;
+ int ret;
- fcr = kmalloc(sizeof(*fcr), GFP_KERNEL);
- if(!fcr)
+ pcr = kmalloc(sizeof(*pcr), GFP_KERNEL);
+ if(!pcr)
return -ENOMEM;
- memset(fcr, 0, sizeof(*fcr));
- init_MUTEX(&fcr->sem);
- INIT_LIST_HEAD(&fcr->list);
- filp->private_data = fcr;
+ memset(pcr, 0, sizeof(*pcr));
+ init_MUTEX(&pcr->fcrypt->sem);
+ INIT_LIST_HEAD(&fcr->fcrypt->list);
+
+
+ pcr->ncr = ncr_init_lists();
+ if (pcr->ncr == NULL) {
+ kfree(pcr);
+ return -ENOMEM;
+ }
+ filp->private_data = pcr;
return 0;
}
static int
cryptodev_release(struct inode *inode, struct file *filp)
{
- struct fcrypt *fcr = filp->private_data;
+ struct crypt_priv *fcr = filp->private_data;
if(fcr) {
crypto_finish_all_sessions(fcr);
+ ncr_deinit_lists(fcr->ncr);
kfree(fcr);
filp->private_data = NULL;
}
@@ -544,10 +558,16 @@ cryptodev_ioctl(struct inode *inode, struct file *filp,
int __user *p = (void __user *)arg;
struct session_op sop;
struct crypt_op cop;
- struct fcrypt *fcr = filp->private_data;
+ struct crypt_priv *pcr = filp->private_data;
+ struct fcrypt * fcr;
uint32_t ses;
int ret, fd;
+ if (unlikely(!pcr))
+ BUG();
+
+ fcr = pcr->fcr;
+
if (unlikely(!fcr))
BUG();
@@ -559,19 +579,16 @@ cryptodev_ioctl(struct inode *inode, struct file *filp,
fd = clonefd(filp);
put_user(fd, p);
return 0;
-
case CIOCGSESSION:
ret = copy_from_user(&sop, (void*)arg, sizeof(sop));
ret |= crypto_create_session(fcr, &sop);
if (unlikely(ret))
return ret;
return copy_to_user((void*)arg, &sop, sizeof(sop));
-
case CIOCFSESSION:
get_user(ses, (uint32_t*)arg);
ret = crypto_finish_session(fcr, ses);
return ret;
-
case CIOCCRYPT:
ret = copy_from_user(&cop, (void*)arg, sizeof(cop));
ret |= crypto_run(fcr, &cop);
@@ -580,7 +597,7 @@ cryptodev_ioctl(struct inode *inode, struct file *filp,
return copy_to_user((void*)arg, &cop, sizeof(cop));
default:
- return -EINVAL;
+ return ncr_ioctl(file->f_cred->fsuid, pcr->ncr, cmd, arg);
}
}
diff --git a/ncr.c b/ncr.c
new file mode 100644
index 0000000..a434d40
--- /dev/null
+++ b/ncr.c
@@ -0,0 +1,141 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+
+ * Copyright (c) 2009,2010 Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * cryptodev is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cryptodev 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#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>
+#include <linux/scatterlist.h>
+#include "ncr.h"
+#include "ncr_int.h"
+
+
+
+void* ncr_init_lists(void)
+{
+ struct ncr_lists *lst;
+ int ret;
+
+ lst = kmalloc(sizeof(*lst), GFP_KERNEL);
+ if(!lst)
+ return NULL;
+
+ memset(lst, 0, sizeof(*lst));
+
+ init_MUTEX(&lst->data_sem);
+ INIT_LIST_HEAD(&lst->data_list);
+
+ return lst;
+}
+
+void ncr_deinit_lists(struct ncr_lists *lst)
+{
+ if(lst) {
+ //data_clear_all(list->data);
+ kfree(lst);
+ }
+
+}
+
+/* must be called with data semaphore down
+ */
+static ncr_data_t _ncr_data_get_new_desc( struct ncr_lists* lst)
+{
+struct data_item* item;
+int mx = 0;
+
+ list_for_each(item, &lst->data_list) {
+ mx = max(mx, item->desc);
+ }
+ mx++;
+
+ return mx;
+}
+
+void* data_alloc(unsigned int uid, size_t size)
+{
+ /* FIXME: implement a maximum memory limit per user */
+ if (size > 64*1024) {
+ return NULL;
+ }
+ return kmalloc(GPF_KERNEL, size);
+}
+
+int ncr_data_new(unsigned int uid, struct ncr_lists* lst, void __user* arg)
+{
+ struct ncr_data_init_st init;
+ struct data_item* data;
+
+ copy_from_user( &init, arg, sizeof(init));
+
+ data = kmalloc(GPF_KERNEL, sizeof(*data));
+ if (data == NULL) {
+ return -ENOMEM;
+ }
+
+ memset(data, 0, sizeof(*data));
+ init_MUTEX(&data->sem);
+
+ data->flags = init.flags;
+
+ data->data = data_alloc(uid, init.max_data_size);
+ if (data->data == NULL) {
+ kfree(data);
+ return -ENOMEM;
+ }
+ data->max_data_size = init.max_data_size;
+
+ down(lst->data_sem);
+
+ data->desc = _ncr_data_get_new_desc(lst);
+
+ list_add(data, &list->data_list);
+
+ up(lst->data_sem);
+
+ init.desc = data->desc;
+
+}
+
+int
+ncr_ioctl(unsigned int uid, struct ncr_lists* lst,
+ unsigned int cmd, unsigned long arg)
+{
+
+ if (unlikely(!lst))
+ BUG();
+
+ switch (cmd) {
+ case NCRIO_DATA_INIT:
+ return ncr_data_new(uid, lst, arg);
+ case NCRIO_DATA_GET:
+ case NCRIO_DATA_SET:
+ case NCRIO_DATA_DEINIT:
+ default:
+ return -EINVAL;
+ }
+}
+
+
+
diff --git a/ncr.h b/ncr.h
new file mode 100644
index 0000000..5df6125
--- /dev/null
+++ b/ncr.h
@@ -0,0 +1,325 @@
+/* This is a source compatible implementation with the original API of
+ * cryptodev by Angelos D. Keromytis, found at openbsd cryptodev.h.
+ * Placed under public domain */
+
+#ifndef L_NCRYPTODEV_H
+#define L_NCRYPTODEV_H
+
+#ifndef __KERNEL__
+#include <inttypes.h>
+#endif
+
+typedef enum {
+ NCR_ALG_3DES_CBC=2,
+ NCR_ALG_AES_CBC,
+ NCR_ALG_CAMELLIA_CBC,
+ NCR_ALG_ARCFOUR,
+
+ NCR_ALG_SHA1=40,
+ NCR_ALG_MD5,
+ NCR_ALG_SHA2_224,
+ NCR_ALG_SHA2_256,
+ NCR_ALG_SHA2_384,
+ NCR_ALG_SHA2_512,
+
+ NCR_ALG_HMAC_SHA1=80,
+ NCR_ALG_HMAC_MD5,
+ NCR_ALG_HMAC_SHA2_224,
+ NCR_ALG_HMAC_SHA2_256,
+ NCR_ALG_HMAC_SHA2_384,
+ NCR_ALG_HMAC_SHA2_512,
+} ncr_algorithm_t;
+
+
+typedef enum {
+ NCR_KEY_TYPE_SECRET=1;
+ NCR_KEY_TYPE_PUBLIC=2;
+ NCR_KEY_TYPE_PRIVATE=3;
+} ncr_key_type_t;
+
+/* Data Handling
+ */
+#define NCR_DATA_FLAG_EXPORTABLE 1
+#define NCR_DATA_FLAG_SIGN_ONLY 2 /* this object can only be used with hash/sign operations */
+
+typedef int ncr_data_t;
+#define NCR_DATA_INVALID (ncr_data_t)(-1)
+
+struct ncr_data_init_st {
+ ncr_data_t desc;
+ size_t max_object_size;
+ unsigned int flags;
+};
+
+struct ncr_data_st {
+ ncr_data_t desc;
+ void* data;
+ size_t data_size;
+ unsigned int append_flag; /* only when used with NCRIO_DATA_SET */
+};
+
+#define NCRIO_DATA_INIT _IOWR('c', 200, struct ncr_data_init_st)
+#define NCRIO_DATA_GET _IOWR('c', 201, struct ncr_data_st)
+#define NCRIO_DATA_SET _IOR('c', 202, struct ncr_data_st)
+#define NCRIO_DATA_DEINIT _IOR('c', 203, ncr_data_t)
+
+/* Key handling
+ */
+
+typedef int ncr_key_t;
+
+#define NCR_KEY_INVALID (api_key_t)(-1)
+
+#define NCR_KEY_FLAG_EXPORTABLE 1
+#define NCR_KEY_FLAG_WRAPPABLE (1<<1)
+/* when generating a pair the flags correspond to private
+ * and public key usage is implicit. For example when private
+ * key can decrypt then public key can encrypt. If private key
+ * can sign then public key can verify.
+ */
+#define NCR_KEY_FLAG_DECRYPT (1<<2)
+#define NCR_KEY_FLAG_SIGN (1<<3)
+
+struct ncr_key_generate_st {
+ ncr_key_t desc;
+ ncr_algorithm_t algorithm;
+ unsigned int bits;
+ unsigned int keyflags;
+};
+
+struct ncr_key_generate_st {
+ ncr_key_t desc; /* input */
+ ncr_algorithm_t algorithm; /* input */
+ unsigned int bits; /* input */
+
+};
+
+struct ncr_key_generate_params_st {
+ ncr_algorithm_t algorithm;
+ unsigned int keyflags;
+ union {
+ struct {
+ unsigned int bits;
+ } cipher;
+ struct {
+ unsigned int bits;
+ void* e;
+ size_t e_size;
+ } rsa;
+ struct {
+ unsigned int bits;
+ } dsa;
+ struct {
+ unsigned int bits;
+ } dh;
+ } params;
+};
+
+/* used in generation
+ */
+struct ncr_key_generate_st {
+ ncr_key_t desc;
+ ncr_key_t desc2; /* when called with GENERATE_PAIR */
+ ncr_key_generate_params_st params;
+};
+
+/* used in derivation/encryption
+ */
+struct ncr_key_params_st {
+ ncr_key_t oldkey;
+ ncr_key_t newkey;
+
+ unsigned int keyflags; /* for new key */
+
+ union {
+ struct {
+ void* iv;
+ size_t iv_size;
+ } cipher;
+ struct {
+ void * peer_public;
+ size_t peer_public_size;
+ } dh;
+ } params;
+};
+
+#define MAX_KEY_ID_SIZE 20
+
+struct ncr_key_info_st {
+ ncr_key_t key; /* input */
+
+ unsigned int flags;
+ ncr_key_type_t type;
+ ncr_algorithm_t algorithm; /* valid for public/private keys */
+
+ uint8_t key_id[MAX_KEY_ID_SIZE];
+ size_t key_id_size;
+};
+
+struct ncr_key_data_st {
+ ncr_key_t key;
+ ncr_data_t data;
+};
+
+struct ncr_public_key_params_st
+{
+ ncr_key_t key;
+ ncr_key_type_t type;
+ union {
+ struct {
+ void* m;
+ size_t m_size;
+ void* e;
+ size_t e_size;
+ void* p;
+ size_t p_size;
+ void* q;
+ size_t q_size;
+ void* c;
+ size_t c_size;
+ } rsa;
+ struct {
+ void* y;
+ size_t y_size;
+ void* p;
+ size_t p_size;
+ void* q;
+ size_t q_size;
+ void* g;
+ size_t g_size;
+ } dsa;
+ struct {
+ void* public;
+ size_t public_size;
+ } dh;
+ } params;
+};
+
+#define NCRIO_KEY_INIT _IOW ('c', 204, ncr_key_t)
+#define NCRIO_KEY_GENERATE _IOR ('c', 205, struct ncr_key_generate_st)
+#define NCRIO_KEY_GENERATE_PAIR _IOR ('c', 206, struct ncr_key_generate_st)
+#define NCRIO_KEY_DERIVE _IOR ('c', 207, struct ncr_key_params_st)
+#define NCRIO_KEY_GET_INFO _IOWR('c', 208, struct ncr_key_info_st)
+#define NCRIO_KEY_EXPORT _IOWR('c', 209, struct ncr_key_data_st)
+#define NCRIO_KEY_IMPORT _IOWR('c', 210, struct ncr_key_data_st)
+#define NCRIO_KEY_GET_PUBLIC _IOWR('c', 211, struct ncr_public_key_params_st)
+#define NCRIO_DATA_DEINIT _IOR ('c', 212, ncr_data_t)
+
+
+/* Storage ioctls
+ */
+#define MAX_LABEL_SIZE 128
+
+struct ncr_storage_st {
+ ncr_key_t key;
+ char label[MAX_LABEL_SIZE]; /* or template */
+ mode_t mode;
+};
+
+struct ncr_storage_metadata_st {
+ char label[MAX_LABEL_SIZE];
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
+
+ api_algorithm_t algorithm;
+ api_key_type_t type;
+
+ uint8_t key_id[MAX_KEY_ID_SIZE];
+ size_t key_id_size;
+};
+
+struct ncr_storage_chown_st {
+ char label[MAX_LABEL_SIZE];
+ uid_t uid;
+ gid_t gid;
+};
+
+struct ncr_storage_chmod_st {
+ char label[MAX_LABEL_SIZE];
+ mode_t mode;
+};
+
+struct ncr_storage_remove_st {
+ char label[MAX_LABEL_SIZE];
+};
+
+
+#define NCRIO_STORAGE_STORE _IOW ('c', 220, struct ncr_storage_st)
+#define NCRIO_STORAGE_MKSTEMP _IOR ('c', 221, struct ncr_storage_st)
+#define NCRIO_STORAGE_LOAD _IOR ('c', 222, struct ncr_storage_st)
+#define NCRIO_STORAGE_CHMOD _IOR ('c', 223, struct ncr_storage_chmod_st)
+#define NCRIO_STORAGE_CHOWN _IOR ('c', 224, struct ncr_storage_chown_st)
+#define NCRIO_STORAGE_REMOVE _IOR('c', 225, struct ncr_storage_remove_st)
+#define NCRIO_STORAGE_LOAD_METADATA _IOWR ('c', 226, struct ncr_storage_metadata_st)
+
+struct ncr_storage_traverse_st {
+ int traverse_id;
+ ncr_storage_metadata_st metadata;
+};
+
+
+#define NCRIO_STORAGE_TRAVERSE_INIT _IOW('c', 227, int)
+#define NCRIO_STORAGE_TRAVERSE_NEXT _IOWR('c', 228, struct ncr_storage_traverse_st)
+#define NCRIO_STORAGE_TRAVERSE_NEXT _IOWR('c', 229, int)
+
+
+/* FIXME key wrap ioctls
+ */
+
+
+/* Crypto Operations ioctls
+ */
+
+typedef enum {
+ NCR_OP_ENCRYPT=1,
+ NCR_OP_DECRYPT,
+ NCR_OP_DIGEST,
+ NCR_OP_MAC,
+ NCR_OP_SIGN,
+ NCR_OP_VERIFY,
+} ncr_crypto_op_t;
+
+typedef int ncr_session_t;
+#define NCR_SESSION_INVALID (ncr_session_t)-1
+
+/* input of CIOCGSESSION */
+struct ncr_session_st {
+ /* input */
+ ncr_algorithm_t algorithm;
+ ncr_key_params_st params;
+ ncr_key_t key;
+ ncr_crypto_op_t op;
+
+ /* output */
+ ncr_session_t ses; /* session identifier */
+};
+
+typedef enum {
+ NCR_SUCCESS = 0,
+ NCR_ERROR_GENERIC = -1,
+} ncr_error_t;
+
+struct ncr_session_op_st {
+ /* input */
+ ncr_session_t ses;
+
+ union {
+ struct {
+ ncr_data_t plaintext;
+ ncr_data_t ciphertext;
+ } cipher;
+ struct {
+ ncr_data_t text;
+ ncr_data_t output;
+ } digest; /* mac/hash/sign */
+ struct {
+ ncr_data_t text;
+ ncr_data_t signature;
+ } verify; /* mac/hash/sign */
+ } data;
+
+ /* output */
+ ncr_error_t err;
+};
+
diff --git a/ncr_int.h b/ncr_int.h
new file mode 100644
index 0000000..4e9e25a
--- /dev/null
+++ b/ncr_int.h
@@ -0,0 +1,27 @@
+struct data_item {
+ struct list_head list;
+ void* data;
+ size_t data_size;
+ size_t max_data_size;
+ struct semaphore sem;
+ unsigned int flags;
+
+ ncr_data_t desc;
+};
+
+/* all the data associated with the open descriptor
+ * are here.
+ */
+struct ncr_lists {
+ struct list_head data_list;
+ struct semaphore data_sem;
+
+ /* sessions */
+ /* keys */
+};
+
+void* ncr_init_lists(void);
+void ncr_deinit_lists(struct ncr_lists *lst);
+
+int ncr_ioctl(struct ncr_lists* lists,
+ unsigned int cmd, unsigned long arg);