| Commit | Line | Data |
|---|---|---|
| 42ee1e6b | 1 | /* $FreeBSD: src/sys/opencrypto/cryptodev.c,v 1.41 2009/09/04 09:48:18 pjd Exp $ */ |
| 984263bc MD |
2 | /* $OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $ */ |
| 3 | ||
| 42ee1e6b | 4 | /*- |
| 984263bc | 5 | * Copyright (c) 2001 Theo de Raadt |
| 42ee1e6b | 6 | * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting |
| 984263bc MD |
7 | * |
| 8 | * Redistribution and use in source and binary forms, with or without | |
| 9 | * modification, are permitted provided that the following conditions | |
| 10 | * are met: | |
| 11 | * | |
| 12 | * 1. Redistributions of source code must retain the above copyright | |
| 13 | * notice, this list of conditions and the following disclaimer. | |
| 14 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 15 | * notice, this list of conditions and the following disclaimer in the | |
| 16 | * documentation and/or other materials provided with the distribution. | |
| 17 | * 3. The name of the author may not be used to endorse or promote products | |
| 18 | * derived from this software without specific prior written permission. | |
| 19 | * | |
| 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
| 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
| 22 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
| 23 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 24 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
| 25 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
| 29 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 30 | * | |
| 31 | * Effort sponsored in part by the Defense Advanced Research Projects | |
| 32 | * Agency (DARPA) and Air Force Research Laboratory, Air Force | |
| 33 | * Materiel Command, USAF, under agreement number F30602-01-2-0537. | |
| 984263bc MD |
34 | */ |
| 35 | ||
| 36 | #include <sys/param.h> | |
| 37 | #include <sys/systm.h> | |
| 38 | #include <sys/malloc.h> | |
| 54734da1 | 39 | #include <sys/device.h> |
| 984263bc | 40 | #include <sys/mbuf.h> |
| 42ee1e6b | 41 | #include <sys/lock.h> |
| 984263bc MD |
42 | #include <sys/sysctl.h> |
| 43 | #include <sys/file.h> | |
| 44 | #include <sys/filedesc.h> | |
| 45 | #include <sys/errno.h> | |
| 46 | #include <sys/uio.h> | |
| 47 | #include <sys/random.h> | |
| 48 | #include <sys/conf.h> | |
| 42ee1e6b | 49 | #include <sys/module.h> |
| 984263bc MD |
50 | #include <sys/kernel.h> |
| 51 | #include <sys/fcntl.h> | |
| dadab5e9 | 52 | #include <sys/proc.h> |
| 684a93c4 | 53 | |
| dadab5e9 | 54 | #include <sys/file2.h> |
| a7f45447 | 55 | #include <sys/thread2.h> |
| 684a93c4 | 56 | #include <sys/mplock2.h> |
| 984263bc MD |
57 | |
| 58 | #include <opencrypto/cryptodev.h> | |
| 59 | #include <opencrypto/xform.h> | |
| 60 | ||
| 61 | struct csession { | |
| 62 | TAILQ_ENTRY(csession) next; | |
| 63 | u_int64_t sid; | |
| 64 | u_int32_t ses; | |
| 42ee1e6b | 65 | struct lock lock; |
| 984263bc MD |
66 | |
| 67 | u_int32_t cipher; | |
| 68 | struct enc_xform *txform; | |
| 69 | u_int32_t mac; | |
| 70 | struct auth_hash *thash; | |
| 71 | ||
| 72 | caddr_t key; | |
| 73 | int keylen; | |
| 54734da1 | 74 | u_char tmp_iv[EALG_MAX_BLOCK_LEN]; |
| 984263bc MD |
75 | |
| 76 | caddr_t mackey; | |
| 77 | int mackeylen; | |
| 984263bc | 78 | |
| 42ee1e6b | 79 | struct iovec iovec; |
| 984263bc MD |
80 | struct uio uio; |
| 81 | int error; | |
| 82 | }; | |
| 83 | ||
| 84 | struct fcrypt { | |
| 85 | TAILQ_HEAD(csessionlist, csession) csessions; | |
| 86 | int sesn; | |
| 87 | }; | |
| 88 | ||
| 89 | static int cryptof_rw(struct file *fp, struct uio *uio, | |
| 87de5057 | 90 | struct ucred *cred, int flags); |
| 87baaf0c MD |
91 | static int cryptof_ioctl(struct file *, u_long, caddr_t, |
| 92 | struct ucred *, struct sysmsg *); | |
| 984263bc | 93 | static int cryptof_kqfilter(struct file *, struct knote *); |
| 87de5057 MD |
94 | static int cryptof_stat(struct file *, struct stat *, struct ucred *); |
| 95 | static int cryptof_close(struct file *); | |
| 984263bc MD |
96 | |
| 97 | static struct fileops cryptofops = { | |
| b2d248cb MD |
98 | .fo_read = cryptof_rw, |
| 99 | .fo_write = cryptof_rw, | |
| 100 | .fo_ioctl = cryptof_ioctl, | |
| b2d248cb MD |
101 | .fo_kqfilter = cryptof_kqfilter, |
| 102 | .fo_stat = cryptof_stat, | |
| 103 | .fo_close = cryptof_close, | |
| 104 | .fo_shutdown = nofo_shutdown | |
| 984263bc MD |
105 | }; |
| 106 | ||
| 107 | static struct csession *csefind(struct fcrypt *, u_int); | |
| 108 | static int csedelete(struct fcrypt *, struct csession *); | |
| 109 | static struct csession *cseadd(struct fcrypt *, struct csession *); | |
| 110 | static struct csession *csecreate(struct fcrypt *, u_int64_t, caddr_t, | |
| 111 | u_int64_t, caddr_t, u_int64_t, u_int32_t, u_int32_t, struct enc_xform *, | |
| 112 | struct auth_hash *); | |
| 113 | static int csefree(struct csession *); | |
| 114 | ||
| 42ee1e6b | 115 | static int cryptodev_op(struct csession *, struct crypt_op *, struct ucred *); |
| 984263bc | 116 | static int cryptodev_key(struct crypt_kop *); |
| 42ee1e6b | 117 | static int cryptodev_find(struct crypt_find_op *); |
| 984263bc MD |
118 | |
| 119 | static int | |
| 120 | cryptof_rw( | |
| 121 | struct file *fp, | |
| 122 | struct uio *uio, | |
| 123 | struct ucred *active_cred, | |
| 87de5057 | 124 | int flags) |
| 984263bc | 125 | { |
| 984263bc MD |
126 | return (EIO); |
| 127 | } | |
| 128 | ||
| d9b2033e | 129 | /* |
| 42ee1e6b SW |
130 | * Check a crypto identifier to see if it requested |
| 131 | * a software device/driver. This can be done either | |
| 132 | * by device name/class or through search constraints. | |
| d9b2033e | 133 | */ |
| 984263bc | 134 | static int |
| 42ee1e6b SW |
135 | checkforsoftware(int crid) |
| 136 | { | |
| 137 | if (crid & CRYPTOCAP_F_SOFTWARE) | |
| 138 | return EINVAL; /* XXX */ | |
| 139 | if ((crid & CRYPTOCAP_F_HARDWARE) == 0 && | |
| 140 | (crypto_getcaps(crid) & CRYPTOCAP_F_HARDWARE) == 0) | |
| 141 | return EINVAL; /* XXX */ | |
| 142 | return 0; | |
| 143 | } | |
| 144 | ||
| 145 | /* ARGSUSED */ | |
| 146 | static int | |
| 87baaf0c MD |
147 | cryptof_ioctl(struct file *fp, u_long cmd, caddr_t data, |
| 148 | struct ucred *cred, struct sysmsg *msg) | |
| 984263bc | 149 | { |
| 42ee1e6b | 150 | #define SES2(p) ((struct session2_op *)p) |
| 984263bc | 151 | struct cryptoini cria, crie; |
| 54734da1 | 152 | struct fcrypt *fcr = fp->f_data; |
| 984263bc MD |
153 | struct csession *cse; |
| 154 | struct session_op *sop; | |
| 155 | struct crypt_op *cop; | |
| 156 | struct enc_xform *txform = NULL; | |
| 157 | struct auth_hash *thash = NULL; | |
| 42ee1e6b | 158 | struct crypt_kop *kop; |
| 984263bc MD |
159 | u_int64_t sid; |
| 160 | u_int32_t ses; | |
| 42ee1e6b | 161 | int error = 0, crid; |
| d9b2033e | 162 | |
| 984263bc MD |
163 | switch (cmd) { |
| 164 | case CIOCGSESSION: | |
| 42ee1e6b | 165 | case CIOCGSESSION2: |
| 984263bc MD |
166 | sop = (struct session_op *)data; |
| 167 | switch (sop->cipher) { | |
| 168 | case 0: | |
| 169 | break; | |
| 170 | case CRYPTO_DES_CBC: | |
| 171 | txform = &enc_xform_des; | |
| 172 | break; | |
| 173 | case CRYPTO_3DES_CBC: | |
| 174 | txform = &enc_xform_3des; | |
| 175 | break; | |
| 176 | case CRYPTO_BLF_CBC: | |
| 177 | txform = &enc_xform_blf; | |
| 178 | break; | |
| 179 | case CRYPTO_CAST_CBC: | |
| 180 | txform = &enc_xform_cast5; | |
| 181 | break; | |
| 182 | case CRYPTO_SKIPJACK_CBC: | |
| 183 | txform = &enc_xform_skipjack; | |
| 184 | break; | |
| 185 | case CRYPTO_AES_CBC: | |
| 186 | txform = &enc_xform_rijndael128; | |
| 187 | break; | |
| da41e4e5 AH |
188 | case CRYPTO_AES_XTS: |
| 189 | txform = &enc_xform_aes_xts; | |
| 190 | break; | |
| 191 | case CRYPTO_AES_CTR: | |
| 192 | txform = &enc_xform_aes_ctr; | |
| 193 | break; | |
| 984263bc MD |
194 | case CRYPTO_NULL_CBC: |
| 195 | txform = &enc_xform_null; | |
| 196 | break; | |
| 197 | case CRYPTO_ARC4: | |
| 198 | txform = &enc_xform_arc4; | |
| 199 | break; | |
| 42ee1e6b SW |
200 | case CRYPTO_CAMELLIA_CBC: |
| 201 | txform = &enc_xform_camellia; | |
| d9b2033e | 202 | break; |
| 37cb95f9 AH |
203 | case CRYPTO_TWOFISH_CBC: |
| 204 | txform = &enc_xform_twofish; | |
| 205 | break; | |
| a2f0c013 AH |
206 | case CRYPTO_SERPENT_CBC: |
| 207 | txform = &enc_xform_serpent; | |
| 208 | break; | |
| 83ceef91 AH |
209 | case CRYPTO_TWOFISH_XTS: |
| 210 | txform = &enc_xform_twofish_xts; | |
| 211 | break; | |
| 212 | case CRYPTO_SERPENT_XTS: | |
| 213 | txform = &enc_xform_serpent_xts; | |
| 214 | break; | |
| 42ee1e6b SW |
215 | default: |
| 216 | return (EINVAL); | |
| 984263bc MD |
217 | } |
| 218 | ||
| 219 | switch (sop->mac) { | |
| 220 | case 0: | |
| 221 | break; | |
| 222 | case CRYPTO_MD5_HMAC: | |
| 42ee1e6b | 223 | thash = &auth_hash_hmac_md5; |
| 984263bc MD |
224 | break; |
| 225 | case CRYPTO_SHA1_HMAC: | |
| 42ee1e6b | 226 | thash = &auth_hash_hmac_sha1; |
| 984263bc | 227 | break; |
| 42ee1e6b SW |
228 | case CRYPTO_SHA2_256_HMAC: |
| 229 | thash = &auth_hash_hmac_sha2_256; | |
| 230 | break; | |
| 231 | case CRYPTO_SHA2_384_HMAC: | |
| 232 | thash = &auth_hash_hmac_sha2_384; | |
| 233 | break; | |
| 234 | case CRYPTO_SHA2_512_HMAC: | |
| 235 | thash = &auth_hash_hmac_sha2_512; | |
| 984263bc MD |
236 | break; |
| 237 | case CRYPTO_RIPEMD160_HMAC: | |
| 42ee1e6b | 238 | thash = &auth_hash_hmac_ripemd_160; |
| 984263bc MD |
239 | break; |
| 240 | #ifdef notdef | |
| 241 | case CRYPTO_MD5: | |
| 242 | thash = &auth_hash_md5; | |
| 243 | break; | |
| 244 | case CRYPTO_SHA1: | |
| 245 | thash = &auth_hash_sha1; | |
| 246 | break; | |
| 247 | #endif | |
| 248 | case CRYPTO_NULL_HMAC: | |
| 249 | thash = &auth_hash_null; | |
| 250 | break; | |
| 251 | default: | |
| 42ee1e6b | 252 | return (EINVAL); |
| 984263bc MD |
253 | } |
| 254 | ||
| 255 | bzero(&crie, sizeof(crie)); | |
| 256 | bzero(&cria, sizeof(cria)); | |
| 257 | ||
| 258 | if (txform) { | |
| 259 | crie.cri_alg = txform->type; | |
| 260 | crie.cri_klen = sop->keylen * 8; | |
| 261 | if (sop->keylen > txform->maxkey || | |
| 262 | sop->keylen < txform->minkey) { | |
| 263 | error = EINVAL; | |
| 264 | goto bail; | |
| 265 | } | |
| 266 | ||
| 42ee1e6b SW |
267 | crie.cri_key = kmalloc(crie.cri_klen / 8, |
| 268 | M_XDATA, M_WAITOK); | |
| 984263bc MD |
269 | if ((error = copyin(sop->key, crie.cri_key, |
| 270 | crie.cri_klen / 8))) | |
| 271 | goto bail; | |
| 272 | if (thash) | |
| 273 | crie.cri_next = &cria; | |
| 274 | } | |
| 275 | ||
| 276 | if (thash) { | |
| 277 | cria.cri_alg = thash->type; | |
| 278 | cria.cri_klen = sop->mackeylen * 8; | |
| 279 | if (sop->mackeylen != thash->keysize) { | |
| 280 | error = EINVAL; | |
| 281 | goto bail; | |
| 282 | } | |
| 283 | ||
| 284 | if (cria.cri_klen) { | |
| 54734da1 | 285 | cria.cri_key = kmalloc(cria.cri_klen / 8, |
| 42ee1e6b | 286 | M_XDATA, M_WAITOK); |
| 984263bc MD |
287 | if ((error = copyin(sop->mackey, cria.cri_key, |
| 288 | cria.cri_klen / 8))) | |
| 289 | goto bail; | |
| 290 | } | |
| 291 | } | |
| 292 | ||
| 42ee1e6b SW |
293 | /* NB: CIOGSESSION2 has the crid */ |
| 294 | if (cmd == CIOCGSESSION2) { | |
| 295 | crid = SES2(sop)->crid; | |
| 296 | error = checkforsoftware(crid); | |
| 297 | if (error) | |
| 298 | goto bail; | |
| 7764fa66 | 299 | } else { |
| 42ee1e6b | 300 | crid = CRYPTOCAP_F_HARDWARE; |
| 7764fa66 AH |
301 | if (crypto_devallowsoft) |
| 302 | crid |= CRYPTOCAP_F_SOFTWARE; | |
| 303 | } | |
| 42ee1e6b | 304 | error = crypto_newsession(&sid, (txform ? &crie : &cria), crid); |
| 984263bc MD |
305 | if (error) |
| 306 | goto bail; | |
| 307 | ||
| 308 | cse = csecreate(fcr, sid, crie.cri_key, crie.cri_klen, | |
| 309 | cria.cri_key, cria.cri_klen, sop->cipher, sop->mac, txform, | |
| 310 | thash); | |
| 311 | ||
| 312 | if (cse == NULL) { | |
| 313 | crypto_freesession(sid); | |
| 314 | error = EINVAL; | |
| 315 | goto bail; | |
| 316 | } | |
| 317 | sop->ses = cse->ses; | |
| 42ee1e6b SW |
318 | if (cmd == CIOCGSESSION2) { |
| 319 | /* return hardware/driver id */ | |
| 320 | SES2(sop)->crid = CRYPTO_SESID2HID(cse->sid); | |
| 321 | } | |
| 984263bc MD |
322 | bail: |
| 323 | if (error) { | |
| d6715a19 AH |
324 | if (crie.cri_key) { |
| 325 | bzero(crie.cri_key, crie.cri_klen / 8); | |
| 42ee1e6b | 326 | kfree(crie.cri_key, M_XDATA); |
| d6715a19 AH |
327 | } |
| 328 | if (cria.cri_key) { | |
| 329 | bzero(crie.cri_key, crie.cri_klen / 8); | |
| 42ee1e6b | 330 | kfree(cria.cri_key, M_XDATA); |
| d6715a19 | 331 | } |
| 984263bc MD |
332 | } |
| 333 | break; | |
| 334 | case CIOCFSESSION: | |
| 335 | ses = *(u_int32_t *)data; | |
| 336 | cse = csefind(fcr, ses); | |
| 42ee1e6b SW |
337 | if (cse == NULL) |
| 338 | return (EINVAL); | |
| 984263bc MD |
339 | csedelete(fcr, cse); |
| 340 | error = csefree(cse); | |
| 341 | break; | |
| 342 | case CIOCCRYPT: | |
| 343 | cop = (struct crypt_op *)data; | |
| 344 | cse = csefind(fcr, cop->ses); | |
| 42ee1e6b SW |
345 | if (cse == NULL) |
| 346 | return (EINVAL); | |
| 54734da1 | 347 | error = cryptodev_op(cse, cop, cred); |
| 984263bc MD |
348 | break; |
| 349 | case CIOCKEY: | |
| 42ee1e6b SW |
350 | case CIOCKEY2: |
| 351 | if (!crypto_userasymcrypto) | |
| 352 | return (EPERM); /* XXX compat? */ | |
| 353 | get_mplock(); | |
| 354 | kop = (struct crypt_kop *)data; | |
| 355 | if (cmd == CIOCKEY) { | |
| 356 | /* NB: crypto core enforces s/w driver use */ | |
| 357 | kop->crk_crid = | |
| 358 | CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE; | |
| 359 | } | |
| 360 | error = cryptodev_key(kop); | |
| 361 | rel_mplock(); | |
| 984263bc MD |
362 | break; |
| 363 | case CIOCASYMFEAT: | |
| 42ee1e6b SW |
364 | if (!crypto_userasymcrypto) { |
| 365 | /* | |
| 366 | * NB: if user asym crypto operations are | |
| 367 | * not permitted return "no algorithms" | |
| 368 | * so well-behaved applications will just | |
| 369 | * fallback to doing them in software. | |
| 370 | */ | |
| 371 | *(int *)data = 0; | |
| 372 | } else | |
| 373 | error = crypto_getfeat((int *)data); | |
| 374 | break; | |
| 375 | case CIOCFINDDEV: | |
| 376 | error = cryptodev_find((struct crypt_find_op *)data); | |
| 984263bc MD |
377 | break; |
| 378 | default: | |
| 379 | error = EINVAL; | |
| d9b2033e | 380 | break; |
| 984263bc MD |
381 | } |
| 382 | return (error); | |
| 42ee1e6b | 383 | #undef SES2 |
| 984263bc MD |
384 | } |
| 385 | ||
| 386 | static int cryptodev_cb(void *); | |
| 387 | ||
| 388 | ||
| 389 | static int | |
| 42ee1e6b SW |
390 | cryptodev_op(struct csession *cse, struct crypt_op *cop, |
| 391 | struct ucred *active_cred) | |
| 984263bc MD |
392 | { |
| 393 | struct cryptop *crp = NULL; | |
| 394 | struct cryptodesc *crde = NULL, *crda = NULL; | |
| 42ee1e6b | 395 | int error; |
| 984263bc MD |
396 | |
| 397 | if (cop->len > 256*1024-4) | |
| 398 | return (E2BIG); | |
| 399 | ||
| 42ee1e6b SW |
400 | if (cse->txform) { |
| 401 | if (cop->len == 0 || (cop->len % cse->txform->blocksize) != 0) | |
| 402 | return (EINVAL); | |
| 403 | } | |
| 984263bc MD |
404 | |
| 405 | bzero(&cse->uio, sizeof(cse->uio)); | |
| 42ee1e6b | 406 | cse->uio.uio_iov = &cse->iovec; |
| 984263bc | 407 | cse->uio.uio_iovcnt = 1; |
| 42ee1e6b SW |
408 | cse->uio.uio_offset = 0; |
| 409 | cse->uio.uio_resid = cop->len; | |
| 984263bc MD |
410 | cse->uio.uio_segflg = UIO_SYSSPACE; |
| 411 | cse->uio.uio_rw = UIO_WRITE; | |
| 54734da1 AH |
412 | /* XXX: not sure, was td, now curthread? */ |
| 413 | cse->uio.uio_td = curthread; | |
| 984263bc | 414 | cse->uio.uio_iov[0].iov_len = cop->len; |
| 42ee1e6b SW |
415 | if (cse->thash) { |
| 416 | cse->uio.uio_iov[0].iov_len += cse->thash->hashsize; | |
| 417 | cse->uio.uio_resid += cse->thash->hashsize; | |
| 418 | } | |
| 419 | cse->uio.uio_iov[0].iov_base = kmalloc(cse->uio.uio_iov[0].iov_len, | |
| 420 | M_XDATA, M_WAITOK); | |
| 984263bc MD |
421 | |
| 422 | crp = crypto_getreq((cse->txform != NULL) + (cse->thash != NULL)); | |
| 423 | if (crp == NULL) { | |
| 424 | error = ENOMEM; | |
| 425 | goto bail; | |
| 426 | } | |
| 427 | ||
| 428 | if (cse->thash) { | |
| 429 | crda = crp->crp_desc; | |
| 430 | if (cse->txform) | |
| 431 | crde = crda->crd_next; | |
| 432 | } else { | |
| 433 | if (cse->txform) | |
| 434 | crde = crp->crp_desc; | |
| 435 | else { | |
| 436 | error = EINVAL; | |
| 437 | goto bail; | |
| 438 | } | |
| 439 | } | |
| 440 | ||
| 441 | if ((error = copyin(cop->src, cse->uio.uio_iov[0].iov_base, cop->len))) | |
| 442 | goto bail; | |
| 443 | ||
| 444 | if (crda) { | |
| 445 | crda->crd_skip = 0; | |
| 446 | crda->crd_len = cop->len; | |
| 42ee1e6b | 447 | crda->crd_inject = cop->len; |
| 984263bc MD |
448 | |
| 449 | crda->crd_alg = cse->mac; | |
| 450 | crda->crd_key = cse->mackey; | |
| 451 | crda->crd_klen = cse->mackeylen * 8; | |
| 452 | } | |
| 453 | ||
| 454 | if (crde) { | |
| 455 | if (cop->op == COP_ENCRYPT) | |
| 456 | crde->crd_flags |= CRD_F_ENCRYPT; | |
| 457 | else | |
| 458 | crde->crd_flags &= ~CRD_F_ENCRYPT; | |
| 459 | crde->crd_len = cop->len; | |
| 460 | crde->crd_inject = 0; | |
| 461 | ||
| 462 | crde->crd_alg = cse->cipher; | |
| 463 | crde->crd_key = cse->key; | |
| 464 | crde->crd_klen = cse->keylen * 8; | |
| 465 | } | |
| 466 | ||
| 467 | crp->crp_ilen = cop->len; | |
| 468 | crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM | |
| 469 | | (cop->flags & COP_F_BATCH); | |
| 470 | crp->crp_buf = (caddr_t)&cse->uio; | |
| 471 | crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb; | |
| 472 | crp->crp_sid = cse->sid; | |
| 473 | crp->crp_opaque = (void *)cse; | |
| 474 | ||
| 475 | if (cop->iv) { | |
| 476 | if (crde == NULL) { | |
| 477 | error = EINVAL; | |
| 478 | goto bail; | |
| 479 | } | |
| 480 | if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */ | |
| 481 | error = EINVAL; | |
| 482 | goto bail; | |
| 483 | } | |
| 484 | if ((error = copyin(cop->iv, cse->tmp_iv, cse->txform->blocksize))) | |
| 485 | goto bail; | |
| 486 | bcopy(cse->tmp_iv, crde->crd_iv, cse->txform->blocksize); | |
| 487 | crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT; | |
| 488 | crde->crd_skip = 0; | |
| 489 | } else if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */ | |
| 490 | crde->crd_skip = 0; | |
| 491 | } else if (crde) { | |
| 492 | crde->crd_flags |= CRD_F_IV_PRESENT; | |
| 493 | crde->crd_skip = cse->txform->blocksize; | |
| 494 | crde->crd_len -= cse->txform->blocksize; | |
| 495 | } | |
| 496 | ||
| 42ee1e6b SW |
497 | if (cop->mac && crda == NULL) { |
| 498 | error = EINVAL; | |
| 499 | goto bail; | |
| 984263bc MD |
500 | } |
| 501 | ||
| 42ee1e6b SW |
502 | again: |
| 503 | /* | |
| 504 | * Let the dispatch run unlocked, then, interlock against the | |
| 505 | * callback before checking if the operation completed and going | |
| 506 | * to sleep. This insures drivers don't inherit our lock which | |
| 507 | * results in a lock order reversal between crypto_dispatch forced | |
| 508 | * entry and the crypto_done callback into us. | |
| 509 | */ | |
| 984263bc | 510 | error = crypto_dispatch(crp); |
| 42ee1e6b | 511 | lockmgr(&cse->lock, LK_EXCLUSIVE); |
| 984263bc | 512 | if (error == 0 && (crp->crp_flags & CRYPTO_F_DONE) == 0) |
| 54734da1 | 513 | error = lksleep(crp, &cse->lock, 0, "crydev", 0); |
| 42ee1e6b SW |
514 | lockmgr(&cse->lock, LK_RELEASE); |
| 515 | ||
| 516 | if (error != 0) | |
| 984263bc MD |
517 | goto bail; |
| 518 | ||
| 42ee1e6b SW |
519 | if (crp->crp_etype == EAGAIN) { |
| 520 | crp->crp_etype = 0; | |
| 521 | crp->crp_flags &= ~CRYPTO_F_DONE; | |
| 522 | goto again; | |
| 523 | } | |
| 524 | ||
| 984263bc MD |
525 | if (crp->crp_etype != 0) { |
| 526 | error = crp->crp_etype; | |
| 527 | goto bail; | |
| 528 | } | |
| 529 | ||
| 530 | if (cse->error) { | |
| 531 | error = cse->error; | |
| 532 | goto bail; | |
| 533 | } | |
| 534 | ||
| 535 | if (cop->dst && | |
| 536 | (error = copyout(cse->uio.uio_iov[0].iov_base, cop->dst, cop->len))) | |
| 537 | goto bail; | |
| 538 | ||
| 539 | if (cop->mac && | |
| 42ee1e6b SW |
540 | (error = copyout((caddr_t)cse->uio.uio_iov[0].iov_base + cop->len, |
| 541 | cop->mac, cse->thash->hashsize))) | |
| 984263bc MD |
542 | goto bail; |
| 543 | ||
| 544 | bail: | |
| 545 | if (crp) | |
| 546 | crypto_freereq(crp); | |
| 547 | if (cse->uio.uio_iov[0].iov_base) | |
| efda3bd0 | 548 | kfree(cse->uio.uio_iov[0].iov_base, M_XDATA); |
| 984263bc MD |
549 | |
| 550 | return (error); | |
| 551 | } | |
| 552 | ||
| 553 | static int | |
| 554 | cryptodev_cb(void *op) | |
| 555 | { | |
| 556 | struct cryptop *crp = (struct cryptop *) op; | |
| 557 | struct csession *cse = (struct csession *)crp->crp_opaque; | |
| 558 | ||
| 42ee1e6b | 559 | lockmgr(&cse->lock, LK_EXCLUSIVE); |
| 984263bc | 560 | cse->error = crp->crp_etype; |
| 984263bc | 561 | wakeup_one(crp); |
| 42ee1e6b | 562 | lockmgr(&cse->lock, LK_RELEASE); |
| 984263bc MD |
563 | return (0); |
| 564 | } | |
| 565 | ||
| 566 | static int | |
| 567 | cryptodevkey_cb(void *op) | |
| 568 | { | |
| 569 | struct cryptkop *krp = (struct cryptkop *) op; | |
| 570 | ||
| 571 | wakeup_one(krp); | |
| 572 | return (0); | |
| 573 | } | |
| 574 | ||
| 575 | static int | |
| 576 | cryptodev_key(struct crypt_kop *kop) | |
| 577 | { | |
| 578 | struct cryptkop *krp = NULL; | |
| 579 | int error = EINVAL; | |
| 580 | int in, out, size, i; | |
| 581 | ||
| 582 | if (kop->crk_iparams + kop->crk_oparams > CRK_MAXPARAM) { | |
| 583 | return (EFBIG); | |
| 584 | } | |
| 585 | ||
| 586 | in = kop->crk_iparams; | |
| 587 | out = kop->crk_oparams; | |
| 588 | switch (kop->crk_op) { | |
| 589 | case CRK_MOD_EXP: | |
| 590 | if (in == 3 && out == 1) | |
| 591 | break; | |
| 592 | return (EINVAL); | |
| 593 | case CRK_MOD_EXP_CRT: | |
| 594 | if (in == 6 && out == 1) | |
| 595 | break; | |
| 596 | return (EINVAL); | |
| 597 | case CRK_DSA_SIGN: | |
| 598 | if (in == 5 && out == 2) | |
| 599 | break; | |
| 600 | return (EINVAL); | |
| 601 | case CRK_DSA_VERIFY: | |
| 602 | if (in == 7 && out == 0) | |
| 603 | break; | |
| 604 | return (EINVAL); | |
| 605 | case CRK_DH_COMPUTE_KEY: | |
| 606 | if (in == 3 && out == 1) | |
| 607 | break; | |
| 608 | return (EINVAL); | |
| 609 | default: | |
| 610 | return (EINVAL); | |
| 611 | } | |
| 612 | ||
| e7b4468c | 613 | krp = (struct cryptkop *)kmalloc(sizeof *krp, M_XDATA, M_WAITOK | M_ZERO); |
| 984263bc MD |
614 | krp->krp_op = kop->crk_op; |
| 615 | krp->krp_status = kop->crk_status; | |
| 616 | krp->krp_iparams = kop->crk_iparams; | |
| 617 | krp->krp_oparams = kop->crk_oparams; | |
| 42ee1e6b | 618 | krp->krp_crid = kop->crk_crid; |
| 984263bc MD |
619 | krp->krp_status = 0; |
| 620 | krp->krp_callback = (int (*) (struct cryptkop *)) cryptodevkey_cb; | |
| 621 | ||
| 42ee1e6b SW |
622 | for (i = 0; i < CRK_MAXPARAM; i++) { |
| 623 | if (kop->crk_param[i].crp_nbits > 65536) | |
| 624 | /* Limit is the same as in OpenBSD */ | |
| 625 | goto fail; | |
| 984263bc | 626 | krp->krp_param[i].crp_nbits = kop->crk_param[i].crp_nbits; |
| 42ee1e6b | 627 | } |
| 984263bc MD |
628 | for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) { |
| 629 | size = (krp->krp_param[i].crp_nbits + 7) / 8; | |
| 630 | if (size == 0) | |
| 631 | continue; | |
| 42ee1e6b | 632 | krp->krp_param[i].crp_p = kmalloc(size, M_XDATA, M_WAITOK); |
| 984263bc MD |
633 | if (i >= krp->krp_iparams) |
| 634 | continue; | |
| 635 | error = copyin(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p, size); | |
| 636 | if (error) | |
| 637 | goto fail; | |
| 638 | } | |
| 639 | ||
| 640 | error = crypto_kdispatch(krp); | |
| 984263bc MD |
641 | if (error) |
| 642 | goto fail; | |
| 54734da1 | 643 | error = tsleep(krp, 0, "crydev", 0); |
| 42ee1e6b SW |
644 | if (error) { |
| 645 | /* XXX can this happen? if so, how do we recover? */ | |
| 646 | goto fail; | |
| 647 | } | |
| 984263bc | 648 | |
| 42ee1e6b | 649 | kop->crk_crid = krp->krp_crid; /* device that did the work */ |
| 984263bc MD |
650 | if (krp->krp_status != 0) { |
| 651 | error = krp->krp_status; | |
| 652 | goto fail; | |
| 653 | } | |
| 654 | ||
| 655 | for (i = krp->krp_iparams; i < krp->krp_iparams + krp->krp_oparams; i++) { | |
| 656 | size = (krp->krp_param[i].crp_nbits + 7) / 8; | |
| 657 | if (size == 0) | |
| 658 | continue; | |
| 659 | error = copyout(krp->krp_param[i].crp_p, kop->crk_param[i].crp_p, size); | |
| 660 | if (error) | |
| 661 | goto fail; | |
| 662 | } | |
| 663 | ||
| 664 | fail: | |
| 665 | if (krp) { | |
| 666 | kop->crk_status = krp->krp_status; | |
| 667 | for (i = 0; i < CRK_MAXPARAM; i++) { | |
| d6715a19 AH |
668 | if (krp->krp_param[i].crp_p) { |
| 669 | bzero(krp->krp_param[i].crp_p, | |
| 670 | (krp->krp_param[i].crp_nbits + 7) / 8); | |
| 42ee1e6b | 671 | kfree(krp->krp_param[i].crp_p, M_XDATA); |
| d6715a19 | 672 | } |
| 984263bc | 673 | } |
| efda3bd0 | 674 | kfree(krp, M_XDATA); |
| 984263bc MD |
675 | } |
| 676 | return (error); | |
| 677 | } | |
| 678 | ||
| 42ee1e6b SW |
679 | static int |
| 680 | cryptodev_find(struct crypt_find_op *find) | |
| 681 | { | |
| 682 | device_t dev; | |
| 683 | ||
| 684 | if (find->crid != -1) { | |
| 685 | dev = crypto_find_device_byhid(find->crid); | |
| 686 | if (dev == NULL) | |
| 687 | return (ENOENT); | |
| 688 | strlcpy(find->name, device_get_nameunit(dev), | |
| 689 | sizeof(find->name)); | |
| 690 | } else { | |
| 691 | find->crid = crypto_find_driver(find->name); | |
| 692 | if (find->crid == -1) | |
| 693 | return (ENOENT); | |
| 694 | } | |
| 695 | return (0); | |
| 696 | } | |
| 697 | ||
| d9b2033e MD |
698 | /* |
| 699 | * MPSAFE | |
| 700 | */ | |
| 984263bc | 701 | static int |
| 984263bc MD |
702 | cryptof_kqfilter(struct file *fp, struct knote *kn) |
| 703 | { | |
| 704 | ||
| 705 | return (0); | |
| 706 | } | |
| 707 | ||
| d9b2033e MD |
708 | /* |
| 709 | * MPSAFE | |
| 710 | */ | |
| 984263bc | 711 | static int |
| 87de5057 | 712 | cryptof_stat(struct file *fp, struct stat *sb, struct ucred *cred) |
| 984263bc | 713 | { |
| 984263bc MD |
714 | return (EOPNOTSUPP); |
| 715 | } | |
| 716 | ||
| d9b2033e MD |
717 | /* |
| 718 | * MPALMOSTSAFE - acquires mplock | |
| 719 | */ | |
| 984263bc | 720 | static int |
| 87de5057 | 721 | cryptof_close(struct file *fp) |
| 984263bc | 722 | { |
| 42ee1e6b | 723 | struct fcrypt *fcr = fp->f_data; |
| 984263bc MD |
724 | struct csession *cse; |
| 725 | ||
| d9b2033e MD |
726 | get_mplock(); |
| 727 | fcr = (struct fcrypt *)fp->f_data; | |
| 984263bc MD |
728 | while ((cse = TAILQ_FIRST(&fcr->csessions))) { |
| 729 | TAILQ_REMOVE(&fcr->csessions, cse, next); | |
| 730 | (void)csefree(cse); | |
| 731 | } | |
| 984263bc | 732 | fp->f_data = NULL; |
| d9b2033e MD |
733 | rel_mplock(); |
| 734 | ||
| 42ee1e6b | 735 | kfree(fcr, M_XDATA); |
| d9b2033e | 736 | return (0); |
| 984263bc MD |
737 | } |
| 738 | ||
| 739 | static struct csession * | |
| 740 | csefind(struct fcrypt *fcr, u_int ses) | |
| 741 | { | |
| 742 | struct csession *cse; | |
| 743 | ||
| 744 | TAILQ_FOREACH(cse, &fcr->csessions, next) | |
| 745 | if (cse->ses == ses) | |
| 746 | return (cse); | |
| 747 | return (NULL); | |
| 748 | } | |
| 749 | ||
| 750 | static int | |
| 751 | csedelete(struct fcrypt *fcr, struct csession *cse_del) | |
| 752 | { | |
| 753 | struct csession *cse; | |
| 754 | ||
| 755 | TAILQ_FOREACH(cse, &fcr->csessions, next) { | |
| 756 | if (cse == cse_del) { | |
| 757 | TAILQ_REMOVE(&fcr->csessions, cse, next); | |
| 758 | return (1); | |
| 759 | } | |
| 760 | } | |
| 761 | return (0); | |
| 762 | } | |
| 763 | ||
| 764 | static struct csession * | |
| 765 | cseadd(struct fcrypt *fcr, struct csession *cse) | |
| 766 | { | |
| 767 | TAILQ_INSERT_TAIL(&fcr->csessions, cse, next); | |
| 768 | cse->ses = fcr->sesn++; | |
| 769 | return (cse); | |
| 770 | } | |
| 771 | ||
| 772 | struct csession * | |
| 773 | csecreate(struct fcrypt *fcr, u_int64_t sid, caddr_t key, u_int64_t keylen, | |
| 774 | caddr_t mackey, u_int64_t mackeylen, u_int32_t cipher, u_int32_t mac, | |
| 775 | struct enc_xform *txform, struct auth_hash *thash) | |
| 776 | { | |
| 777 | struct csession *cse; | |
| 778 | ||
| a0419b33 | 779 | cse = kmalloc(sizeof(struct csession), M_XDATA, M_WAITOK | M_ZERO); |
| 54734da1 | 780 | lockinit(&cse->lock, "cryptodev", 0, LK_CANRECURSE); |
| 984263bc MD |
781 | cse->key = key; |
| 782 | cse->keylen = keylen/8; | |
| 783 | cse->mackey = mackey; | |
| 784 | cse->mackeylen = mackeylen/8; | |
| 785 | cse->sid = sid; | |
| 786 | cse->cipher = cipher; | |
| 787 | cse->mac = mac; | |
| 788 | cse->txform = txform; | |
| 789 | cse->thash = thash; | |
| 790 | cseadd(fcr, cse); | |
| 791 | return (cse); | |
| 792 | } | |
| 793 | ||
| 794 | static int | |
| 795 | csefree(struct csession *cse) | |
| 796 | { | |
| 797 | int error; | |
| 798 | ||
| 799 | error = crypto_freesession(cse->sid); | |
| 42ee1e6b | 800 | lockuninit(&cse->lock); |
| 984263bc | 801 | if (cse->key) |
| 42ee1e6b | 802 | kfree(cse->key, M_XDATA); |
| 984263bc | 803 | if (cse->mackey) |
| 42ee1e6b SW |
804 | kfree(cse->mackey, M_XDATA); |
| 805 | kfree(cse, M_XDATA); | |
| 984263bc MD |
806 | return (error); |
| 807 | } | |
| 808 | ||
| 809 | static int | |
| fef8985e | 810 | cryptoopen(struct dev_open_args *ap) |
| 984263bc | 811 | { |
| 984263bc MD |
812 | return (0); |
| 813 | } | |
| 814 | ||
| 815 | static int | |
| fef8985e | 816 | cryptoread(struct dev_read_args *ap) |
| 984263bc MD |
817 | { |
| 818 | return (EIO); | |
| 819 | } | |
| 820 | ||
| 821 | static int | |
| fef8985e | 822 | cryptowrite(struct dev_write_args *ap) |
| 984263bc MD |
823 | { |
| 824 | return (EIO); | |
| 825 | } | |
| 826 | ||
| 827 | static int | |
| fef8985e | 828 | cryptoioctl(struct dev_ioctl_args *ap) |
| 984263bc | 829 | { |
| f3a2d8c4 | 830 | struct thread *td = curthread; |
| 984263bc MD |
831 | struct file *f; |
| 832 | struct fcrypt *fcr; | |
| 833 | int fd, error; | |
| fef8985e MD |
834 | |
| 835 | switch (ap->a_cmd) { | |
| 984263bc | 836 | case CRIOGET: |
| 42ee1e6b | 837 | fcr = kmalloc(sizeof(struct fcrypt), M_XDATA, M_WAITOK); |
| 984263bc MD |
838 | TAILQ_INIT(&fcr->csessions); |
| 839 | fcr->sesn = 0; | |
| 840 | ||
| f3a2d8c4 MD |
841 | KKASSERT(td->td_lwp); |
| 842 | error = falloc(td->td_lwp, &f, &fd); | |
| 984263bc MD |
843 | |
| 844 | if (error) { | |
| 42ee1e6b | 845 | kfree(fcr, M_XDATA); |
| 984263bc MD |
846 | return (error); |
| 847 | } | |
| 42ee1e6b | 848 | /* falloc automatically provides an extra reference to 'f'. */ |
| 54734da1 AH |
849 | f->f_flag = FREAD | FWRITE; |
| 850 | f->f_type = DTYPE_CRYPTO; | |
| 851 | f->f_ops = &cryptofops; | |
| 852 | f->f_data = fcr; | |
| f3a2d8c4 | 853 | fsetfd(td->td_proc->p_fd, f, fd); |
| 54734da1 AH |
854 | *(u_int32_t *)ap->a_data = fd; |
| 855 | fdrop(f); | |
| 856 | ||
| 42ee1e6b SW |
857 | break; |
| 858 | case CRIOFINDDEV: | |
| 54734da1 | 859 | error = cryptodev_find((struct crypt_find_op *)ap->a_data); |
| 42ee1e6b SW |
860 | break; |
| 861 | case CRIOASYMFEAT: | |
| 54734da1 | 862 | error = crypto_getfeat((int *)ap->a_data); |
| 984263bc MD |
863 | break; |
| 864 | default: | |
| 865 | error = EINVAL; | |
| 866 | break; | |
| 867 | } | |
| 868 | return (error); | |
| 869 | } | |
| 870 | ||
| fef8985e | 871 | static struct dev_ops crypto_ops = { |
| 9f889dc4 | 872 | { "crypto", 0, D_MPSAFE }, |
| fef8985e | 873 | .d_open = cryptoopen, |
| fef8985e MD |
874 | .d_read = cryptoread, |
| 875 | .d_write = cryptowrite, | |
| 876 | .d_ioctl = cryptoioctl, | |
| 984263bc | 877 | }; |
| 984263bc MD |
878 | |
| 879 | /* | |
| 880 | * Initialization code, both for static and dynamic loading. | |
| 881 | */ | |
| 882 | static int | |
| 883 | cryptodev_modevent(module_t mod, int type, void *unused) | |
| 884 | { | |
| 885 | switch (type) { | |
| 886 | case MOD_LOAD: | |
| 887 | if (bootverbose) | |
| 26be20a0 | 888 | kprintf("crypto: <crypto device>\n"); |
| fef8985e | 889 | make_dev(&crypto_ops, 0, UID_ROOT, GID_WHEEL, |
| 3e82b46c | 890 | 0666, "crypto"); |
| 984263bc MD |
891 | return 0; |
| 892 | case MOD_UNLOAD: | |
| 893 | /*XXX disallow if active sessions */ | |
| cd29885a MD |
894 | //dev_ops_remove(&crypto_ops, 0, 0); |
| 895 | dev_ops_remove_all(&crypto_ops); | |
| 984263bc MD |
896 | return 0; |
| 897 | } | |
| 898 | return EINVAL; | |
| 899 | } | |
| 900 | ||
| 901 | static moduledata_t cryptodev_mod = { | |
| 902 | "cryptodev", | |
| 903 | cryptodev_modevent, | |
| 904 | 0 | |
| 905 | }; | |
| 906 | MODULE_VERSION(cryptodev, 1); | |
| 907 | DECLARE_MODULE(cryptodev, cryptodev_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); | |
| 984263bc | 908 | MODULE_DEPEND(cryptodev, crypto, 1, 1, 1); |
| 42ee1e6b | 909 | MODULE_DEPEND(cryptodev, zlib, 1, 1, 1); |