📄 cryptodev.c
字号:
/* $OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $ *//* * The linux port of this code done by David McCullough <davidm@snapgear.com> * The license and original author are listed below. * Copyright (C) 2004 David McCullough <davidm@snapgear.com> * * Copyright (c) 2001 Theo de Raadt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Effort sponsored in part by the Defense Advanced Research Projects * Agency (DARPA) and Air Force Research Laboratory, Air Force * Materiel Command, USAF, under agreement number F30602-01-2-0537. */static int errno = -1;#define __KERNEL_SYSCALLS__ 1#include <linux/config.h>#include <linux/types.h>#include <linux/time.h>#include <linux/list.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/unistd.h>#include <linux/module.h>#include <linux/wait.h>#include <linux/slab.h>#include <linux/fs.h>#include <linux/file.h>#include <linux/miscdevice.h>#include <asm/uaccess.h>#include <cryptodev.h>#include <uio.h>static int debug = 0;MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "Enable debug");static int crypto_devsel = 0;MODULE_PARM(crypto_devsel, "i");MODULE_PARM_DESC(crypto_devsel, "Select cryptodev drivers: -1=software only, 1=HW only, 0=any");struct csession_info { u_int16_t blocksize; u_int16_t minkey, maxkey; u_int16_t keysize; /* u_int16_t hashsize; */ u_int16_t authsize; /* u_int16_t ctxsize; */};struct csession { struct list_head list; u_int64_t sid; u_int32_t ses; wait_queue_head_t waitq; u_int32_t cipher; u_int32_t mac; caddr_t key; int keylen; u_char tmp_iv[EALG_MAX_BLOCK_LEN]; caddr_t mackey; int mackeylen; u_char tmp_mac[CRYPTO_MAX_MAC_LEN]; struct csession_info info; struct iovec iovec; struct uio uio; int error;};struct fcrypt { struct list_head csessions; int sesn;};static struct csession *csefind(struct fcrypt *, u_int);static int csedelete(struct fcrypt *, struct csession *);static struct csession *cseadd(struct fcrypt *, struct csession *);static struct csession *csecreate(struct fcrypt *, u_int64_t, struct cryptoini *crie, struct cryptoini *cria, struct csession_info *);static int csefree(struct csession *);static int cryptodev_op(struct csession *, struct crypt_op *);static int cryptodev_key(struct crypt_kop *);static int cryptodev_cb(void *);static intcryptodev_op(struct csession *cse, struct crypt_op *cop){ struct cryptop *crp = NULL; struct cryptodesc *crde = NULL, *crda = NULL; int error; dprintk("%s()\n", __FUNCTION__); if (cop->len > 256*1024-4) { dprintk("%s: %d > 256k\n", __FUNCTION__, cop->len); return (E2BIG); } if (cse->info.blocksize && (cop->len % cse->info.blocksize) != 0) { dprintk("%s: blocksize=%d len=%d\n", __FUNCTION__, cse->info.blocksize, cop->len); return (EINVAL); } cse->uio.uio_iov = &cse->iovec; cse->uio.uio_iovcnt = 1; cse->uio.uio_offset = 0;#if 0 cse->uio.uio_resid = cop->len; cse->uio.uio_segflg = UIO_SYSSPACE; cse->uio.uio_rw = UIO_WRITE; cse->uio.uio_td = td;#endif cse->uio.uio_iov[0].iov_len = cop->len; cse->uio.uio_iov[0].iov_base = kmalloc(cop->len, GFP_KERNEL); crp = crypto_getreq((cse->info.blocksize != 0) + (cse->info.authsize != 0)); if (crp == NULL) { dprintk("%s: ENOMEM\n", __FUNCTION__); error = ENOMEM; goto bail; } if (cse->info.authsize) { crda = crp->crp_desc; if (cse->info.blocksize) crde = crda->crd_next; } else { if (cse->info.blocksize) crde = crp->crp_desc; else { dprintk("%s: bad request\n", __FUNCTION__); error = EINVAL; goto bail; } } if ((error = copy_from_user(cse->uio.uio_iov[0].iov_base, cop->src, cop->len))) { dprintk("%s: bad copy\n", __FUNCTION__); goto bail; } if (crda) { crda->crd_skip = 0; crda->crd_len = cop->len; crda->crd_inject = 0; /* ??? */ crda->crd_alg = cse->mac; crda->crd_key = cse->mackey; crda->crd_klen = cse->mackeylen * 8; } if (crde) { if (cop->op == COP_ENCRYPT) crde->crd_flags |= CRD_F_ENCRYPT; else crde->crd_flags &= ~CRD_F_ENCRYPT; crde->crd_len = cop->len; crde->crd_inject = 0; crde->crd_alg = cse->cipher; crde->crd_key = cse->key; crde->crd_klen = cse->keylen * 8; } crp->crp_ilen = cop->len; crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM | (cop->flags & COP_F_BATCH); crp->crp_buf = (caddr_t)&cse->uio; crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb; crp->crp_sid = cse->sid; crp->crp_opaque = (void *)cse; if (cop->iv) { if (crde == NULL) { error = EINVAL; dprintk("%s no crde\n", __FUNCTION__); goto bail; } if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */ error = EINVAL; dprintk("%s arc4 with IV\n", __FUNCTION__); goto bail; } if ((error = copy_from_user(cse->tmp_iv, cop->iv, cse->info.blocksize))) { dprintk("%s bad iv copy\n", __FUNCTION__); goto bail; } memcpy(crde->crd_iv, cse->tmp_iv, cse->info.blocksize); crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT; crde->crd_skip = 0; } else if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */ crde->crd_skip = 0; } else if (crde) { crde->crd_flags |= CRD_F_IV_PRESENT; crde->crd_skip = cse->info.blocksize; crde->crd_len -= cse->info.blocksize; } if (cop->mac) { if (crda == NULL) { error = EINVAL; dprintk("%s no crda\n", __FUNCTION__); goto bail; } crp->crp_mac=cse->tmp_mac; } /* * Let the dispatch run unlocked, then, interlock against the * callback before checking if the operation completed and going * to sleep. This insures drivers don't inherit our lock which * results in a lock order reversal between crypto_dispatch forced * entry and the crypto_done callback into us. */ error = crypto_dispatch(crp); if (error == 0) { dprintk("%s about to WAIT\n", __FUNCTION__); /* * we really need to wait for driver to complete to maintain * state, luckily interrupts will be remembered */ do { error = wait_event_interruptible(crp->crp_waitq, ((crp->crp_flags & CRYPTO_F_DONE) != 0)); error = -error; } while ((crp->crp_flags & CRYPTO_F_DONE) == 0); dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error); } if (crp->crp_etype != 0) { error = crp->crp_etype; dprintk("%s error in crp processing\n", __FUNCTION__); goto bail; } if (cse->error) { error = cse->error; dprintk("%s error in cse processing\n", __FUNCTION__); goto bail; } if (cop->dst && (error = copy_to_user(cop->dst, cse->uio.uio_iov[0].iov_base, cop->len))) { dprintk("%s bad dst copy\n", __FUNCTION__); goto bail; } if (cop->mac && (error=copy_to_user(cop->mac, crp->crp_mac, cse->info.authsize))) { dprintk("%s bad mac copy\n", __FUNCTION__); goto bail; }bail: if (crp) crypto_freereq(crp); if (cse->uio.uio_iov[0].iov_base) kfree(cse->uio.uio_iov[0].iov_base); return (error);}static intcryptodev_cb(void *op){ struct cryptop *crp = (struct cryptop *) op; struct csession *cse = (struct csession *)crp->crp_opaque; dprintk("%s()\n", __FUNCTION__); cse->error = crp->crp_etype; if (crp->crp_etype == EAGAIN) { crp->crp_flags &= ~CRYPTO_F_DONE;#ifdef NOTYET /* * DAVIDM I am fairly sure that we should turn this into a batch * request to stop bad karma/lockup, revisit */ crp->crp_flags |= CRYPTO_F_BATCH;#endif return crypto_dispatch(crp); } wake_up_interruptible(&crp->crp_waitq); return (0);}static intcryptodevkey_cb(void *op){ struct cryptkop *krp = (struct cryptkop *) op; dprintk("%s()\n", __FUNCTION__); wake_up_interruptible(&krp->krp_waitq); return (0);}static intcryptodev_key(struct crypt_kop *kop){ struct cryptkop *krp = NULL; int error = EINVAL; int in, out, size, i; dprintk("%s()\n", __FUNCTION__); if (kop->crk_iparams + kop->crk_oparams > CRK_MAXPARAM) { dprintk("%s params too big\n", __FUNCTION__); return (EFBIG); } in = kop->crk_iparams; out = kop->crk_oparams; switch (kop->crk_op) { case CRK_MOD_EXP: if (in == 3 && out == 1) break; return (EINVAL); case CRK_MOD_EXP_CRT: if (in == 6 && out == 1) break; return (EINVAL); case CRK_DSA_SIGN: if (in == 5 && out == 2) break; return (EINVAL); case CRK_DSA_VERIFY: if (in == 7 && out == 0) break; return (EINVAL); case CRK_DH_COMPUTE_KEY: if (in == 3 && out == 1) break; return (EINVAL); default: return (EINVAL); } krp = (struct cryptkop *)kmalloc(sizeof *krp, GFP_KERNEL); if (!krp) return (ENOMEM); memset(krp, 0, sizeof *krp); krp->krp_op = kop->crk_op; krp->krp_status = kop->crk_status; krp->krp_iparams = kop->crk_iparams; krp->krp_oparams = kop->crk_oparams; krp->krp_status = 0; krp->krp_callback = (int (*) (struct cryptkop *)) cryptodevkey_cb; init_waitqueue_head(&krp->krp_waitq); for (i = 0; i < CRK_MAXPARAM; i++) krp->krp_param[i].crp_nbits = kop->crk_param[i].crp_nbits; for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) { size = (krp->krp_param[i].crp_nbits + 7) / 8; if (size == 0) continue; krp->krp_param[i].crp_p = (caddr_t) kmalloc(size, GFP_KERNEL); if (i >= krp->krp_iparams) continue; error = copy_from_user(krp->krp_param[i].crp_p, kop->crk_param[i].crp_p, size); if (error) goto fail; } error = crypto_kdispatch(krp); if (error) goto fail; interruptible_sleep_on(&krp->krp_waitq); if (krp->krp_status != 0) { error = krp->krp_status; goto fail; } for (i = krp->krp_iparams; i < krp->krp_iparams + krp->krp_oparams; i++) { size = (krp->krp_param[i].crp_nbits + 7) / 8; if (size == 0) continue; error = copy_to_user(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p, size); if (error)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -