compat: use compat_ptr() and ptr_to_compat()
[cryptodev-linux.git] / cryptodev_main.c
blobdfbc23182ab01a181d237c16aece398be8d682f7
1 /*
2 * Driver for /dev/crypto device (aka CryptoDev)
4 * Copyright (c) 2004 Michal Ludvig <mludvig@logix.net.nz>, SuSE Labs
5 * Copyright (c) 2009,2010 Nikos Mavrogiannopoulos <nmav@gnutls.org>
7 * This file is part of linux cryptodev.
9 * cryptodev is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * cryptodev is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * Device /dev/crypto provides an interface for
25 * accessing kernel CryptoAPI algorithms (ciphers,
26 * hashes) from userspace programs.
28 * /dev/crypto interface was originally introduced in
29 * OpenBSD and this module attempts to keep the API.
33 #include <linux/crypto.h>
34 #include <linux/mm.h>
35 #include <linux/highmem.h>
36 #include <linux/random.h>
37 #include "cryptodev.h"
38 #include <asm/uaccess.h>
39 #include <asm/ioctl.h>
40 #include <linux/scatterlist.h>
41 #include "cryptodev_int.h"
42 #include "version.h"
44 MODULE_AUTHOR("Nikos Mavrogiannopoulos <nmav@gnutls.org>");
45 MODULE_DESCRIPTION("CryptoDev driver");
46 MODULE_LICENSE("GPL");
48 /* ====== Compile-time config ====== */
50 #define CRYPTODEV_STATS
52 /* ====== Module parameters ====== */
54 int cryptodev_verbosity = 0;
55 module_param(cryptodev_verbosity, int, 0644);
56 MODULE_PARM_DESC(cryptodev_verbosity, "0: normal, 1: verbose, 2: debug");
58 #ifdef CRYPTODEV_STATS
59 static int enable_stats = 0;
60 module_param(enable_stats, int, 0644);
61 MODULE_PARM_DESC(enable_stats, "collect statictics about cryptodev usage");
62 #endif
64 /* ====== CryptoAPI ====== */
66 #define FILL_SG(sg,ptr,len) \
67 do { \
68 (sg)->page = virt_to_page(ptr); \
69 (sg)->offset = offset_in_page(ptr); \
70 (sg)->length = len; \
71 (sg)->dma_address = 0; \
72 } while (0)
74 struct csession {
75 struct list_head entry;
76 struct semaphore sem;
77 struct cipher_data cdata;
78 struct hash_data hdata;
79 uint32_t sid;
80 #ifdef CRYPTODEV_STATS
81 #if ! ((COP_ENCRYPT < 2) && (COP_DECRYPT < 2))
82 #error Struct csession.stat uses COP_{ENCRYPT,DECRYPT} as indices. Do something!
83 #endif
84 unsigned long long stat[2];
85 size_t stat_max_size, stat_count;
86 #endif
89 struct fcrypt {
90 struct list_head list;
91 struct semaphore sem;
94 /* Prepare session for future use. */
95 static int
96 crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
98 struct csession *ses_new = NULL, *ses_ptr;
99 int ret = 0;
100 const char *alg_name=NULL;
101 const char *hash_name=NULL;
102 int hmac_mode = 1;
104 /* Does the request make sense? */
105 if (unlikely(!sop->cipher && !sop->mac)) {
106 dprintk(1,KERN_DEBUG,"Both 'cipher' and 'mac' unset.\n");
107 return -EINVAL;
110 switch (sop->cipher) {
111 case 0:
112 break;
113 case CRYPTO_DES_CBC:
114 alg_name = "cbc(des)";
115 break;
116 case CRYPTO_3DES_CBC:
117 alg_name = "cbc(des3_ede)";
118 break;
119 case CRYPTO_BLF_CBC:
120 alg_name = "cbc(blowfish)";
121 break;
122 case CRYPTO_AES_CBC:
123 alg_name = "cbc(aes)";
124 break;
125 case CRYPTO_CAMELLIA_CBC:
126 alg_name = "cbc(camelia)";
127 break;
128 default:
129 dprintk(1,KERN_DEBUG,"%s: bad cipher: %d\n", __func__, sop->cipher);
130 return -EINVAL;
133 switch (sop->mac) {
134 case 0:
135 break;
136 case CRYPTO_MD5_HMAC:
137 hash_name = "hmac(md5)";
138 break;
139 case CRYPTO_RIPEMD160_HMAC:
140 hash_name = "hmac(rmd160)";
141 break;
142 case CRYPTO_SHA1_HMAC:
143 hash_name = "hmac(sha1)";
144 break;
145 case CRYPTO_SHA2_256_HMAC:
146 hash_name = "hmac(sha256)";
147 break;
148 case CRYPTO_SHA2_384_HMAC:
149 hash_name = "hmac(sha384)";
150 break;
151 case CRYPTO_SHA2_512_HMAC:
152 hash_name = "hmac(sha512)";
153 break;
155 /* non-hmac cases */
156 case CRYPTO_MD5:
157 hash_name = "md5";
158 hmac_mode = 0;
159 break;
160 case CRYPTO_RIPEMD160:
161 hash_name = "rmd160";
162 hmac_mode = 0;
163 break;
164 case CRYPTO_SHA1:
165 hash_name = "sha1";
166 hmac_mode = 0;
167 break;
168 case CRYPTO_SHA2_256:
169 hash_name = "sha256";
170 hmac_mode = 0;
171 break;
172 case CRYPTO_SHA2_384:
173 hash_name = "sha384";
174 hmac_mode = 0;
175 break;
176 case CRYPTO_SHA2_512:
177 hash_name = "sha512";
178 hmac_mode = 0;
179 break;
181 default:
182 dprintk(1,KERN_DEBUG,"%s: bad mac: %d\n", __func__, sop->mac);
183 return -EINVAL;
186 /* Create a session and put it to the list. */
187 ses_new = kmalloc(sizeof(*ses_new), GFP_KERNEL);
188 if(!ses_new) {
189 return -ENOMEM;
192 memset(ses_new, 0, sizeof(*ses_new));
194 /* Set-up crypto transform. */
195 if (alg_name) {
196 ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, sop->key, sop->keylen);
197 if (ret < 0) {
198 dprintk(1,KERN_DEBUG,"%s: Failed to load cipher for %s\n", __func__,
199 alg_name);
200 ret = -EINVAL;
201 goto error_cipher;
205 if (hash_name) {
206 ret = cryptodev_hash_init(&ses_new->hdata, hash_name, hmac_mode, sop->mackey, sop->mackeylen);
207 if (ret != 0) {
208 dprintk(1,KERN_DEBUG,"%s: Failed to load hash for %s\n", __func__,
209 hash_name);
210 ret = -EINVAL;
211 goto error_hash;
215 /* put the new session to the list */
216 get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
217 init_MUTEX(&ses_new->sem);
219 down(&fcr->sem);
220 restart:
221 list_for_each_entry(ses_ptr, &fcr->list, entry) {
222 /* Check for duplicate SID */
223 if (unlikely(ses_new->sid == ses_ptr->sid)) {
224 get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
225 /* Unless we have a broken RNG this
226 shouldn't loop forever... ;-) */
227 goto restart;
231 list_add(&ses_new->entry, &fcr->list);
232 up(&fcr->sem);
234 /* Fill in some values for the user. */
235 sop->ses = ses_new->sid;
237 return 0;
239 error_hash:
240 cryptodev_cipher_deinit( &ses_new->cdata);
241 error_cipher:
242 if (ses_new) kfree(ses_new);
244 return ret;
248 /* Everything that needs to be done when remowing a session. */
249 static inline void
250 crypto_destroy_session(struct csession *ses_ptr)
252 if(down_trylock(&ses_ptr->sem)) {
253 dprintk(2, KERN_DEBUG, "Waiting for semaphore of sid=0x%08X\n",
254 ses_ptr->sid);
255 down(&ses_ptr->sem);
257 dprintk(2, KERN_DEBUG, "Removed session 0x%08X\n", ses_ptr->sid);
258 #if defined(CRYPTODEV_STATS)
259 if(enable_stats)
260 dprintk(2, KERN_DEBUG,
261 "Usage in Bytes: enc=%llu, dec=%llu, max=%zu, avg=%lu, cnt=%zu\n",
262 ses_ptr->stat[COP_ENCRYPT], ses_ptr->stat[COP_DECRYPT],
263 ses_ptr->stat_max_size, ses_ptr->stat_count > 0
264 ? ((unsigned long)(ses_ptr->stat[COP_ENCRYPT]+
265 ses_ptr->stat[COP_DECRYPT]) /
266 ses_ptr->stat_count) : 0,
267 ses_ptr->stat_count);
268 #endif
269 cryptodev_cipher_deinit(&ses_ptr->cdata);
270 cryptodev_hash_deinit(&ses_ptr->hdata);
271 up(&ses_ptr->sem);
272 kfree(ses_ptr);
275 /* Look up a session by ID and remove. */
276 static int
277 crypto_finish_session(struct fcrypt *fcr, uint32_t sid)
279 struct csession *tmp, *ses_ptr;
280 struct list_head *head;
281 int ret = 0;
283 down(&fcr->sem);
284 head = &fcr->list;
285 list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
286 if(ses_ptr->sid == sid) {
287 list_del(&ses_ptr->entry);
288 crypto_destroy_session(ses_ptr);
289 break;
293 if (unlikely(!ses_ptr)) {
294 dprintk(1, KERN_ERR, "Session with sid=0x%08X not found!\n", sid);
295 ret = -ENOENT;
297 up(&fcr->sem);
299 return ret;
302 /* Remove all sessions when closing the file */
303 static int
304 crypto_finish_all_sessions(struct fcrypt *fcr)
306 struct csession *tmp, *ses_ptr;
307 struct list_head *head;
309 down(&fcr->sem);
311 head = &fcr->list;
312 list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
313 list_del(&ses_ptr->entry);
314 crypto_destroy_session(ses_ptr);
316 up(&fcr->sem);
318 return 0;
321 /* Look up session by session ID. The returned session is locked. */
322 static struct csession *
323 crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid)
325 struct csession *ses_ptr;
327 down(&fcr->sem);
328 list_for_each_entry(ses_ptr, &fcr->list, entry) {
329 if(ses_ptr->sid == sid) {
330 down(&ses_ptr->sem);
331 break;
334 up(&fcr->sem);
336 return ses_ptr;
339 /* This is the main crypto function - feed it with plaintext
340 and get a ciphertext (or vice versa :-) */
341 static int
342 crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
344 char *data;
345 char __user *src, __user *dst;
346 struct scatterlist sg;
347 struct csession *ses_ptr;
348 unsigned int ivsize=0;
349 size_t nbytes, bufsize;
350 int ret = 0;
351 uint8_t hash_output[AALG_MAX_RESULT_LEN];
353 if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) {
354 dprintk(1, KERN_DEBUG, "invalid operation op=%u\n", cop->op);
355 return -EINVAL;
358 ses_ptr = crypto_get_session_by_sid(fcr, cop->ses);
359 if (unlikely(!ses_ptr)) {
360 dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", cop->ses);
361 return -EINVAL;
364 nbytes = cop->len;
365 data = (char*)__get_free_page(GFP_KERNEL);
367 if (unlikely(!data)) {
368 ret = -ENOMEM;
369 goto out_unlock;
371 bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes;
373 nbytes = cop->len;
375 if (ses_ptr->hdata.init != 0) {
376 ret = cryptodev_hash_reset(&ses_ptr->hdata);
377 if (unlikely(ret)) {
378 dprintk(1, KERN_ERR,
379 "error in cryptodev_hash_reset()\n");
380 goto out_unlock;
384 if (ses_ptr->cdata.init != 0) {
385 int blocksize = ses_ptr->cdata.blocksize;
387 if (unlikely(nbytes % blocksize)) {
388 dprintk(1, KERN_ERR,
389 "data size (%zu) isn't a multiple of block size (%u)\n",
390 nbytes, blocksize);
391 ret = -EINVAL;
392 goto out_unlock;
395 ivsize = ses_ptr->cdata.ivsize;
397 if (cop->iv) {
398 cryptodev_cipher_set_iv(&ses_ptr->cdata, cop->iv, ivsize);
402 src = cop->src;
403 dst = cop->dst;
406 while(nbytes > 0) {
407 size_t current_len = nbytes > bufsize ? bufsize : nbytes;
409 ret = copy_from_user(data, src, current_len);
410 if (unlikely(ret))
411 goto out;
413 sg_init_one(&sg, data, current_len);
415 /* Always hash before encryption and after decryption. Maybe
416 * we should introduce a flag to switch... TBD later on.
418 if (cop->op == COP_ENCRYPT) {
419 if (ses_ptr->hdata.init != 0) {
420 ret = cryptodev_hash_update(&ses_ptr->hdata, &sg, current_len);
421 if (unlikely(ret)) {
422 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
423 goto out;
426 if (ses_ptr->cdata.init != 0) {
427 ret = cryptodev_cipher_encrypt( &ses_ptr->cdata, &sg, &sg, current_len);
429 if (unlikely(ret)) {
430 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
431 goto out;
433 if (unlikely(copy_to_user(dst, data, current_len)))
434 goto out;
435 dst += current_len;
437 } else {
438 if (ses_ptr->cdata.init != 0) {
439 ret = cryptodev_cipher_decrypt( &ses_ptr->cdata, &sg, &sg, current_len);
441 if (unlikely(ret)) {
442 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
443 goto out;
445 if (unlikely(copy_to_user(dst, data, current_len)))
446 goto out;
447 dst += current_len;
451 if (ses_ptr->hdata.init != 0) {
452 ret = cryptodev_hash_update(&ses_ptr->hdata, &sg, current_len);
453 if (unlikely(ret)) {
454 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
455 goto out;
460 nbytes -= current_len;
461 src += current_len;
464 if (ses_ptr->hdata.init != 0) {
465 ret = cryptodev_hash_final(&ses_ptr->hdata, hash_output);
466 if (unlikely(ret)) {
467 dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret);
468 goto out;
471 if (unlikely(copy_to_user(cop->mac, hash_output, ses_ptr->hdata.digestsize)))
472 goto out;
475 #if defined(CRYPTODEV_STATS)
476 if (enable_stats) {
477 /* this is safe - we check cop->op at the function entry */
478 ses_ptr->stat[cop->op] += cop->len;
479 if (ses_ptr->stat_max_size < cop->len)
480 ses_ptr->stat_max_size = cop->len;
481 ses_ptr->stat_count++;
483 #endif
485 out:
486 free_page((unsigned long)data);
488 out_unlock:
489 up(&ses_ptr->sem);
491 return ret;
494 /* ====== /dev/crypto ====== */
496 static int
497 cryptodev_open(struct inode *inode, struct file *filp)
499 struct fcrypt *fcr;
501 fcr = kmalloc(sizeof(*fcr), GFP_KERNEL);
502 if(!fcr)
503 return -ENOMEM;
505 memset(fcr, 0, sizeof(*fcr));
506 init_MUTEX(&fcr->sem);
507 INIT_LIST_HEAD(&fcr->list);
508 filp->private_data = fcr;
510 return 0;
513 static int
514 cryptodev_release(struct inode *inode, struct file *filp)
516 struct fcrypt *fcr = filp->private_data;
518 if(fcr) {
519 crypto_finish_all_sessions(fcr);
520 kfree(fcr);
521 filp->private_data = NULL;
524 return 0;
527 static int
528 clonefd(struct file *filp)
530 struct fdtable *fdt = files_fdtable(current->files);
531 int ret;
532 ret = get_unused_fd();
533 if (ret >= 0) {
534 get_file(filp);
535 FD_SET(ret, fdt->open_fds);
536 fd_install(ret, filp);
539 return ret;
542 static int
543 cryptodev_ioctl(struct inode *inode, struct file *filp,
544 unsigned int cmd, unsigned long arg)
546 int __user *p = (void __user *)arg;
547 struct session_op sop;
548 struct crypt_op cop;
549 struct fcrypt *fcr = filp->private_data;
550 uint32_t ses;
551 int ret, fd;
553 if (unlikely(!fcr))
554 BUG();
556 switch (cmd) {
557 case CIOCASYMFEAT:
558 put_user(0, p);
559 return 0;
560 case CRIOGET:
561 fd = clonefd(filp);
562 put_user(fd, p);
563 return 0;
565 case CIOCGSESSION:
566 ret = copy_from_user(&sop, (void*)arg, sizeof(sop));
567 if (unlikely(ret))
568 return ret;
570 ret = crypto_create_session(fcr, &sop);
571 if (unlikely(ret))
572 return ret;
573 return copy_to_user((void*)arg, &sop, sizeof(sop));
575 case CIOCFSESSION:
576 get_user(ses, (uint32_t*)arg);
577 ret = crypto_finish_session(fcr, ses);
578 return ret;
580 case CIOCCRYPT:
581 ret = copy_from_user(&cop, (void*)arg, sizeof(cop));
582 if (unlikely(ret))
583 return ret;
585 ret = crypto_run(fcr, &cop);
586 if (unlikely(ret))
587 return ret;
588 return copy_to_user((void*)arg, &cop, sizeof(cop));
590 default:
591 return -EINVAL;
595 /* compatibility code for 32bit userlands */
596 #ifdef CONFIG_COMPAT
598 static inline void
599 compat_to_session_op(struct compat_session_op *compat, struct session_op *sop)
601 sop->cipher = compat->cipher;
602 sop->mac = compat->mac;
603 sop->keylen = compat->keylen;
605 sop->key = compat_ptr(compat->key);
606 sop->mackeylen = compat->mackeylen;
607 sop->mackey = compat_ptr(compat->mackey);
608 sop->ses = compat->ses;
611 static inline void
612 session_op_to_compat(struct session_op *sop, struct compat_session_op *compat)
614 compat->cipher = sop->cipher;
615 compat->mac = sop->mac;
616 compat->keylen = sop->keylen;
618 compat->key = ptr_to_compat(sop->key);
619 compat->mackeylen = sop->mackeylen;
620 compat->mackey = ptr_to_compat(sop->mackey);
621 compat->ses = sop->ses;
624 static inline void
625 compat_to_crypt_op(struct compat_crypt_op *compat, struct crypt_op *cop)
627 cop->ses = compat->ses;
628 cop->op = compat->op;
629 cop->flags = compat->flags;
630 cop->len = compat->len;
632 cop->src = compat_ptr(compat->src);
633 cop->dst = compat_ptr(compat->dst);
634 cop->mac = compat_ptr(compat->mac);
635 cop->iv = compat_ptr(compat->iv);
638 static inline void
639 crypt_op_to_compat(struct crypt_op *cop, struct compat_crypt_op *compat)
641 compat->ses = cop->ses;
642 compat->op = cop->op;
643 compat->flags = cop->flags;
644 compat->len = cop->len;
646 compat->src = ptr_to_compat(cop->src);
647 compat->dst = ptr_to_compat(cop->dst);
648 compat->mac = ptr_to_compat(cop->mac);
649 compat->iv = ptr_to_compat(cop->iv);
652 static long
653 cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
655 struct fcrypt *fcr = file->private_data;
656 struct session_op sop;
657 struct compat_session_op compat_sop;
658 struct crypt_op cop;
659 struct compat_crypt_op compat_cop;
660 int ret;
662 if (unlikely(!fcr))
663 BUG();
665 switch (cmd) {
666 case CIOCASYMFEAT:
667 case CRIOGET:
668 case CIOCFSESSION:
669 return cryptodev_ioctl(NULL, file, cmd, arg);
671 case COMPAT_CIOCGSESSION:
672 ret = copy_from_user(&compat_sop,
673 (void *)arg, sizeof(compat_sop));
674 if (unlikely(ret))
675 return ret;
677 compat_to_session_op(&compat_sop, &sop);
679 ret = crypto_create_session(fcr, &sop);
680 if (unlikely(ret))
681 return ret;
683 session_op_to_compat(&sop, &compat_sop);
684 return copy_to_user((void*)arg,
685 &compat_sop, sizeof(compat_sop));
687 case COMPAT_CIOCCRYPT:
688 ret = copy_from_user(&compat_cop,
689 (void*)arg, sizeof(compat_cop));
690 if (unlikely(ret))
691 return ret;
693 compat_to_crypt_op(&compat_cop, &cop);
695 ret = crypto_run(fcr, &cop);
696 if (unlikely(ret))
697 return ret;
699 crypt_op_to_compat(&cop, &compat_cop);
700 return copy_to_user((void*)arg,
701 &compat_cop, sizeof(compat_cop));
703 default:
704 return -EINVAL;
708 #endif /* CONFIG_COMPAT */
710 struct file_operations cryptodev_fops = {
711 .owner = THIS_MODULE,
712 .open = cryptodev_open,
713 .release = cryptodev_release,
714 .ioctl = cryptodev_ioctl,
715 #ifdef CONFIG_COMPAT
716 .compat_ioctl = cryptodev_compat_ioctl,
717 #endif /* CONFIG_COMPAT */
720 struct miscdevice cryptodev = {
721 .minor = MISC_DYNAMIC_MINOR,
722 .name = "crypto",
723 .fops = &cryptodev_fops,
726 static int
727 cryptodev_register(void)
729 int rc;
731 rc = misc_register (&cryptodev);
732 if (unlikely(rc)) {
733 printk(KERN_ERR PFX "registeration of /dev/crypto failed\n");
734 return rc;
737 return 0;
740 static void
741 cryptodev_deregister(void)
743 misc_deregister(&cryptodev);
746 /* ====== Module init/exit ====== */
748 int __init init_cryptodev(void)
750 int rc;
752 rc = cryptodev_register();
753 if (unlikely(rc))
754 return rc;
756 printk(KERN_INFO PFX "driver %s loaded.\n", VERSION);
758 return 0;
761 void __exit exit_cryptodev(void)
763 cryptodev_deregister();
764 printk(KERN_INFO PFX "driver unloaded.\n");
767 module_init(init_cryptodev);
768 module_exit(exit_cryptodev);