1104476Ssam/* $OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $ */ 2104476Ssam 3139825Simp/*- 4104476Ssam * Copyright (c) 2001 Theo de Raadt 5167755Ssam * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting 6104476Ssam * 7104476Ssam * Redistribution and use in source and binary forms, with or without 8104476Ssam * modification, are permitted provided that the following conditions 9104476Ssam * are met: 10104476Ssam * 11104476Ssam * 1. Redistributions of source code must retain the above copyright 12104476Ssam * notice, this list of conditions and the following disclaimer. 13104476Ssam * 2. Redistributions in binary form must reproduce the above copyright 14104476Ssam * notice, this list of conditions and the following disclaimer in the 15104476Ssam * documentation and/or other materials provided with the distribution. 16104476Ssam * 3. The name of the author may not be used to endorse or promote products 17104476Ssam * derived from this software without specific prior written permission. 18104476Ssam * 19104476Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20104476Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21104476Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22104476Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23104476Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24104476Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25104476Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26104476Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27104476Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28104476Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29104476Ssam * 30104476Ssam * Effort sponsored in part by the Defense Advanced Research Projects 31104476Ssam * Agency (DARPA) and Air Force Research Laboratory, Air Force 32104476Ssam * Materiel Command, USAF, under agreement number F30602-01-2-0537. 33104476Ssam */ 34104476Ssam 35116191Sobrien#include <sys/cdefs.h> 36116191Sobrien__FBSDID("$FreeBSD$"); 37116191Sobrien 38210631Skib#include "opt_compat.h" 39210631Skib 40104476Ssam#include <sys/param.h> 41104476Ssam#include <sys/systm.h> 42104476Ssam#include <sys/malloc.h> 43104476Ssam#include <sys/mbuf.h> 44104476Ssam#include <sys/lock.h> 45104476Ssam#include <sys/mutex.h> 46104476Ssam#include <sys/sysctl.h> 47104476Ssam#include <sys/file.h> 48104476Ssam#include <sys/filedesc.h> 49104476Ssam#include <sys/errno.h> 50104476Ssam#include <sys/uio.h> 51104476Ssam#include <sys/random.h> 52104476Ssam#include <sys/conf.h> 53104476Ssam#include <sys/kernel.h> 54129880Sphk#include <sys/module.h> 55104476Ssam#include <sys/fcntl.h> 56167755Ssam#include <sys/bus.h> 57104476Ssam 58104476Ssam#include <opencrypto/cryptodev.h> 59104476Ssam#include <opencrypto/xform.h> 60104476Ssam 61210631Skib#ifdef COMPAT_FREEBSD32 62210631Skib#include <sys/mount.h> 63210631Skib#include <compat/freebsd32/freebsd32.h> 64210631Skib 65210631Skibstruct session_op32 { 66210631Skib u_int32_t cipher; 67210631Skib u_int32_t mac; 68210631Skib u_int32_t keylen; 69210631Skib u_int32_t key; 70210631Skib int mackeylen; 71210631Skib u_int32_t mackey; 72210631Skib u_int32_t ses; 73210631Skib}; 74210631Skib 75210631Skibstruct session2_op32 { 76210631Skib u_int32_t cipher; 77210631Skib u_int32_t mac; 78210631Skib u_int32_t keylen; 79210631Skib u_int32_t key; 80210631Skib int mackeylen; 81210631Skib u_int32_t mackey; 82210631Skib u_int32_t ses; 83210631Skib int crid; 84210631Skib int pad[4]; 85210631Skib}; 86210631Skib 87210631Skibstruct crypt_op32 { 88210631Skib u_int32_t ses; 89210631Skib u_int16_t op; 90210631Skib u_int16_t flags; 91210631Skib u_int len; 92210631Skib u_int32_t src, dst; 93210631Skib u_int32_t mac; 94210631Skib u_int32_t iv; 95210631Skib}; 96210631Skib 97210631Skibstruct crparam32 { 98210631Skib u_int32_t crp_p; 99210631Skib u_int crp_nbits; 100210631Skib}; 101210631Skib 102210631Skibstruct crypt_kop32 { 103210631Skib u_int crk_op; 104210631Skib u_int crk_status; 105210631Skib u_short crk_iparams; 106210631Skib u_short crk_oparams; 107210631Skib u_int crk_crid; 108210631Skib struct crparam32 crk_param[CRK_MAXPARAM]; 109210631Skib}; 110210631Skib 111210631Skibstruct cryptotstat32 { 112210631Skib struct timespec32 acc; 113210631Skib struct timespec32 min; 114210631Skib struct timespec32 max; 115210631Skib u_int32_t count; 116210631Skib}; 117210631Skib 118210631Skibstruct cryptostats32 { 119210631Skib u_int32_t cs_ops; 120210631Skib u_int32_t cs_errs; 121210631Skib u_int32_t cs_kops; 122210631Skib u_int32_t cs_kerrs; 123210631Skib u_int32_t cs_intrs; 124210631Skib u_int32_t cs_rets; 125210631Skib u_int32_t cs_blocks; 126210631Skib u_int32_t cs_kblocks; 127210631Skib struct cryptotstat32 cs_invoke; 128210631Skib struct cryptotstat32 cs_done; 129210631Skib struct cryptotstat32 cs_cb; 130210631Skib struct cryptotstat32 cs_finis; 131210631Skib}; 132210631Skib 133210631Skib#define CIOCGSESSION32 _IOWR('c', 101, struct session_op32) 134210631Skib#define CIOCCRYPT32 _IOWR('c', 103, struct crypt_op32) 135210631Skib#define CIOCKEY32 _IOWR('c', 104, struct crypt_kop32) 136210631Skib#define CIOCGSESSION232 _IOWR('c', 106, struct session2_op32) 137210631Skib#define CIOCKEY232 _IOWR('c', 107, struct crypt_kop32) 138210631Skib 139210631Skibstatic void 140210631Skibsession_op_from_32(const struct session_op32 *from, struct session_op *to) 141210631Skib{ 142210631Skib 143210631Skib CP(*from, *to, cipher); 144210631Skib CP(*from, *to, mac); 145210631Skib CP(*from, *to, keylen); 146210631Skib PTRIN_CP(*from, *to, key); 147210631Skib CP(*from, *to, mackeylen); 148210631Skib PTRIN_CP(*from, *to, mackey); 149210631Skib CP(*from, *to, ses); 150210631Skib} 151210631Skib 152210631Skibstatic void 153210631Skibsession2_op_from_32(const struct session2_op32 *from, struct session2_op *to) 154210631Skib{ 155210631Skib 156210631Skib session_op_from_32((const struct session_op32 *)from, 157210631Skib (struct session_op *)to); 158210631Skib CP(*from, *to, crid); 159210631Skib} 160210631Skib 161210631Skibstatic void 162210631Skibsession_op_to_32(const struct session_op *from, struct session_op32 *to) 163210631Skib{ 164210631Skib 165210631Skib CP(*from, *to, cipher); 166210631Skib CP(*from, *to, mac); 167210631Skib CP(*from, *to, keylen); 168210631Skib PTROUT_CP(*from, *to, key); 169210631Skib CP(*from, *to, mackeylen); 170210631Skib PTROUT_CP(*from, *to, mackey); 171210631Skib CP(*from, *to, ses); 172210631Skib} 173210631Skib 174210631Skibstatic void 175210631Skibsession2_op_to_32(const struct session2_op *from, struct session2_op32 *to) 176210631Skib{ 177210631Skib 178210631Skib session_op_to_32((const struct session_op *)from, 179210631Skib (struct session_op32 *)to); 180210631Skib CP(*from, *to, crid); 181210631Skib} 182210631Skib 183210631Skibstatic void 184210631Skibcrypt_op_from_32(const struct crypt_op32 *from, struct crypt_op *to) 185210631Skib{ 186210631Skib 187210631Skib CP(*from, *to, ses); 188210631Skib CP(*from, *to, op); 189210631Skib CP(*from, *to, flags); 190210631Skib CP(*from, *to, len); 191210631Skib PTRIN_CP(*from, *to, src); 192210631Skib PTRIN_CP(*from, *to, dst); 193210631Skib PTRIN_CP(*from, *to, mac); 194210631Skib PTRIN_CP(*from, *to, iv); 195210631Skib} 196210631Skib 197210631Skibstatic void 198210631Skibcrypt_op_to_32(const struct crypt_op *from, struct crypt_op32 *to) 199210631Skib{ 200210631Skib 201210631Skib CP(*from, *to, ses); 202210631Skib CP(*from, *to, op); 203210631Skib CP(*from, *to, flags); 204210631Skib CP(*from, *to, len); 205210631Skib PTROUT_CP(*from, *to, src); 206210631Skib PTROUT_CP(*from, *to, dst); 207210631Skib PTROUT_CP(*from, *to, mac); 208210631Skib PTROUT_CP(*from, *to, iv); 209210631Skib} 210210631Skib 211210631Skibstatic void 212210631Skibcrparam_from_32(const struct crparam32 *from, struct crparam *to) 213210631Skib{ 214210631Skib 215210631Skib PTRIN_CP(*from, *to, crp_p); 216210631Skib CP(*from, *to, crp_nbits); 217210631Skib} 218210631Skib 219210631Skibstatic void 220210631Skibcrparam_to_32(const struct crparam *from, struct crparam32 *to) 221210631Skib{ 222210631Skib 223210631Skib PTROUT_CP(*from, *to, crp_p); 224210631Skib CP(*from, *to, crp_nbits); 225210631Skib} 226210631Skib 227210631Skibstatic void 228210631Skibcrypt_kop_from_32(const struct crypt_kop32 *from, struct crypt_kop *to) 229210631Skib{ 230210631Skib int i; 231210631Skib 232210631Skib CP(*from, *to, crk_op); 233210631Skib CP(*from, *to, crk_status); 234210631Skib CP(*from, *to, crk_iparams); 235210631Skib CP(*from, *to, crk_oparams); 236210631Skib CP(*from, *to, crk_crid); 237210631Skib for (i = 0; i < CRK_MAXPARAM; i++) 238210631Skib crparam_from_32(&from->crk_param[i], &to->crk_param[i]); 239210631Skib} 240210631Skib 241210631Skibstatic void 242210631Skibcrypt_kop_to_32(const struct crypt_kop *from, struct crypt_kop32 *to) 243210631Skib{ 244210631Skib int i; 245210631Skib 246210631Skib CP(*from, *to, crk_op); 247210631Skib CP(*from, *to, crk_status); 248210631Skib CP(*from, *to, crk_iparams); 249210631Skib CP(*from, *to, crk_oparams); 250210631Skib CP(*from, *to, crk_crid); 251210631Skib for (i = 0; i < CRK_MAXPARAM; i++) 252210631Skib crparam_to_32(&from->crk_param[i], &to->crk_param[i]); 253210631Skib} 254210631Skib#endif 255210631Skib 256104476Ssamstruct csession { 257104476Ssam TAILQ_ENTRY(csession) next; 258104476Ssam u_int64_t sid; 259104476Ssam u_int32_t ses; 260115746Ssam struct mtx lock; /* for op submission */ 261104476Ssam 262104476Ssam u_int32_t cipher; 263104476Ssam struct enc_xform *txform; 264104476Ssam u_int32_t mac; 265104476Ssam struct auth_hash *thash; 266104476Ssam 267104476Ssam caddr_t key; 268104476Ssam int keylen; 269104476Ssam u_char tmp_iv[EALG_MAX_BLOCK_LEN]; 270104476Ssam 271104476Ssam caddr_t mackey; 272104476Ssam int mackeylen; 273104476Ssam 274122908Ssam struct iovec iovec; 275104476Ssam struct uio uio; 276104476Ssam int error; 277104476Ssam}; 278104476Ssam 279104476Ssamstruct fcrypt { 280104476Ssam TAILQ_HEAD(csessionlist, csession) csessions; 281104476Ssam int sesn; 282104476Ssam}; 283104476Ssam 284104476Ssamstatic int cryptof_rw(struct file *fp, struct uio *uio, 285104476Ssam struct ucred *cred, int flags, struct thread *); 286175140Sjhbstatic int cryptof_truncate(struct file *, off_t, struct ucred *, 287175140Sjhb struct thread *); 288104476Ssamstatic int cryptof_ioctl(struct file *, u_long, void *, 289104476Ssam struct ucred *, struct thread *); 290104476Ssamstatic int cryptof_poll(struct file *, int, struct ucred *, struct thread *); 291104476Ssamstatic int cryptof_kqfilter(struct file *, struct knote *); 292104476Ssamstatic int cryptof_stat(struct file *, struct stat *, 293104476Ssam struct ucred *, struct thread *); 294104476Ssamstatic int cryptof_close(struct file *, struct thread *); 295104476Ssam 296104476Ssamstatic struct fileops cryptofops = { 297116546Sphk .fo_read = cryptof_rw, 298116546Sphk .fo_write = cryptof_rw, 299175140Sjhb .fo_truncate = cryptof_truncate, 300116546Sphk .fo_ioctl = cryptof_ioctl, 301116546Sphk .fo_poll = cryptof_poll, 302116546Sphk .fo_kqfilter = cryptof_kqfilter, 303116546Sphk .fo_stat = cryptof_stat, 304224914Skib .fo_close = cryptof_close, 305224914Skib .fo_chmod = invfo_chmod, 306224914Skib .fo_chown = invfo_chown, 307254356Sglebius .fo_sendfile = invfo_sendfile, 308104476Ssam}; 309104476Ssam 310104476Ssamstatic struct csession *csefind(struct fcrypt *, u_int); 311104476Ssamstatic int csedelete(struct fcrypt *, struct csession *); 312104476Ssamstatic struct csession *cseadd(struct fcrypt *, struct csession *); 313104476Ssamstatic struct csession *csecreate(struct fcrypt *, u_int64_t, caddr_t, 314104476Ssam u_int64_t, caddr_t, u_int64_t, u_int32_t, u_int32_t, struct enc_xform *, 315104476Ssam struct auth_hash *); 316104476Ssamstatic int csefree(struct csession *); 317104476Ssam 318104476Ssamstatic int cryptodev_op(struct csession *, struct crypt_op *, 319104476Ssam struct ucred *, struct thread *td); 320104476Ssamstatic int cryptodev_key(struct crypt_kop *); 321167755Ssamstatic int cryptodev_find(struct crypt_find_op *); 322104476Ssam 323104476Ssamstatic int 324104476Ssamcryptof_rw( 325104476Ssam struct file *fp, 326104476Ssam struct uio *uio, 327104476Ssam struct ucred *active_cred, 328104476Ssam int flags, 329104476Ssam struct thread *td) 330104476Ssam{ 331104476Ssam 332104476Ssam return (EIO); 333104476Ssam} 334104476Ssam 335175140Sjhbstatic int 336175140Sjhbcryptof_truncate( 337175140Sjhb struct file *fp, 338175140Sjhb off_t length, 339175140Sjhb struct ucred *active_cred, 340175140Sjhb struct thread *td) 341175140Sjhb{ 342175140Sjhb 343175140Sjhb return (EINVAL); 344175140Sjhb} 345175140Sjhb 346167755Ssam/* 347167755Ssam * Check a crypto identifier to see if it requested 348167755Ssam * a software device/driver. This can be done either 349167755Ssam * by device name/class or through search constraints. 350167755Ssam */ 351167755Ssamstatic int 352167755Ssamcheckforsoftware(int crid) 353167755Ssam{ 354167755Ssam if (crid & CRYPTOCAP_F_SOFTWARE) 355167755Ssam return EINVAL; /* XXX */ 356167755Ssam if ((crid & CRYPTOCAP_F_HARDWARE) == 0 && 357167755Ssam (crypto_getcaps(crid) & CRYPTOCAP_F_HARDWARE) == 0) 358167755Ssam return EINVAL; /* XXX */ 359167755Ssam return 0; 360167755Ssam} 361167755Ssam 362104476Ssam/* ARGSUSED */ 363104476Ssamstatic int 364104476Ssamcryptof_ioctl( 365104476Ssam struct file *fp, 366104476Ssam u_long cmd, 367104476Ssam void *data, 368104476Ssam struct ucred *active_cred, 369104476Ssam struct thread *td) 370104476Ssam{ 371167755Ssam#define SES2(p) ((struct session2_op *)p) 372104476Ssam struct cryptoini cria, crie; 373109153Sdillon struct fcrypt *fcr = fp->f_data; 374104476Ssam struct csession *cse; 375104476Ssam struct session_op *sop; 376104476Ssam struct crypt_op *cop; 377104476Ssam struct enc_xform *txform = NULL; 378104476Ssam struct auth_hash *thash = NULL; 379167755Ssam struct crypt_kop *kop; 380104476Ssam u_int64_t sid; 381104476Ssam u_int32_t ses; 382167755Ssam int error = 0, crid; 383210631Skib#ifdef COMPAT_FREEBSD32 384210631Skib struct session2_op sopc; 385210631Skib struct crypt_op copc; 386210631Skib struct crypt_kop kopc; 387210631Skib#endif 388104476Ssam 389104476Ssam switch (cmd) { 390104476Ssam case CIOCGSESSION: 391167755Ssam case CIOCGSESSION2: 392210631Skib#ifdef COMPAT_FREEBSD32 393210631Skib case CIOCGSESSION32: 394210631Skib case CIOCGSESSION232: 395210631Skib if (cmd == CIOCGSESSION32) { 396210631Skib session_op_from_32(data, (struct session_op *)&sopc); 397210631Skib sop = (struct session_op *)&sopc; 398210631Skib } else if (cmd == CIOCGSESSION232) { 399210631Skib session2_op_from_32(data, &sopc); 400210631Skib sop = (struct session_op *)&sopc; 401210631Skib } else 402210631Skib#endif 403210631Skib sop = (struct session_op *)data; 404104476Ssam switch (sop->cipher) { 405104476Ssam case 0: 406104476Ssam break; 407104476Ssam case CRYPTO_DES_CBC: 408104476Ssam txform = &enc_xform_des; 409104476Ssam break; 410104476Ssam case CRYPTO_3DES_CBC: 411104476Ssam txform = &enc_xform_3des; 412104476Ssam break; 413104476Ssam case CRYPTO_BLF_CBC: 414104476Ssam txform = &enc_xform_blf; 415104476Ssam break; 416104476Ssam case CRYPTO_CAST_CBC: 417104476Ssam txform = &enc_xform_cast5; 418104476Ssam break; 419104476Ssam case CRYPTO_SKIPJACK_CBC: 420104476Ssam txform = &enc_xform_skipjack; 421104476Ssam break; 422104476Ssam case CRYPTO_AES_CBC: 423104476Ssam txform = &enc_xform_rijndael128; 424104476Ssam break; 425213068Spjd case CRYPTO_AES_XTS: 426213068Spjd txform = &enc_xform_aes_xts; 427213068Spjd break; 428104476Ssam case CRYPTO_NULL_CBC: 429104476Ssam txform = &enc_xform_null; 430104476Ssam break; 431104476Ssam case CRYPTO_ARC4: 432104476Ssam txform = &enc_xform_arc4; 433104476Ssam break; 434169425Sgnn case CRYPTO_CAMELLIA_CBC: 435169425Sgnn txform = &enc_xform_camellia; 436169425Sgnn break; 437104476Ssam default: 438104476Ssam return (EINVAL); 439104476Ssam } 440104476Ssam 441104476Ssam switch (sop->mac) { 442104476Ssam case 0: 443104476Ssam break; 444104476Ssam case CRYPTO_MD5_HMAC: 445158703Spjd thash = &auth_hash_hmac_md5; 446104476Ssam break; 447104476Ssam case CRYPTO_SHA1_HMAC: 448158703Spjd thash = &auth_hash_hmac_sha1; 449104476Ssam break; 450158703Spjd case CRYPTO_SHA2_256_HMAC: 451158703Spjd thash = &auth_hash_hmac_sha2_256; 452104476Ssam break; 453158703Spjd case CRYPTO_SHA2_384_HMAC: 454158703Spjd thash = &auth_hash_hmac_sha2_384; 455158703Spjd break; 456158703Spjd case CRYPTO_SHA2_512_HMAC: 457158703Spjd thash = &auth_hash_hmac_sha2_512; 458158703Spjd break; 459104476Ssam case CRYPTO_RIPEMD160_HMAC: 460158703Spjd thash = &auth_hash_hmac_ripemd_160; 461104476Ssam break; 462104476Ssam#ifdef notdef 463104476Ssam case CRYPTO_MD5: 464104476Ssam thash = &auth_hash_md5; 465104476Ssam break; 466104476Ssam case CRYPTO_SHA1: 467104476Ssam thash = &auth_hash_sha1; 468104476Ssam break; 469104476Ssam#endif 470104476Ssam case CRYPTO_NULL_HMAC: 471104476Ssam thash = &auth_hash_null; 472104476Ssam break; 473104476Ssam default: 474104476Ssam return (EINVAL); 475104476Ssam } 476104476Ssam 477104476Ssam bzero(&crie, sizeof(crie)); 478104476Ssam bzero(&cria, sizeof(cria)); 479104476Ssam 480104476Ssam if (txform) { 481104476Ssam crie.cri_alg = txform->type; 482104476Ssam crie.cri_klen = sop->keylen * 8; 483104476Ssam if (sop->keylen > txform->maxkey || 484104476Ssam sop->keylen < txform->minkey) { 485104476Ssam error = EINVAL; 486104476Ssam goto bail; 487104476Ssam } 488104476Ssam 489184214Sdes crie.cri_key = malloc(crie.cri_klen / 8, 490184214Sdes M_XDATA, M_WAITOK); 491104476Ssam if ((error = copyin(sop->key, crie.cri_key, 492104476Ssam crie.cri_klen / 8))) 493104476Ssam goto bail; 494104476Ssam if (thash) 495104476Ssam crie.cri_next = &cria; 496104476Ssam } 497104476Ssam 498104476Ssam if (thash) { 499104476Ssam cria.cri_alg = thash->type; 500104476Ssam cria.cri_klen = sop->mackeylen * 8; 501104476Ssam if (sop->mackeylen != thash->keysize) { 502104476Ssam error = EINVAL; 503104476Ssam goto bail; 504104476Ssam } 505104476Ssam 506104476Ssam if (cria.cri_klen) { 507184214Sdes cria.cri_key = malloc(cria.cri_klen / 8, 508184214Sdes M_XDATA, M_WAITOK); 509104476Ssam if ((error = copyin(sop->mackey, cria.cri_key, 510104476Ssam cria.cri_klen / 8))) 511104476Ssam goto bail; 512104476Ssam } 513104476Ssam } 514104476Ssam 515211181Sjhb /* NB: CIOCGSESSION2 has the crid */ 516210631Skib if (cmd == CIOCGSESSION2 517210631Skib#ifdef COMPAT_FREEBSD32 518210631Skib || cmd == CIOCGSESSION232 519210631Skib#endif 520210631Skib ) { 521167755Ssam crid = SES2(sop)->crid; 522167755Ssam error = checkforsoftware(crid); 523158700Spjd if (error) 524158700Spjd goto bail; 525167755Ssam } else 526167755Ssam crid = CRYPTOCAP_F_HARDWARE; 527167755Ssam error = crypto_newsession(&sid, (txform ? &crie : &cria), crid); 528167755Ssam if (error) 529167755Ssam goto bail; 530104476Ssam 531104476Ssam cse = csecreate(fcr, sid, crie.cri_key, crie.cri_klen, 532104476Ssam cria.cri_key, cria.cri_klen, sop->cipher, sop->mac, txform, 533104476Ssam thash); 534104476Ssam 535104476Ssam if (cse == NULL) { 536104476Ssam crypto_freesession(sid); 537104476Ssam error = EINVAL; 538104476Ssam goto bail; 539104476Ssam } 540104476Ssam sop->ses = cse->ses; 541210631Skib if (cmd == CIOCGSESSION2 542210631Skib#ifdef COMPAT_FREEBSD32 543210631Skib || cmd == CIOCGSESSION232 544210631Skib#endif 545210631Skib ) { 546167755Ssam /* return hardware/driver id */ 547167755Ssam SES2(sop)->crid = CRYPTO_SESID2HID(cse->sid); 548167755Ssam } 549104476Ssambail: 550104476Ssam if (error) { 551104476Ssam if (crie.cri_key) 552184205Sdes free(crie.cri_key, M_XDATA); 553104476Ssam if (cria.cri_key) 554184205Sdes free(cria.cri_key, M_XDATA); 555104476Ssam } 556210631Skib#ifdef COMPAT_FREEBSD32 557210631Skib else { 558210631Skib if (cmd == CIOCGSESSION32) 559210631Skib session_op_to_32(sop, data); 560210631Skib else if (cmd == CIOCGSESSION232) 561210631Skib session2_op_to_32((struct session2_op *)sop, 562210631Skib data); 563210631Skib } 564210631Skib#endif 565104476Ssam break; 566104476Ssam case CIOCFSESSION: 567104476Ssam ses = *(u_int32_t *)data; 568104476Ssam cse = csefind(fcr, ses); 569167755Ssam if (cse == NULL) 570104476Ssam return (EINVAL); 571104476Ssam csedelete(fcr, cse); 572104476Ssam error = csefree(cse); 573104476Ssam break; 574104476Ssam case CIOCCRYPT: 575210631Skib#ifdef COMPAT_FREEBSD32 576210631Skib case CIOCCRYPT32: 577210631Skib if (cmd == CIOCCRYPT32) { 578210631Skib cop = &copc; 579210631Skib crypt_op_from_32(data, cop); 580210631Skib } else 581210631Skib#endif 582210631Skib cop = (struct crypt_op *)data; 583104476Ssam cse = csefind(fcr, cop->ses); 584167755Ssam if (cse == NULL) 585104476Ssam return (EINVAL); 586104476Ssam error = cryptodev_op(cse, cop, active_cred, td); 587210631Skib#ifdef COMPAT_FREEBSD32 588210631Skib if (error == 0 && cmd == CIOCCRYPT32) 589210631Skib crypt_op_to_32(cop, data); 590210631Skib#endif 591104476Ssam break; 592104476Ssam case CIOCKEY: 593167755Ssam case CIOCKEY2: 594210631Skib#ifdef COMPAT_FREEBSD32 595210631Skib case CIOCKEY32: 596210631Skib case CIOCKEY232: 597210631Skib#endif 598167755Ssam if (!crypto_userasymcrypto) 599167755Ssam return (EPERM); /* XXX compat? */ 600210631Skib#ifdef COMPAT_FREEBSD32 601210631Skib if (cmd == CIOCKEY32 || cmd == CIOCKEY232) { 602210631Skib kop = &kopc; 603210631Skib crypt_kop_from_32(data, kop); 604210631Skib } else 605210631Skib#endif 606210631Skib kop = (struct crypt_kop *)data; 607210631Skib if (cmd == CIOCKEY 608210631Skib#ifdef COMPAT_FREEBSD32 609210631Skib || cmd == CIOCKEY32 610210631Skib#endif 611210631Skib ) { 612167755Ssam /* NB: crypto core enforces s/w driver use */ 613167755Ssam kop->crk_crid = 614167755Ssam CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; 615167755Ssam } 616210631Skib mtx_lock(&Giant); 617167755Ssam error = cryptodev_key(kop); 618167755Ssam mtx_unlock(&Giant); 619210631Skib#ifdef COMPAT_FREEBSD32 620210631Skib if (cmd == CIOCKEY32 || cmd == CIOCKEY232) 621210631Skib crypt_kop_to_32(kop, data); 622210631Skib#endif 623104476Ssam break; 624104476Ssam case CIOCASYMFEAT: 625167755Ssam if (!crypto_userasymcrypto) { 626167755Ssam /* 627167755Ssam * NB: if user asym crypto operations are 628167755Ssam * not permitted return "no algorithms" 629167755Ssam * so well-behaved applications will just 630167755Ssam * fallback to doing them in software. 631167755Ssam */ 632167755Ssam *(int *)data = 0; 633167755Ssam } else 634167755Ssam error = crypto_getfeat((int *)data); 635104476Ssam break; 636167755Ssam case CIOCFINDDEV: 637167755Ssam error = cryptodev_find((struct crypt_find_op *)data); 638167755Ssam break; 639104476Ssam default: 640104476Ssam error = EINVAL; 641167755Ssam break; 642104476Ssam } 643104476Ssam return (error); 644167755Ssam#undef SES2 645104476Ssam} 646104476Ssam 647104476Ssamstatic int cryptodev_cb(void *); 648104476Ssam 649104476Ssam 650104476Ssamstatic int 651104476Ssamcryptodev_op( 652104476Ssam struct csession *cse, 653104476Ssam struct crypt_op *cop, 654104476Ssam struct ucred *active_cred, 655104476Ssam struct thread *td) 656104476Ssam{ 657104476Ssam struct cryptop *crp = NULL; 658104476Ssam struct cryptodesc *crde = NULL, *crda = NULL; 659122908Ssam int error; 660104476Ssam 661104476Ssam if (cop->len > 256*1024-4) 662104476Ssam return (E2BIG); 663104476Ssam 664149228Spjd if (cse->txform) { 665149228Spjd if (cop->len == 0 || (cop->len % cse->txform->blocksize) != 0) 666149228Spjd return (EINVAL); 667149228Spjd } 668104476Ssam 669122908Ssam cse->uio.uio_iov = &cse->iovec; 670104476Ssam cse->uio.uio_iovcnt = 1; 671122908Ssam cse->uio.uio_offset = 0; 672122908Ssam cse->uio.uio_resid = cop->len; 673104476Ssam cse->uio.uio_segflg = UIO_SYSSPACE; 674104476Ssam cse->uio.uio_rw = UIO_WRITE; 675104476Ssam cse->uio.uio_td = td; 676104476Ssam cse->uio.uio_iov[0].iov_len = cop->len; 677192636Sraj if (cse->thash) { 678158831Spjd cse->uio.uio_iov[0].iov_len += cse->thash->hashsize; 679192636Sraj cse->uio.uio_resid += cse->thash->hashsize; 680192636Sraj } 681158831Spjd cse->uio.uio_iov[0].iov_base = malloc(cse->uio.uio_iov[0].iov_len, 682158831Spjd M_XDATA, M_WAITOK); 683104476Ssam 684104476Ssam crp = crypto_getreq((cse->txform != NULL) + (cse->thash != NULL)); 685104476Ssam if (crp == NULL) { 686104476Ssam error = ENOMEM; 687104476Ssam goto bail; 688104476Ssam } 689104476Ssam 690104476Ssam if (cse->thash) { 691104476Ssam crda = crp->crp_desc; 692104476Ssam if (cse->txform) 693104476Ssam crde = crda->crd_next; 694104476Ssam } else { 695104476Ssam if (cse->txform) 696104476Ssam crde = crp->crp_desc; 697104476Ssam else { 698104476Ssam error = EINVAL; 699104476Ssam goto bail; 700104476Ssam } 701104476Ssam } 702104476Ssam 703104476Ssam if ((error = copyin(cop->src, cse->uio.uio_iov[0].iov_base, cop->len))) 704104476Ssam goto bail; 705104476Ssam 706104476Ssam if (crda) { 707104476Ssam crda->crd_skip = 0; 708104476Ssam crda->crd_len = cop->len; 709158831Spjd crda->crd_inject = cop->len; 710104476Ssam 711104476Ssam crda->crd_alg = cse->mac; 712104476Ssam crda->crd_key = cse->mackey; 713104476Ssam crda->crd_klen = cse->mackeylen * 8; 714104476Ssam } 715104476Ssam 716104476Ssam if (crde) { 717104476Ssam if (cop->op == COP_ENCRYPT) 718104476Ssam crde->crd_flags |= CRD_F_ENCRYPT; 719104476Ssam else 720104476Ssam crde->crd_flags &= ~CRD_F_ENCRYPT; 721104476Ssam crde->crd_len = cop->len; 722104476Ssam crde->crd_inject = 0; 723104476Ssam 724104476Ssam crde->crd_alg = cse->cipher; 725104476Ssam crde->crd_key = cse->key; 726104476Ssam crde->crd_klen = cse->keylen * 8; 727104476Ssam } 728104476Ssam 729104476Ssam crp->crp_ilen = cop->len; 730111297Ssam crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM 731111297Ssam | (cop->flags & COP_F_BATCH); 732104476Ssam crp->crp_buf = (caddr_t)&cse->uio; 733104476Ssam crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb; 734104476Ssam crp->crp_sid = cse->sid; 735104476Ssam crp->crp_opaque = (void *)cse; 736104476Ssam 737104476Ssam if (cop->iv) { 738104476Ssam if (crde == NULL) { 739104476Ssam error = EINVAL; 740104476Ssam goto bail; 741104476Ssam } 742104476Ssam if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */ 743104476Ssam error = EINVAL; 744104476Ssam goto bail; 745104476Ssam } 746104476Ssam if ((error = copyin(cop->iv, cse->tmp_iv, cse->txform->blocksize))) 747104476Ssam goto bail; 748104476Ssam bcopy(cse->tmp_iv, crde->crd_iv, cse->txform->blocksize); 749104476Ssam crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT; 750104476Ssam crde->crd_skip = 0; 751104476Ssam } else if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */ 752104476Ssam crde->crd_skip = 0; 753104476Ssam } else if (crde) { 754104476Ssam crde->crd_flags |= CRD_F_IV_PRESENT; 755104476Ssam crde->crd_skip = cse->txform->blocksize; 756104476Ssam crde->crd_len -= cse->txform->blocksize; 757104476Ssam } 758104476Ssam 759158831Spjd if (cop->mac && crda == NULL) { 760158831Spjd error = EINVAL; 761158831Spjd goto bail; 762104476Ssam } 763104476Ssam 764196825Spjdagain: 765115746Ssam /* 766115746Ssam * Let the dispatch run unlocked, then, interlock against the 767115746Ssam * callback before checking if the operation completed and going 768115746Ssam * to sleep. This insures drivers don't inherit our lock which 769115746Ssam * results in a lock order reversal between crypto_dispatch forced 770115746Ssam * entry and the crypto_done callback into us. 771115746Ssam */ 772115746Ssam error = crypto_dispatch(crp); 773115746Ssam mtx_lock(&cse->lock); 774115746Ssam if (error == 0 && (crp->crp_flags & CRYPTO_F_DONE) == 0) 775115746Ssam error = msleep(crp, &cse->lock, PWAIT, "crydev", 0); 776115746Ssam mtx_unlock(&cse->lock); 777115746Ssam 778115746Ssam if (error != 0) 779104476Ssam goto bail; 780104476Ssam 781196825Spjd if (crp->crp_etype == EAGAIN) { 782196825Spjd crp->crp_etype = 0; 783196825Spjd crp->crp_flags &= ~CRYPTO_F_DONE; 784196825Spjd goto again; 785196825Spjd } 786196825Spjd 787104476Ssam if (crp->crp_etype != 0) { 788104476Ssam error = crp->crp_etype; 789104476Ssam goto bail; 790104476Ssam } 791104476Ssam 792104476Ssam if (cse->error) { 793104476Ssam error = cse->error; 794104476Ssam goto bail; 795104476Ssam } 796104476Ssam 797104476Ssam if (cop->dst && 798104476Ssam (error = copyout(cse->uio.uio_iov[0].iov_base, cop->dst, cop->len))) 799104476Ssam goto bail; 800104476Ssam 801104476Ssam if (cop->mac && 802158831Spjd (error = copyout((caddr_t)cse->uio.uio_iov[0].iov_base + cop->len, 803158831Spjd cop->mac, cse->thash->hashsize))) 804104476Ssam goto bail; 805104476Ssam 806104476Ssambail: 807104476Ssam if (crp) 808104476Ssam crypto_freereq(crp); 809104476Ssam if (cse->uio.uio_iov[0].iov_base) 810104476Ssam free(cse->uio.uio_iov[0].iov_base, M_XDATA); 811104476Ssam 812104476Ssam return (error); 813104476Ssam} 814104476Ssam 815104476Ssamstatic int 816104476Ssamcryptodev_cb(void *op) 817104476Ssam{ 818104476Ssam struct cryptop *crp = (struct cryptop *) op; 819104476Ssam struct csession *cse = (struct csession *)crp->crp_opaque; 820104476Ssam 821115746Ssam mtx_lock(&cse->lock); 822196825Spjd cse->error = crp->crp_etype; 823196825Spjd wakeup_one(crp); 824115746Ssam mtx_unlock(&cse->lock); 825104476Ssam return (0); 826104476Ssam} 827104476Ssam 828104476Ssamstatic int 829104476Ssamcryptodevkey_cb(void *op) 830104476Ssam{ 831104476Ssam struct cryptkop *krp = (struct cryptkop *) op; 832104476Ssam 833167755Ssam wakeup_one(krp); 834104476Ssam return (0); 835104476Ssam} 836104476Ssam 837104476Ssamstatic int 838104476Ssamcryptodev_key(struct crypt_kop *kop) 839104476Ssam{ 840104476Ssam struct cryptkop *krp = NULL; 841104476Ssam int error = EINVAL; 842104476Ssam int in, out, size, i; 843104476Ssam 844104476Ssam if (kop->crk_iparams + kop->crk_oparams > CRK_MAXPARAM) { 845104476Ssam return (EFBIG); 846104476Ssam } 847104476Ssam 848104476Ssam in = kop->crk_iparams; 849104476Ssam out = kop->crk_oparams; 850104476Ssam switch (kop->crk_op) { 851104476Ssam case CRK_MOD_EXP: 852104476Ssam if (in == 3 && out == 1) 853104476Ssam break; 854104476Ssam return (EINVAL); 855104476Ssam case CRK_MOD_EXP_CRT: 856104476Ssam if (in == 6 && out == 1) 857104476Ssam break; 858104476Ssam return (EINVAL); 859104476Ssam case CRK_DSA_SIGN: 860104476Ssam if (in == 5 && out == 2) 861104476Ssam break; 862104476Ssam return (EINVAL); 863104476Ssam case CRK_DSA_VERIFY: 864104476Ssam if (in == 7 && out == 0) 865104476Ssam break; 866104476Ssam return (EINVAL); 867104476Ssam case CRK_DH_COMPUTE_KEY: 868104476Ssam if (in == 3 && out == 1) 869104476Ssam break; 870104476Ssam return (EINVAL); 871104476Ssam default: 872104476Ssam return (EINVAL); 873104476Ssam } 874104476Ssam 875172474Skib krp = (struct cryptkop *)malloc(sizeof *krp, M_XDATA, M_WAITOK|M_ZERO); 876104476Ssam if (!krp) 877104476Ssam return (ENOMEM); 878104476Ssam krp->krp_op = kop->crk_op; 879104476Ssam krp->krp_status = kop->crk_status; 880104476Ssam krp->krp_iparams = kop->crk_iparams; 881104476Ssam krp->krp_oparams = kop->crk_oparams; 882167755Ssam krp->krp_crid = kop->crk_crid; 883104476Ssam krp->krp_status = 0; 884104476Ssam krp->krp_callback = (int (*) (struct cryptkop *)) cryptodevkey_cb; 885104476Ssam 886172474Skib for (i = 0; i < CRK_MAXPARAM; i++) { 887172474Skib if (kop->crk_param[i].crp_nbits > 65536) 888172474Skib /* Limit is the same as in OpenBSD */ 889172474Skib goto fail; 890104476Ssam krp->krp_param[i].crp_nbits = kop->crk_param[i].crp_nbits; 891172474Skib } 892104476Ssam for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) { 893104476Ssam size = (krp->krp_param[i].crp_nbits + 7) / 8; 894104476Ssam if (size == 0) 895104476Ssam continue; 896184205Sdes krp->krp_param[i].crp_p = malloc(size, M_XDATA, M_WAITOK); 897104476Ssam if (i >= krp->krp_iparams) 898104476Ssam continue; 899104476Ssam error = copyin(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p, size); 900104476Ssam if (error) 901104476Ssam goto fail; 902104476Ssam } 903104476Ssam 904104476Ssam error = crypto_kdispatch(krp); 905104476Ssam if (error) 906104476Ssam goto fail; 907104476Ssam error = tsleep(krp, PSOCK, "crydev", 0); 908104476Ssam if (error) { 909104476Ssam /* XXX can this happen? if so, how do we recover? */ 910104476Ssam goto fail; 911104476Ssam } 912104476Ssam 913167755Ssam kop->crk_crid = krp->krp_crid; /* device that did the work */ 914104476Ssam if (krp->krp_status != 0) { 915104476Ssam error = krp->krp_status; 916104476Ssam goto fail; 917104476Ssam } 918104476Ssam 919104476Ssam for (i = krp->krp_iparams; i < krp->krp_iparams + krp->krp_oparams; i++) { 920104476Ssam size = (krp->krp_param[i].crp_nbits + 7) / 8; 921104476Ssam if (size == 0) 922104476Ssam continue; 923104476Ssam error = copyout(krp->krp_param[i].crp_p, kop->crk_param[i].crp_p, size); 924104476Ssam if (error) 925104476Ssam goto fail; 926104476Ssam } 927104476Ssam 928104476Ssamfail: 929104476Ssam if (krp) { 930104476Ssam kop->crk_status = krp->krp_status; 931104476Ssam for (i = 0; i < CRK_MAXPARAM; i++) { 932104476Ssam if (krp->krp_param[i].crp_p) 933184205Sdes free(krp->krp_param[i].crp_p, M_XDATA); 934104476Ssam } 935104476Ssam free(krp, M_XDATA); 936104476Ssam } 937104476Ssam return (error); 938104476Ssam} 939104476Ssam 940167755Ssamstatic int 941167755Ssamcryptodev_find(struct crypt_find_op *find) 942167755Ssam{ 943167755Ssam device_t dev; 944167755Ssam 945167755Ssam if (find->crid != -1) { 946167755Ssam dev = crypto_find_device_byhid(find->crid); 947167755Ssam if (dev == NULL) 948167755Ssam return (ENOENT); 949167755Ssam strlcpy(find->name, device_get_nameunit(dev), 950167755Ssam sizeof(find->name)); 951167755Ssam } else { 952167755Ssam find->crid = crypto_find_driver(find->name); 953167755Ssam if (find->crid == -1) 954167755Ssam return (ENOENT); 955167755Ssam } 956167755Ssam return (0); 957167755Ssam} 958167755Ssam 959104476Ssam/* ARGSUSED */ 960104476Ssamstatic int 961104476Ssamcryptof_poll( 962104476Ssam struct file *fp, 963104476Ssam int events, 964104476Ssam struct ucred *active_cred, 965104476Ssam struct thread *td) 966104476Ssam{ 967104476Ssam 968104476Ssam return (0); 969104476Ssam} 970104476Ssam 971104476Ssam/* ARGSUSED */ 972104476Ssamstatic int 973104476Ssamcryptof_kqfilter(struct file *fp, struct knote *kn) 974104476Ssam{ 975104476Ssam 976104476Ssam return (0); 977104476Ssam} 978104476Ssam 979104476Ssam/* ARGSUSED */ 980104476Ssamstatic int 981104476Ssamcryptof_stat( 982104476Ssam struct file *fp, 983104476Ssam struct stat *sb, 984104476Ssam struct ucred *active_cred, 985104476Ssam struct thread *td) 986104476Ssam{ 987104476Ssam 988104476Ssam return (EOPNOTSUPP); 989104476Ssam} 990104476Ssam 991104476Ssam/* ARGSUSED */ 992104476Ssamstatic int 993104476Ssamcryptof_close(struct file *fp, struct thread *td) 994104476Ssam{ 995109153Sdillon struct fcrypt *fcr = fp->f_data; 996104476Ssam struct csession *cse; 997104476Ssam 998104476Ssam while ((cse = TAILQ_FIRST(&fcr->csessions))) { 999104476Ssam TAILQ_REMOVE(&fcr->csessions, cse, next); 1000104476Ssam (void)csefree(cse); 1001104476Ssam } 1002184205Sdes free(fcr, M_XDATA); 1003109153Sdillon fp->f_data = NULL; 1004104476Ssam return 0; 1005104476Ssam} 1006104476Ssam 1007104476Ssamstatic struct csession * 1008104476Ssamcsefind(struct fcrypt *fcr, u_int ses) 1009104476Ssam{ 1010104476Ssam struct csession *cse; 1011104476Ssam 1012104476Ssam TAILQ_FOREACH(cse, &fcr->csessions, next) 1013104476Ssam if (cse->ses == ses) 1014104476Ssam return (cse); 1015104476Ssam return (NULL); 1016104476Ssam} 1017104476Ssam 1018104476Ssamstatic int 1019104476Ssamcsedelete(struct fcrypt *fcr, struct csession *cse_del) 1020104476Ssam{ 1021104476Ssam struct csession *cse; 1022104476Ssam 1023104476Ssam TAILQ_FOREACH(cse, &fcr->csessions, next) { 1024104476Ssam if (cse == cse_del) { 1025104476Ssam TAILQ_REMOVE(&fcr->csessions, cse, next); 1026104476Ssam return (1); 1027104476Ssam } 1028104476Ssam } 1029104476Ssam return (0); 1030104476Ssam} 1031104476Ssam 1032104476Ssamstatic struct csession * 1033104476Ssamcseadd(struct fcrypt *fcr, struct csession *cse) 1034104476Ssam{ 1035104476Ssam TAILQ_INSERT_TAIL(&fcr->csessions, cse, next); 1036104476Ssam cse->ses = fcr->sesn++; 1037104476Ssam return (cse); 1038104476Ssam} 1039104476Ssam 1040104476Ssamstruct csession * 1041104476Ssamcsecreate(struct fcrypt *fcr, u_int64_t sid, caddr_t key, u_int64_t keylen, 1042104476Ssam caddr_t mackey, u_int64_t mackeylen, u_int32_t cipher, u_int32_t mac, 1043104476Ssam struct enc_xform *txform, struct auth_hash *thash) 1044104476Ssam{ 1045104476Ssam struct csession *cse; 1046104476Ssam 1047115746Ssam#ifdef INVARIANTS 1048115746Ssam /* NB: required when mtx_init is built with INVARIANTS */ 1049184214Sdes cse = malloc(sizeof(struct csession), M_XDATA, M_NOWAIT | M_ZERO); 1050115746Ssam#else 1051184214Sdes cse = malloc(sizeof(struct csession), M_XDATA, M_NOWAIT); 1052115746Ssam#endif 1053104476Ssam if (cse == NULL) 1054104476Ssam return NULL; 1055115746Ssam mtx_init(&cse->lock, "cryptodev", "crypto session lock", MTX_DEF); 1056104476Ssam cse->key = key; 1057104476Ssam cse->keylen = keylen/8; 1058104476Ssam cse->mackey = mackey; 1059104476Ssam cse->mackeylen = mackeylen/8; 1060104476Ssam cse->sid = sid; 1061104476Ssam cse->cipher = cipher; 1062104476Ssam cse->mac = mac; 1063104476Ssam cse->txform = txform; 1064104476Ssam cse->thash = thash; 1065104476Ssam cseadd(fcr, cse); 1066104476Ssam return (cse); 1067104476Ssam} 1068104476Ssam 1069104476Ssamstatic int 1070104476Ssamcsefree(struct csession *cse) 1071104476Ssam{ 1072104476Ssam int error; 1073104476Ssam 1074104476Ssam error = crypto_freesession(cse->sid); 1075115746Ssam mtx_destroy(&cse->lock); 1076104476Ssam if (cse->key) 1077184205Sdes free(cse->key, M_XDATA); 1078104476Ssam if (cse->mackey) 1079184205Sdes free(cse->mackey, M_XDATA); 1080184205Sdes free(cse, M_XDATA); 1081104476Ssam return (error); 1082104476Ssam} 1083104476Ssam 1084104476Ssamstatic int 1085130585Sphkcryptoopen(struct cdev *dev, int oflags, int devtype, struct thread *td) 1086104476Ssam{ 1087104476Ssam return (0); 1088104476Ssam} 1089104476Ssam 1090104476Ssamstatic int 1091130585Sphkcryptoread(struct cdev *dev, struct uio *uio, int ioflag) 1092104476Ssam{ 1093104476Ssam return (EIO); 1094104476Ssam} 1095104476Ssam 1096104476Ssamstatic int 1097130585Sphkcryptowrite(struct cdev *dev, struct uio *uio, int ioflag) 1098104476Ssam{ 1099104476Ssam return (EIO); 1100104476Ssam} 1101104476Ssam 1102104476Ssamstatic int 1103130585Sphkcryptoioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 1104104476Ssam{ 1105104476Ssam struct file *f; 1106104476Ssam struct fcrypt *fcr; 1107104476Ssam int fd, error; 1108104476Ssam 1109104476Ssam switch (cmd) { 1110104476Ssam case CRIOGET: 1111184214Sdes fcr = malloc(sizeof(struct fcrypt), M_XDATA, M_WAITOK); 1112104476Ssam TAILQ_INIT(&fcr->csessions); 1113104476Ssam fcr->sesn = 0; 1114104476Ssam 1115220245Skib error = falloc(td, &f, &fd, 0); 1116104476Ssam 1117104476Ssam if (error) { 1118184205Sdes free(fcr, M_XDATA); 1119104476Ssam return (error); 1120104476Ssam } 1121121256Sdwmalone /* falloc automatically provides an extra reference to 'f'. */ 1122174988Sjeff finit(f, FREAD | FWRITE, DTYPE_CRYPTO, fcr, &cryptofops); 1123104476Ssam *(u_int32_t *)data = fd; 1124104476Ssam fdrop(f, td); 1125104476Ssam break; 1126167755Ssam case CRIOFINDDEV: 1127167755Ssam error = cryptodev_find((struct crypt_find_op *)data); 1128167755Ssam break; 1129167755Ssam case CRIOASYMFEAT: 1130167755Ssam error = crypto_getfeat((int *)data); 1131167755Ssam break; 1132104476Ssam default: 1133104476Ssam error = EINVAL; 1134104476Ssam break; 1135104476Ssam } 1136104476Ssam return (error); 1137104476Ssam} 1138104476Ssam 1139104476Ssamstatic struct cdevsw crypto_cdevsw = { 1140126080Sphk .d_version = D_VERSION, 1141126080Sphk .d_flags = D_NEEDGIANT, 1142111815Sphk .d_open = cryptoopen, 1143111815Sphk .d_read = cryptoread, 1144111815Sphk .d_write = cryptowrite, 1145111815Sphk .d_ioctl = cryptoioctl, 1146111815Sphk .d_name = "crypto", 1147104476Ssam}; 1148130585Sphkstatic struct cdev *crypto_dev; 1149104476Ssam 1150104476Ssam/* 1151104476Ssam * Initialization code, both for static and dynamic loading. 1152104476Ssam */ 1153104476Ssamstatic int 1154104476Ssamcryptodev_modevent(module_t mod, int type, void *unused) 1155104476Ssam{ 1156104476Ssam switch (type) { 1157104476Ssam case MOD_LOAD: 1158104476Ssam if (bootverbose) 1159104476Ssam printf("crypto: <crypto device>\n"); 1160106677Ssam crypto_dev = make_dev(&crypto_cdevsw, 0, 1161104476Ssam UID_ROOT, GID_WHEEL, 0666, 1162104476Ssam "crypto"); 1163104476Ssam return 0; 1164104476Ssam case MOD_UNLOAD: 1165104476Ssam /*XXX disallow if active sessions */ 1166104476Ssam destroy_dev(crypto_dev); 1167104476Ssam return 0; 1168104476Ssam } 1169104476Ssam return EINVAL; 1170104476Ssam} 1171104476Ssam 1172104476Ssamstatic moduledata_t cryptodev_mod = { 1173104476Ssam "cryptodev", 1174104476Ssam cryptodev_modevent, 1175241394Skevlo 0 1176104476Ssam}; 1177104476SsamMODULE_VERSION(cryptodev, 1); 1178104476SsamDECLARE_MODULE(cryptodev, cryptodev_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 1179105251SmarkmMODULE_DEPEND(cryptodev, crypto, 1, 1, 1); 1180156072SwkoszekMODULE_DEPEND(cryptodev, zlib, 1, 1, 1); 1181