Commit | Line | Data |
---|---|---|
8ff59090 HX |
1 | /* |
2 | * algif_skcipher: User-space interface for skcipher algorithms | |
3 | * | |
4 | * This file provides the user-space API for symmetric key ciphers. | |
5 | * | |
6 | * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify it | |
9 | * under the terms of the GNU General Public License as published by the Free | |
10 | * Software Foundation; either version 2 of the License, or (at your option) | |
11 | * any later version. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include <crypto/scatterwalk.h> | |
16 | #include <crypto/skcipher.h> | |
17 | #include <crypto/if_alg.h> | |
18 | #include <linux/init.h> | |
19 | #include <linux/list.h> | |
20 | #include <linux/kernel.h> | |
21 | #include <linux/mm.h> | |
22 | #include <linux/module.h> | |
23 | #include <linux/net.h> | |
24 | #include <net/sock.h> | |
25 | ||
26 | struct skcipher_sg_list { | |
27 | struct list_head list; | |
28 | ||
29 | int cur; | |
30 | ||
31 | struct scatterlist sg[0]; | |
32 | }; | |
33 | ||
b8867191 HX |
34 | struct skcipher_tfm { |
35 | struct crypto_ablkcipher *skcipher; | |
36 | bool has_key; | |
37 | }; | |
38 | ||
8ff59090 HX |
39 | struct skcipher_ctx { |
40 | struct list_head tsgl; | |
41 | struct af_alg_sgl rsgl; | |
42 | ||
43 | void *iv; | |
44 | ||
45 | struct af_alg_completion completion; | |
46 | ||
47 | unsigned used; | |
48 | ||
49 | unsigned int len; | |
50 | bool more; | |
51 | bool merge; | |
52 | bool enc; | |
53 | ||
54 | struct ablkcipher_request req; | |
55 | }; | |
56 | ||
591189c2 | 57 | #define MAX_SGL_ENTS ((4096 - sizeof(struct skcipher_sg_list)) / \ |
8ff59090 HX |
58 | sizeof(struct scatterlist) - 1) |
59 | ||
0f6bb83c | 60 | static inline int skcipher_sndbuf(struct sock *sk) |
8ff59090 HX |
61 | { |
62 | struct alg_sock *ask = alg_sk(sk); | |
63 | struct skcipher_ctx *ctx = ask->private; | |
64 | ||
0f6bb83c HX |
65 | return max_t(int, max_t(int, sk->sk_sndbuf & PAGE_MASK, PAGE_SIZE) - |
66 | ctx->used, 0); | |
67 | } | |
68 | ||
69 | static inline bool skcipher_writable(struct sock *sk) | |
70 | { | |
71 | return PAGE_SIZE <= skcipher_sndbuf(sk); | |
8ff59090 HX |
72 | } |
73 | ||
74 | static int skcipher_alloc_sgl(struct sock *sk) | |
75 | { | |
76 | struct alg_sock *ask = alg_sk(sk); | |
77 | struct skcipher_ctx *ctx = ask->private; | |
78 | struct skcipher_sg_list *sgl; | |
79 | struct scatterlist *sg = NULL; | |
80 | ||
81 | sgl = list_entry(ctx->tsgl.prev, struct skcipher_sg_list, list); | |
82 | if (!list_empty(&ctx->tsgl)) | |
83 | sg = sgl->sg; | |
84 | ||
85 | if (!sg || sgl->cur >= MAX_SGL_ENTS) { | |
86 | sgl = sock_kmalloc(sk, sizeof(*sgl) + | |
87 | sizeof(sgl->sg[0]) * (MAX_SGL_ENTS + 1), | |
88 | GFP_KERNEL); | |
89 | if (!sgl) | |
90 | return -ENOMEM; | |
91 | ||
92 | sg_init_table(sgl->sg, MAX_SGL_ENTS + 1); | |
93 | sgl->cur = 0; | |
94 | ||
92e84b6a | 95 | if (sg) { |
8ff59090 | 96 | scatterwalk_sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg); |
92e84b6a SM |
97 | sg_unmark_end(sg + (MAX_SGL_ENTS - 1)); |
98 | } | |
8ff59090 HX |
99 | |
100 | list_add_tail(&sgl->list, &ctx->tsgl); | |
101 | } | |
102 | ||
103 | return 0; | |
104 | } | |
105 | ||
106 | static void skcipher_pull_sgl(struct sock *sk, int used) | |
107 | { | |
108 | struct alg_sock *ask = alg_sk(sk); | |
109 | struct skcipher_ctx *ctx = ask->private; | |
110 | struct skcipher_sg_list *sgl; | |
111 | struct scatterlist *sg; | |
112 | int i; | |
113 | ||
114 | while (!list_empty(&ctx->tsgl)) { | |
115 | sgl = list_first_entry(&ctx->tsgl, struct skcipher_sg_list, | |
116 | list); | |
117 | sg = sgl->sg; | |
118 | ||
119 | for (i = 0; i < sgl->cur; i++) { | |
120 | int plen = min_t(int, used, sg[i].length); | |
121 | ||
122 | if (!sg_page(sg + i)) | |
123 | continue; | |
124 | ||
125 | sg[i].length -= plen; | |
126 | sg[i].offset += plen; | |
127 | ||
128 | used -= plen; | |
129 | ctx->used -= plen; | |
130 | ||
131 | if (sg[i].length) | |
132 | return; | |
133 | ||
134 | put_page(sg_page(sg + i)); | |
135 | sg_assign_page(sg + i, NULL); | |
136 | } | |
137 | ||
138 | list_del(&sgl->list); | |
139 | sock_kfree_s(sk, sgl, | |
140 | sizeof(*sgl) + sizeof(sgl->sg[0]) * | |
141 | (MAX_SGL_ENTS + 1)); | |
142 | } | |
143 | ||
144 | if (!ctx->used) | |
145 | ctx->merge = 0; | |
146 | } | |
147 | ||
148 | static void skcipher_free_sgl(struct sock *sk) | |
149 | { | |
150 | struct alg_sock *ask = alg_sk(sk); | |
151 | struct skcipher_ctx *ctx = ask->private; | |
152 | ||
153 | skcipher_pull_sgl(sk, ctx->used); | |
154 | } | |
155 | ||
156 | static int skcipher_wait_for_wmem(struct sock *sk, unsigned flags) | |
157 | { | |
158 | long timeout; | |
159 | DEFINE_WAIT(wait); | |
160 | int err = -ERESTARTSYS; | |
161 | ||
162 | if (flags & MSG_DONTWAIT) | |
163 | return -EAGAIN; | |
164 | ||
165 | set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); | |
166 | ||
167 | for (;;) { | |
168 | if (signal_pending(current)) | |
169 | break; | |
170 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | |
171 | timeout = MAX_SCHEDULE_TIMEOUT; | |
172 | if (sk_wait_event(sk, &timeout, skcipher_writable(sk))) { | |
173 | err = 0; | |
174 | break; | |
175 | } | |
176 | } | |
177 | finish_wait(sk_sleep(sk), &wait); | |
178 | ||
179 | return err; | |
180 | } | |
181 | ||
182 | static void skcipher_wmem_wakeup(struct sock *sk) | |
183 | { | |
184 | struct socket_wq *wq; | |
185 | ||
186 | if (!skcipher_writable(sk)) | |
187 | return; | |
188 | ||
189 | rcu_read_lock(); | |
190 | wq = rcu_dereference(sk->sk_wq); | |
191 | if (wq_has_sleeper(wq)) | |
192 | wake_up_interruptible_sync_poll(&wq->wait, POLLIN | | |
193 | POLLRDNORM | | |
194 | POLLRDBAND); | |
195 | sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); | |
196 | rcu_read_unlock(); | |
197 | } | |
198 | ||
199 | static int skcipher_wait_for_data(struct sock *sk, unsigned flags) | |
200 | { | |
201 | struct alg_sock *ask = alg_sk(sk); | |
202 | struct skcipher_ctx *ctx = ask->private; | |
203 | long timeout; | |
204 | DEFINE_WAIT(wait); | |
205 | int err = -ERESTARTSYS; | |
206 | ||
207 | if (flags & MSG_DONTWAIT) { | |
208 | return -EAGAIN; | |
209 | } | |
210 | ||
211 | set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); | |
212 | ||
213 | for (;;) { | |
214 | if (signal_pending(current)) | |
215 | break; | |
216 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | |
217 | timeout = MAX_SCHEDULE_TIMEOUT; | |
218 | if (sk_wait_event(sk, &timeout, ctx->used)) { | |
219 | err = 0; | |
220 | break; | |
221 | } | |
222 | } | |
223 | finish_wait(sk_sleep(sk), &wait); | |
224 | ||
225 | clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); | |
226 | ||
227 | return err; | |
228 | } | |
229 | ||
230 | static void skcipher_data_wakeup(struct sock *sk) | |
231 | { | |
232 | struct alg_sock *ask = alg_sk(sk); | |
233 | struct skcipher_ctx *ctx = ask->private; | |
234 | struct socket_wq *wq; | |
235 | ||
236 | if (!ctx->used) | |
237 | return; | |
238 | ||
239 | rcu_read_lock(); | |
240 | wq = rcu_dereference(sk->sk_wq); | |
241 | if (wq_has_sleeper(wq)) | |
242 | wake_up_interruptible_sync_poll(&wq->wait, POLLOUT | | |
243 | POLLRDNORM | | |
244 | POLLRDBAND); | |
245 | sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); | |
246 | rcu_read_unlock(); | |
247 | } | |
248 | ||
249 | static int skcipher_sendmsg(struct kiocb *unused, struct socket *sock, | |
250 | struct msghdr *msg, size_t size) | |
251 | { | |
252 | struct sock *sk = sock->sk; | |
253 | struct alg_sock *ask = alg_sk(sk); | |
254 | struct skcipher_ctx *ctx = ask->private; | |
255 | struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(&ctx->req); | |
256 | unsigned ivsize = crypto_ablkcipher_ivsize(tfm); | |
257 | struct skcipher_sg_list *sgl; | |
258 | struct af_alg_control con = {}; | |
259 | long copied = 0; | |
260 | bool enc = 0; | |
8ff59090 HX |
261 | int err; |
262 | int i; | |
263 | ||
264 | if (msg->msg_controllen) { | |
265 | err = af_alg_cmsg_send(msg, &con); | |
266 | if (err) | |
267 | return err; | |
268 | ||
269 | switch (con.op) { | |
270 | case ALG_OP_ENCRYPT: | |
271 | enc = 1; | |
272 | break; | |
273 | case ALG_OP_DECRYPT: | |
274 | enc = 0; | |
275 | break; | |
276 | default: | |
277 | return -EINVAL; | |
278 | } | |
279 | ||
280 | if (con.iv && con.iv->ivlen != ivsize) | |
281 | return -EINVAL; | |
282 | } | |
283 | ||
284 | err = -EINVAL; | |
285 | ||
286 | lock_sock(sk); | |
287 | if (!ctx->more && ctx->used) | |
288 | goto unlock; | |
289 | ||
290 | if (!ctx->used) { | |
291 | ctx->enc = enc; | |
292 | if (con.iv) | |
293 | memcpy(ctx->iv, con.iv->iv, ivsize); | |
294 | } | |
295 | ||
8ff59090 HX |
296 | while (size) { |
297 | struct scatterlist *sg; | |
298 | unsigned long len = size; | |
299 | int plen; | |
300 | ||
301 | if (ctx->merge) { | |
302 | sgl = list_entry(ctx->tsgl.prev, | |
303 | struct skcipher_sg_list, list); | |
304 | sg = sgl->sg + sgl->cur - 1; | |
305 | len = min_t(unsigned long, len, | |
306 | PAGE_SIZE - sg->offset - sg->length); | |
307 | ||
308 | err = memcpy_fromiovec(page_address(sg_page(sg)) + | |
309 | sg->offset + sg->length, | |
310 | msg->msg_iov, len); | |
311 | if (err) | |
312 | goto unlock; | |
313 | ||
314 | sg->length += len; | |
315 | ctx->merge = (sg->offset + sg->length) & | |
316 | (PAGE_SIZE - 1); | |
317 | ||
318 | ctx->used += len; | |
319 | copied += len; | |
320 | size -= len; | |
8ff59090 HX |
321 | continue; |
322 | } | |
323 | ||
0f6bb83c | 324 | if (!skcipher_writable(sk)) { |
8ff59090 HX |
325 | err = skcipher_wait_for_wmem(sk, msg->msg_flags); |
326 | if (err) | |
327 | goto unlock; | |
8ff59090 HX |
328 | } |
329 | ||
0f6bb83c | 330 | len = min_t(unsigned long, len, skcipher_sndbuf(sk)); |
8ff59090 HX |
331 | |
332 | err = skcipher_alloc_sgl(sk); | |
333 | if (err) | |
334 | goto unlock; | |
335 | ||
336 | sgl = list_entry(ctx->tsgl.prev, struct skcipher_sg_list, list); | |
337 | sg = sgl->sg; | |
338 | do { | |
339 | i = sgl->cur; | |
340 | plen = min_t(int, len, PAGE_SIZE); | |
341 | ||
342 | sg_assign_page(sg + i, alloc_page(GFP_KERNEL)); | |
343 | err = -ENOMEM; | |
344 | if (!sg_page(sg + i)) | |
345 | goto unlock; | |
346 | ||
347 | err = memcpy_fromiovec(page_address(sg_page(sg + i)), | |
348 | msg->msg_iov, plen); | |
349 | if (err) { | |
350 | __free_page(sg_page(sg + i)); | |
351 | sg_assign_page(sg + i, NULL); | |
352 | goto unlock; | |
353 | } | |
354 | ||
355 | sg[i].length = plen; | |
356 | len -= plen; | |
357 | ctx->used += plen; | |
358 | copied += plen; | |
359 | size -= plen; | |
8ff59090 HX |
360 | sgl->cur++; |
361 | } while (len && sgl->cur < MAX_SGL_ENTS); | |
362 | ||
363 | ctx->merge = plen & (PAGE_SIZE - 1); | |
364 | } | |
365 | ||
366 | err = 0; | |
367 | ||
368 | ctx->more = msg->msg_flags & MSG_MORE; | |
369 | if (!ctx->more && !list_empty(&ctx->tsgl)) | |
370 | sgl = list_entry(ctx->tsgl.prev, struct skcipher_sg_list, list); | |
371 | ||
372 | unlock: | |
373 | skcipher_data_wakeup(sk); | |
374 | release_sock(sk); | |
375 | ||
376 | return copied ?: err; | |
377 | } | |
378 | ||
379 | static ssize_t skcipher_sendpage(struct socket *sock, struct page *page, | |
380 | int offset, size_t size, int flags) | |
381 | { | |
382 | struct sock *sk = sock->sk; | |
383 | struct alg_sock *ask = alg_sk(sk); | |
384 | struct skcipher_ctx *ctx = ask->private; | |
385 | struct skcipher_sg_list *sgl; | |
386 | int err = -EINVAL; | |
8ff59090 | 387 | |
86a24344 SL |
388 | if (flags & MSG_SENDPAGE_NOTLAST) |
389 | flags |= MSG_MORE; | |
390 | ||
8ff59090 HX |
391 | lock_sock(sk); |
392 | if (!ctx->more && ctx->used) | |
393 | goto unlock; | |
394 | ||
395 | if (!size) | |
396 | goto done; | |
397 | ||
0f6bb83c | 398 | if (!skcipher_writable(sk)) { |
8ff59090 HX |
399 | err = skcipher_wait_for_wmem(sk, flags); |
400 | if (err) | |
401 | goto unlock; | |
8ff59090 HX |
402 | } |
403 | ||
404 | err = skcipher_alloc_sgl(sk); | |
405 | if (err) | |
406 | goto unlock; | |
407 | ||
408 | ctx->merge = 0; | |
409 | sgl = list_entry(ctx->tsgl.prev, struct skcipher_sg_list, list); | |
410 | ||
411 | get_page(page); | |
412 | sg_set_page(sgl->sg + sgl->cur, page, size, offset); | |
413 | sgl->cur++; | |
414 | ctx->used += size; | |
415 | ||
416 | done: | |
417 | ctx->more = flags & MSG_MORE; | |
418 | if (!ctx->more && !list_empty(&ctx->tsgl)) | |
419 | sgl = list_entry(ctx->tsgl.prev, struct skcipher_sg_list, list); | |
420 | ||
421 | unlock: | |
422 | skcipher_data_wakeup(sk); | |
423 | release_sock(sk); | |
424 | ||
425 | return err ?: size; | |
426 | } | |
427 | ||
428 | static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock, | |
429 | struct msghdr *msg, size_t ignored, int flags) | |
430 | { | |
431 | struct sock *sk = sock->sk; | |
432 | struct alg_sock *ask = alg_sk(sk); | |
433 | struct skcipher_ctx *ctx = ask->private; | |
434 | unsigned bs = crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm( | |
435 | &ctx->req)); | |
436 | struct skcipher_sg_list *sgl; | |
437 | struct scatterlist *sg; | |
438 | unsigned long iovlen; | |
439 | struct iovec *iov; | |
440 | int err = -EAGAIN; | |
441 | int used; | |
442 | long copied = 0; | |
443 | ||
444 | lock_sock(sk); | |
445 | for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0; | |
446 | iovlen--, iov++) { | |
447 | unsigned long seglen = iov->iov_len; | |
448 | char __user *from = iov->iov_base; | |
449 | ||
450 | while (seglen) { | |
8ff59090 HX |
451 | used = ctx->used; |
452 | if (!used) { | |
453 | err = skcipher_wait_for_data(sk, flags); | |
454 | if (err) | |
455 | goto unlock; | |
456 | } | |
457 | ||
458 | used = min_t(unsigned long, used, seglen); | |
459 | ||
bc97e57e HX |
460 | used = af_alg_make_sg(&ctx->rsgl, from, used, 1); |
461 | err = used; | |
462 | if (err < 0) | |
463 | goto unlock; | |
464 | ||
8ff59090 HX |
465 | if (ctx->more || used < ctx->used) |
466 | used -= used % bs; | |
467 | ||
468 | err = -EINVAL; | |
469 | if (!used) | |
bc97e57e | 470 | goto free; |
8ff59090 | 471 | |
ca46046c HX |
472 | sgl = list_first_entry(&ctx->tsgl, |
473 | struct skcipher_sg_list, list); | |
474 | sg = sgl->sg; | |
475 | ||
476 | while (!sg->length) | |
477 | sg++; | |
478 | ||
8ff59090 HX |
479 | ablkcipher_request_set_crypt(&ctx->req, sg, |
480 | ctx->rsgl.sg, used, | |
481 | ctx->iv); | |
482 | ||
483 | err = af_alg_wait_for_completion( | |
484 | ctx->enc ? | |
485 | crypto_ablkcipher_encrypt(&ctx->req) : | |
486 | crypto_ablkcipher_decrypt(&ctx->req), | |
487 | &ctx->completion); | |
488 | ||
bc97e57e | 489 | free: |
8ff59090 HX |
490 | af_alg_free_sg(&ctx->rsgl); |
491 | ||
492 | if (err) | |
493 | goto unlock; | |
494 | ||
495 | copied += used; | |
496 | from += used; | |
497 | seglen -= used; | |
498 | skcipher_pull_sgl(sk, used); | |
499 | } | |
500 | } | |
501 | ||
502 | err = 0; | |
503 | ||
504 | unlock: | |
505 | skcipher_wmem_wakeup(sk); | |
506 | release_sock(sk); | |
507 | ||
508 | return copied ?: err; | |
509 | } | |
510 | ||
511 | ||
512 | static unsigned int skcipher_poll(struct file *file, struct socket *sock, | |
513 | poll_table *wait) | |
514 | { | |
515 | struct sock *sk = sock->sk; | |
516 | struct alg_sock *ask = alg_sk(sk); | |
517 | struct skcipher_ctx *ctx = ask->private; | |
518 | unsigned int mask; | |
519 | ||
520 | sock_poll_wait(file, sk_sleep(sk), wait); | |
521 | mask = 0; | |
522 | ||
523 | if (ctx->used) | |
524 | mask |= POLLIN | POLLRDNORM; | |
525 | ||
526 | if (skcipher_writable(sk)) | |
527 | mask |= POLLOUT | POLLWRNORM | POLLWRBAND; | |
528 | ||
529 | return mask; | |
530 | } | |
531 | ||
532 | static struct proto_ops algif_skcipher_ops = { | |
533 | .family = PF_ALG, | |
534 | ||
535 | .connect = sock_no_connect, | |
536 | .socketpair = sock_no_socketpair, | |
537 | .getname = sock_no_getname, | |
538 | .ioctl = sock_no_ioctl, | |
539 | .listen = sock_no_listen, | |
540 | .shutdown = sock_no_shutdown, | |
541 | .getsockopt = sock_no_getsockopt, | |
542 | .mmap = sock_no_mmap, | |
543 | .bind = sock_no_bind, | |
544 | .accept = sock_no_accept, | |
545 | .setsockopt = sock_no_setsockopt, | |
546 | ||
547 | .release = af_alg_release, | |
548 | .sendmsg = skcipher_sendmsg, | |
549 | .sendpage = skcipher_sendpage, | |
550 | .recvmsg = skcipher_recvmsg, | |
551 | .poll = skcipher_poll, | |
552 | }; | |
553 | ||
4ad8ff67 HX |
554 | static int skcipher_check_key(struct socket *sock) |
555 | { | |
0ac80b6e | 556 | int err = 0; |
4ad8ff67 HX |
557 | struct sock *psk; |
558 | struct alg_sock *pask; | |
559 | struct skcipher_tfm *tfm; | |
560 | struct sock *sk = sock->sk; | |
561 | struct alg_sock *ask = alg_sk(sk); | |
562 | ||
0ac80b6e | 563 | lock_sock(sk); |
4ad8ff67 | 564 | if (ask->refcnt) |
0ac80b6e | 565 | goto unlock_child; |
4ad8ff67 HX |
566 | |
567 | psk = ask->parent; | |
568 | pask = alg_sk(ask->parent); | |
569 | tfm = pask->private; | |
570 | ||
571 | err = -ENOKEY; | |
0ac80b6e | 572 | lock_sock_nested(psk, SINGLE_DEPTH_NESTING); |
4ad8ff67 HX |
573 | if (!tfm->has_key) |
574 | goto unlock; | |
575 | ||
576 | if (!pask->refcnt++) | |
577 | sock_hold(psk); | |
578 | ||
579 | ask->refcnt = 1; | |
580 | sock_put(psk); | |
581 | ||
582 | err = 0; | |
583 | ||
584 | unlock: | |
585 | release_sock(psk); | |
0ac80b6e HX |
586 | unlock_child: |
587 | release_sock(sk); | |
4ad8ff67 HX |
588 | |
589 | return err; | |
590 | } | |
591 | ||
592 | static int skcipher_sendmsg_nokey(struct kiocb *unused, struct socket *sock, | |
593 | struct msghdr *msg, size_t size) | |
594 | { | |
595 | int err; | |
596 | ||
597 | err = skcipher_check_key(sock); | |
598 | if (err) | |
599 | return err; | |
600 | ||
601 | return skcipher_sendmsg(unused, sock, msg, size); | |
602 | } | |
603 | ||
604 | static ssize_t skcipher_sendpage_nokey(struct socket *sock, struct page *page, | |
605 | int offset, size_t size, int flags) | |
606 | { | |
607 | int err; | |
608 | ||
609 | err = skcipher_check_key(sock); | |
610 | if (err) | |
611 | return err; | |
612 | ||
613 | return skcipher_sendpage(sock, page, offset, size, flags); | |
614 | } | |
615 | ||
616 | static int skcipher_recvmsg_nokey(struct kiocb *unused, struct socket *sock, | |
617 | struct msghdr *msg, size_t ignored, int flags) | |
618 | { | |
619 | int err; | |
620 | ||
621 | err = skcipher_check_key(sock); | |
622 | if (err) | |
623 | return err; | |
624 | ||
625 | return skcipher_recvmsg(unused, sock, msg, ignored, flags); | |
626 | } | |
627 | ||
628 | static struct proto_ops algif_skcipher_ops_nokey = { | |
629 | .family = PF_ALG, | |
630 | ||
631 | .connect = sock_no_connect, | |
632 | .socketpair = sock_no_socketpair, | |
633 | .getname = sock_no_getname, | |
634 | .ioctl = sock_no_ioctl, | |
635 | .listen = sock_no_listen, | |
636 | .shutdown = sock_no_shutdown, | |
637 | .getsockopt = sock_no_getsockopt, | |
638 | .mmap = sock_no_mmap, | |
639 | .bind = sock_no_bind, | |
640 | .accept = sock_no_accept, | |
641 | .setsockopt = sock_no_setsockopt, | |
642 | ||
643 | .release = af_alg_release, | |
644 | .sendmsg = skcipher_sendmsg_nokey, | |
645 | .sendpage = skcipher_sendpage_nokey, | |
646 | .recvmsg = skcipher_recvmsg_nokey, | |
647 | .poll = skcipher_poll, | |
648 | }; | |
649 | ||
8ff59090 HX |
650 | static void *skcipher_bind(const char *name, u32 type, u32 mask) |
651 | { | |
b8867191 HX |
652 | struct skcipher_tfm *tfm; |
653 | struct crypto_ablkcipher *skcipher; | |
654 | ||
655 | tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); | |
656 | if (!tfm) | |
657 | return ERR_PTR(-ENOMEM); | |
658 | ||
659 | skcipher = crypto_alloc_ablkcipher(name, type, mask); | |
660 | if (IS_ERR(skcipher)) { | |
661 | kfree(tfm); | |
662 | return ERR_CAST(skcipher); | |
663 | } | |
664 | ||
665 | tfm->skcipher = skcipher; | |
666 | ||
667 | return tfm; | |
8ff59090 HX |
668 | } |
669 | ||
670 | static void skcipher_release(void *private) | |
671 | { | |
b8867191 HX |
672 | struct skcipher_tfm *tfm = private; |
673 | ||
674 | crypto_free_ablkcipher(tfm->skcipher); | |
675 | kfree(tfm); | |
8ff59090 HX |
676 | } |
677 | ||
678 | static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen) | |
679 | { | |
b8867191 HX |
680 | struct skcipher_tfm *tfm = private; |
681 | int err; | |
682 | ||
683 | err = crypto_ablkcipher_setkey(tfm->skcipher, key, keylen); | |
684 | tfm->has_key = !err; | |
685 | ||
686 | return err; | |
8ff59090 HX |
687 | } |
688 | ||
92954970 | 689 | static void skcipher_sock_destruct(struct sock *sk) |
8ff59090 HX |
690 | { |
691 | struct alg_sock *ask = alg_sk(sk); | |
692 | struct skcipher_ctx *ctx = ask->private; | |
693 | struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(&ctx->req); | |
694 | ||
695 | skcipher_free_sgl(sk); | |
696 | sock_kfree_s(sk, ctx->iv, crypto_ablkcipher_ivsize(tfm)); | |
697 | sock_kfree_s(sk, ctx, ctx->len); | |
4ad8ff67 HX |
698 | af_alg_release_parent(sk); |
699 | } | |
700 | ||
92954970 | 701 | static int skcipher_accept_parent_nokey(void *private, struct sock *sk) |
8ff59090 HX |
702 | { |
703 | struct skcipher_ctx *ctx; | |
704 | struct alg_sock *ask = alg_sk(sk); | |
b8867191 HX |
705 | struct skcipher_tfm *tfm = private; |
706 | struct crypto_ablkcipher *skcipher = tfm->skcipher; | |
707 | unsigned int len = sizeof(*ctx) + crypto_ablkcipher_reqsize(skcipher); | |
708 | ||
8ff59090 HX |
709 | ctx = sock_kmalloc(sk, len, GFP_KERNEL); |
710 | if (!ctx) | |
711 | return -ENOMEM; | |
b8867191 | 712 | ctx->iv = sock_kmalloc(sk, crypto_ablkcipher_ivsize(skcipher), |
8ff59090 HX |
713 | GFP_KERNEL); |
714 | if (!ctx->iv) { | |
715 | sock_kfree_s(sk, ctx, len); | |
716 | return -ENOMEM; | |
717 | } | |
718 | ||
b8867191 | 719 | memset(ctx->iv, 0, crypto_ablkcipher_ivsize(skcipher)); |
8ff59090 HX |
720 | |
721 | INIT_LIST_HEAD(&ctx->tsgl); | |
722 | ctx->len = len; | |
723 | ctx->used = 0; | |
724 | ctx->more = 0; | |
725 | ctx->merge = 0; | |
726 | ctx->enc = 0; | |
727 | af_alg_init_completion(&ctx->completion); | |
728 | ||
729 | ask->private = ctx; | |
730 | ||
b8867191 | 731 | ablkcipher_request_set_tfm(&ctx->req, skcipher); |
8ff59090 | 732 | ablkcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG, |
b8867191 | 733 | af_alg_complete, &ctx->completion); |
8ff59090 HX |
734 | |
735 | sk->sk_destruct = skcipher_sock_destruct; | |
736 | ||
737 | return 0; | |
738 | } | |
739 | ||
4ad8ff67 HX |
740 | static int skcipher_accept_parent(void *private, struct sock *sk) |
741 | { | |
742 | struct skcipher_tfm *tfm = private; | |
743 | ||
b5b7b2f8 | 744 | if (!tfm->has_key && crypto_ablkcipher_has_setkey(tfm->skcipher)) |
4ad8ff67 HX |
745 | return -ENOKEY; |
746 | ||
92954970 | 747 | return skcipher_accept_parent_nokey(private, sk); |
4ad8ff67 HX |
748 | } |
749 | ||
8ff59090 HX |
750 | static const struct af_alg_type algif_type_skcipher = { |
751 | .bind = skcipher_bind, | |
752 | .release = skcipher_release, | |
753 | .setkey = skcipher_setkey, | |
754 | .accept = skcipher_accept_parent, | |
4ad8ff67 | 755 | .accept_nokey = skcipher_accept_parent_nokey, |
8ff59090 | 756 | .ops = &algif_skcipher_ops, |
4ad8ff67 | 757 | .ops_nokey = &algif_skcipher_ops_nokey, |
8ff59090 HX |
758 | .name = "skcipher", |
759 | .owner = THIS_MODULE | |
760 | }; | |
761 | ||
762 | static int __init algif_skcipher_init(void) | |
763 | { | |
764 | return af_alg_register_type(&algif_type_skcipher); | |
765 | } | |
766 | ||
767 | static void __exit algif_skcipher_exit(void) | |
768 | { | |
769 | int err = af_alg_unregister_type(&algif_type_skcipher); | |
770 | BUG_ON(err); | |
771 | } | |
772 | ||
773 | module_init(algif_skcipher_init); | |
774 | module_exit(algif_skcipher_exit); | |
775 | MODULE_LICENSE("GPL"); |