12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2fe869cdbSHerbert Xu /*
3fe869cdbSHerbert Xu * algif_hash: User-space interface for hash algorithms
4fe869cdbSHerbert Xu *
5fe869cdbSHerbert Xu * This file provides the user-space API for hash algorithms.
6fe869cdbSHerbert Xu *
7fe869cdbSHerbert Xu * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au>
8fe869cdbSHerbert Xu */
9fe869cdbSHerbert Xu
10fe869cdbSHerbert Xu #include <crypto/hash.h>
11fe869cdbSHerbert Xu #include <crypto/if_alg.h>
12fe869cdbSHerbert Xu #include <linux/init.h>
13fe869cdbSHerbert Xu #include <linux/kernel.h>
14fe869cdbSHerbert Xu #include <linux/mm.h>
15fe869cdbSHerbert Xu #include <linux/module.h>
16fe869cdbSHerbert Xu #include <linux/net.h>
17fe869cdbSHerbert Xu #include <net/sock.h>
18fe869cdbSHerbert Xu
19fe869cdbSHerbert Xu struct hash_ctx {
20fe869cdbSHerbert Xu struct af_alg_sgl sgl;
21fe869cdbSHerbert Xu
22fe869cdbSHerbert Xu u8 *result;
23fe869cdbSHerbert Xu
242c3f8b16SGilad Ben-Yossef struct crypto_wait wait;
25fe869cdbSHerbert Xu
26fe869cdbSHerbert Xu unsigned int len;
27fe869cdbSHerbert Xu bool more;
28fe869cdbSHerbert Xu
29fe869cdbSHerbert Xu struct ahash_request req;
30fe869cdbSHerbert Xu };
31fe869cdbSHerbert Xu
hash_alloc_result(struct sock * sk,struct hash_ctx * ctx)32493b2ed3SHerbert Xu static int hash_alloc_result(struct sock *sk, struct hash_ctx *ctx)
33493b2ed3SHerbert Xu {
34493b2ed3SHerbert Xu unsigned ds;
35493b2ed3SHerbert Xu
36493b2ed3SHerbert Xu if (ctx->result)
37493b2ed3SHerbert Xu return 0;
38493b2ed3SHerbert Xu
39493b2ed3SHerbert Xu ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req));
40493b2ed3SHerbert Xu
41493b2ed3SHerbert Xu ctx->result = sock_kmalloc(sk, ds, GFP_KERNEL);
42493b2ed3SHerbert Xu if (!ctx->result)
43493b2ed3SHerbert Xu return -ENOMEM;
44493b2ed3SHerbert Xu
45493b2ed3SHerbert Xu memset(ctx->result, 0, ds);
46493b2ed3SHerbert Xu
47493b2ed3SHerbert Xu return 0;
48493b2ed3SHerbert Xu }
49493b2ed3SHerbert Xu
hash_free_result(struct sock * sk,struct hash_ctx * ctx)50493b2ed3SHerbert Xu static void hash_free_result(struct sock *sk, struct hash_ctx *ctx)
51493b2ed3SHerbert Xu {
52493b2ed3SHerbert Xu unsigned ds;
53493b2ed3SHerbert Xu
54493b2ed3SHerbert Xu if (!ctx->result)
55493b2ed3SHerbert Xu return;
56493b2ed3SHerbert Xu
57493b2ed3SHerbert Xu ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req));
58493b2ed3SHerbert Xu
59493b2ed3SHerbert Xu sock_kzfree_s(sk, ctx->result, ds);
60493b2ed3SHerbert Xu ctx->result = NULL;
61493b2ed3SHerbert Xu }
62493b2ed3SHerbert Xu
hash_sendmsg(struct socket * sock,struct msghdr * msg,size_t ignored)631b784140SYing Xue static int hash_sendmsg(struct socket *sock, struct msghdr *msg,
641b784140SYing Xue size_t ignored)
65fe869cdbSHerbert Xu {
66fe869cdbSHerbert Xu struct sock *sk = sock->sk;
67fe869cdbSHerbert Xu struct alg_sock *ask = alg_sk(sk);
68fe869cdbSHerbert Xu struct hash_ctx *ctx = ask->private;
69c662b043SDavid Howells ssize_t copied = 0;
70c662b043SDavid Howells size_t len, max_pages, npages;
710b7ec177SDavid Howells bool continuing, need_init = false;
72fe869cdbSHerbert Xu int err;
73fe869cdbSHerbert Xu
74c662b043SDavid Howells max_pages = min_t(size_t, ALG_MAX_PAGES,
75c662b043SDavid Howells DIV_ROUND_UP(sk->sk_sndbuf, PAGE_SIZE));
76fe869cdbSHerbert Xu
77fe869cdbSHerbert Xu lock_sock(sk);
780b7ec177SDavid Howells continuing = ctx->more;
790b7ec177SDavid Howells
80c662b043SDavid Howells if (!continuing) {
81b6d972f6SDavid Howells /* Discard a previous request that wasn't marked MSG_MORE. */
82493b2ed3SHerbert Xu hash_free_result(sk, ctx);
83b6d972f6SDavid Howells if (!msg_data_left(msg))
84b6d972f6SDavid Howells goto done; /* Zero-length; don't start new req */
85c662b043SDavid Howells need_init = true;
86b6d972f6SDavid Howells } else if (!msg_data_left(msg)) {
87b6d972f6SDavid Howells /*
88b6d972f6SDavid Howells * No data - finalise the prev req if MSG_MORE so any error
89b6d972f6SDavid Howells * comes out here.
90b6d972f6SDavid Howells */
91b6d972f6SDavid Howells if (!(msg->msg_flags & MSG_MORE)) {
92b6d972f6SDavid Howells err = hash_alloc_result(sk, ctx);
93b6d972f6SDavid Howells if (err)
94*9c829203SHerbert Xu goto unlock_free_result;
95b6d972f6SDavid Howells ahash_request_set_crypt(&ctx->req, NULL,
96b6d972f6SDavid Howells ctx->result, 0);
97b6d972f6SDavid Howells err = crypto_wait_req(crypto_ahash_final(&ctx->req),
98b6d972f6SDavid Howells &ctx->wait);
99b6d972f6SDavid Howells if (err)
100*9c829203SHerbert Xu goto unlock_free_result;
101fe869cdbSHerbert Xu }
102b6d972f6SDavid Howells goto done_more;
103b6d972f6SDavid Howells }
104fe869cdbSHerbert Xu
10501e97e65SAl Viro while (msg_data_left(msg)) {
106c1abe6f5SDavid Howells ctx->sgl.sgt.sgl = ctx->sgl.sgl;
107c1abe6f5SDavid Howells ctx->sgl.sgt.nents = 0;
108c1abe6f5SDavid Howells ctx->sgl.sgt.orig_nents = 0;
109c1abe6f5SDavid Howells
110c662b043SDavid Howells err = -EIO;
111c662b043SDavid Howells npages = iov_iter_npages(&msg->msg_iter, max_pages);
112c662b043SDavid Howells if (npages == 0)
113c662b043SDavid Howells goto unlock_free;
114c662b043SDavid Howells
115c662b043SDavid Howells sg_init_table(ctx->sgl.sgl, npages);
116fe869cdbSHerbert Xu
117c1abe6f5SDavid Howells ctx->sgl.need_unpin = iov_iter_extract_will_pin(&msg->msg_iter);
118c1abe6f5SDavid Howells
119c662b043SDavid Howells err = extract_iter_to_sg(&msg->msg_iter, LONG_MAX,
120c662b043SDavid Howells &ctx->sgl.sgt, npages, 0);
121c662b043SDavid Howells if (err < 0)
122c662b043SDavid Howells goto unlock_free;
123c662b043SDavid Howells len = err;
124c662b043SDavid Howells sg_mark_end(ctx->sgl.sgt.sgl + ctx->sgl.sgt.nents - 1);
125fe869cdbSHerbert Xu
126c662b043SDavid Howells if (!msg_data_left(msg)) {
127493b2ed3SHerbert Xu err = hash_alloc_result(sk, ctx);
128493b2ed3SHerbert Xu if (err)
129c662b043SDavid Howells goto unlock_free;
130fe869cdbSHerbert Xu }
131fe869cdbSHerbert Xu
132c662b043SDavid Howells ahash_request_set_crypt(&ctx->req, ctx->sgl.sgt.sgl,
133c662b043SDavid Howells ctx->result, len);
134c662b043SDavid Howells
135c662b043SDavid Howells if (!msg_data_left(msg) && !continuing &&
136c662b043SDavid Howells !(msg->msg_flags & MSG_MORE)) {
137c662b043SDavid Howells err = crypto_ahash_digest(&ctx->req);
138c662b043SDavid Howells } else {
139c662b043SDavid Howells if (need_init) {
140c662b043SDavid Howells err = crypto_wait_req(
141c662b043SDavid Howells crypto_ahash_init(&ctx->req),
142c662b043SDavid Howells &ctx->wait);
143c662b043SDavid Howells if (err)
144c662b043SDavid Howells goto unlock_free;
145c662b043SDavid Howells need_init = false;
146c662b043SDavid Howells }
147c662b043SDavid Howells
148c662b043SDavid Howells if (msg_data_left(msg) || (msg->msg_flags & MSG_MORE))
149c662b043SDavid Howells err = crypto_ahash_update(&ctx->req);
150c662b043SDavid Howells else
151c662b043SDavid Howells err = crypto_ahash_finup(&ctx->req);
152c662b043SDavid Howells continuing = true;
153c662b043SDavid Howells }
154c662b043SDavid Howells
155c662b043SDavid Howells err = crypto_wait_req(err, &ctx->wait);
156c662b043SDavid Howells if (err)
157c662b043SDavid Howells goto unlock_free;
158c662b043SDavid Howells
159c662b043SDavid Howells copied += len;
160c662b043SDavid Howells af_alg_free_sg(&ctx->sgl);
161c662b043SDavid Howells }
162c662b043SDavid Howells
163b6d972f6SDavid Howells done_more:
164c662b043SDavid Howells ctx->more = msg->msg_flags & MSG_MORE;
165b6d972f6SDavid Howells done:
166c662b043SDavid Howells err = 0;
167fe869cdbSHerbert Xu unlock:
168fe869cdbSHerbert Xu release_sock(sk);
169c662b043SDavid Howells return copied ?: err;
170fe869cdbSHerbert Xu
171c662b043SDavid Howells unlock_free:
172c662b043SDavid Howells af_alg_free_sg(&ctx->sgl);
173*9c829203SHerbert Xu unlock_free_result:
174b6d972f6SDavid Howells hash_free_result(sk, ctx);
175b6d972f6SDavid Howells ctx->more = false;
176c662b043SDavid Howells goto unlock;
177fe869cdbSHerbert Xu }
178fe869cdbSHerbert Xu
hash_recvmsg(struct socket * sock,struct msghdr * msg,size_t len,int flags)1791b784140SYing Xue static int hash_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
1801b784140SYing Xue int flags)
181fe869cdbSHerbert Xu {
182fe869cdbSHerbert Xu struct sock *sk = sock->sk;
183fe869cdbSHerbert Xu struct alg_sock *ask = alg_sk(sk);
184fe869cdbSHerbert Xu struct hash_ctx *ctx = ask->private;
185fe869cdbSHerbert Xu unsigned ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req));
186493b2ed3SHerbert Xu bool result;
187fe869cdbSHerbert Xu int err;
188fe869cdbSHerbert Xu
189fe869cdbSHerbert Xu if (len > ds)
190fe869cdbSHerbert Xu len = ds;
191fe869cdbSHerbert Xu else if (len < ds)
192fe869cdbSHerbert Xu msg->msg_flags |= MSG_TRUNC;
193fe869cdbSHerbert Xu
194fe869cdbSHerbert Xu lock_sock(sk);
195493b2ed3SHerbert Xu result = ctx->result;
196493b2ed3SHerbert Xu err = hash_alloc_result(sk, ctx);
197493b2ed3SHerbert Xu if (err)
198493b2ed3SHerbert Xu goto unlock;
199493b2ed3SHerbert Xu
200493b2ed3SHerbert Xu ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0);
201493b2ed3SHerbert Xu
2028acf7a10SHerbert Xu if (!result && !ctx->more) {
2032c3f8b16SGilad Ben-Yossef err = crypto_wait_req(crypto_ahash_init(&ctx->req),
2042c3f8b16SGilad Ben-Yossef &ctx->wait);
205a8348bcaSHerbert Xu if (err)
206a8348bcaSHerbert Xu goto unlock;
207a8348bcaSHerbert Xu }
208a8348bcaSHerbert Xu
209a8348bcaSHerbert Xu if (!result || ctx->more) {
210fcb90d51SLothar Rubusch ctx->more = false;
2112c3f8b16SGilad Ben-Yossef err = crypto_wait_req(crypto_ahash_final(&ctx->req),
2122c3f8b16SGilad Ben-Yossef &ctx->wait);
213fe869cdbSHerbert Xu if (err)
214fe869cdbSHerbert Xu goto unlock;
215fe869cdbSHerbert Xu }
216fe869cdbSHerbert Xu
2177eab8d9eSAl Viro err = memcpy_to_msg(msg, ctx->result, len);
218fe869cdbSHerbert Xu
219fe869cdbSHerbert Xu unlock:
220a8348bcaSHerbert Xu hash_free_result(sk, ctx);
221fe869cdbSHerbert Xu release_sock(sk);
222fe869cdbSHerbert Xu
223fe869cdbSHerbert Xu return err ?: len;
224fe869cdbSHerbert Xu }
225fe869cdbSHerbert Xu
hash_accept(struct socket * sock,struct socket * newsock,int flags,bool kern)226cdfbabfbSDavid Howells static int hash_accept(struct socket *sock, struct socket *newsock, int flags,
227cdfbabfbSDavid Howells bool kern)
228fe869cdbSHerbert Xu {
229fe869cdbSHerbert Xu struct sock *sk = sock->sk;
230fe869cdbSHerbert Xu struct alg_sock *ask = alg_sk(sk);
231fe869cdbSHerbert Xu struct hash_ctx *ctx = ask->private;
232fe869cdbSHerbert Xu struct ahash_request *req = &ctx->req;
233acc03d89SHerbert Xu struct crypto_ahash *tfm;
234fe869cdbSHerbert Xu struct sock *sk2;
235fe869cdbSHerbert Xu struct alg_sock *ask2;
236fe869cdbSHerbert Xu struct hash_ctx *ctx2;
237acc03d89SHerbert Xu char *state;
2384afa5f96SHerbert Xu bool more;
239fe869cdbSHerbert Xu int err;
240fe869cdbSHerbert Xu
241acc03d89SHerbert Xu tfm = crypto_ahash_reqtfm(req);
242acc03d89SHerbert Xu state = kmalloc(crypto_ahash_statesize(tfm), GFP_KERNEL);
243acc03d89SHerbert Xu err = -ENOMEM;
244acc03d89SHerbert Xu if (!state)
245acc03d89SHerbert Xu goto out;
246acc03d89SHerbert Xu
2474afa5f96SHerbert Xu lock_sock(sk);
2484afa5f96SHerbert Xu more = ctx->more;
2494afa5f96SHerbert Xu err = more ? crypto_ahash_export(req, state) : 0;
2504afa5f96SHerbert Xu release_sock(sk);
2514afa5f96SHerbert Xu
252fe869cdbSHerbert Xu if (err)
253acc03d89SHerbert Xu goto out_free_state;
254fe869cdbSHerbert Xu
255cdfbabfbSDavid Howells err = af_alg_accept(ask->parent, newsock, kern);
256fe869cdbSHerbert Xu if (err)
257acc03d89SHerbert Xu goto out_free_state;
258fe869cdbSHerbert Xu
259fe869cdbSHerbert Xu sk2 = newsock->sk;
260fe869cdbSHerbert Xu ask2 = alg_sk(sk2);
261fe869cdbSHerbert Xu ctx2 = ask2->private;
2624afa5f96SHerbert Xu ctx2->more = more;
2634afa5f96SHerbert Xu
2644afa5f96SHerbert Xu if (!more)
265acc03d89SHerbert Xu goto out_free_state;
266fe869cdbSHerbert Xu
267fe869cdbSHerbert Xu err = crypto_ahash_import(&ctx2->req, state);
268fe869cdbSHerbert Xu if (err) {
269fe869cdbSHerbert Xu sock_orphan(sk2);
270fe869cdbSHerbert Xu sock_put(sk2);
271fe869cdbSHerbert Xu }
272fe869cdbSHerbert Xu
273acc03d89SHerbert Xu out_free_state:
274acc03d89SHerbert Xu kfree_sensitive(state);
275acc03d89SHerbert Xu
276acc03d89SHerbert Xu out:
277fe869cdbSHerbert Xu return err;
278fe869cdbSHerbert Xu }
279fe869cdbSHerbert Xu
280fe869cdbSHerbert Xu static struct proto_ops algif_hash_ops = {
281fe869cdbSHerbert Xu .family = PF_ALG,
282fe869cdbSHerbert Xu
283fe869cdbSHerbert Xu .connect = sock_no_connect,
284fe869cdbSHerbert Xu .socketpair = sock_no_socketpair,
285fe869cdbSHerbert Xu .getname = sock_no_getname,
286fe869cdbSHerbert Xu .ioctl = sock_no_ioctl,
287fe869cdbSHerbert Xu .listen = sock_no_listen,
288fe869cdbSHerbert Xu .shutdown = sock_no_shutdown,
289fe869cdbSHerbert Xu .mmap = sock_no_mmap,
290fe869cdbSHerbert Xu .bind = sock_no_bind,
291fe869cdbSHerbert Xu
292fe869cdbSHerbert Xu .release = af_alg_release,
293fe869cdbSHerbert Xu .sendmsg = hash_sendmsg,
294fe869cdbSHerbert Xu .recvmsg = hash_recvmsg,
295fe869cdbSHerbert Xu .accept = hash_accept,
296fe869cdbSHerbert Xu };
297fe869cdbSHerbert Xu
hash_check_key(struct socket * sock)2986de62f15SHerbert Xu static int hash_check_key(struct socket *sock)
2996de62f15SHerbert Xu {
300ad46d7e3SHerbert Xu int err = 0;
3016de62f15SHerbert Xu struct sock *psk;
3026de62f15SHerbert Xu struct alg_sock *pask;
3039fa68f62SEric Biggers struct crypto_ahash *tfm;
3046de62f15SHerbert Xu struct sock *sk = sock->sk;
3056de62f15SHerbert Xu struct alg_sock *ask = alg_sk(sk);
3066de62f15SHerbert Xu
307ad46d7e3SHerbert Xu lock_sock(sk);
30834c86f4cSHerbert Xu if (!atomic_read(&ask->nokey_refcnt))
309ad46d7e3SHerbert Xu goto unlock_child;
3106de62f15SHerbert Xu
3116de62f15SHerbert Xu psk = ask->parent;
3126de62f15SHerbert Xu pask = alg_sk(ask->parent);
3136de62f15SHerbert Xu tfm = pask->private;
3146de62f15SHerbert Xu
3156de62f15SHerbert Xu err = -ENOKEY;
316ad46d7e3SHerbert Xu lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
3179fa68f62SEric Biggers if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
3186de62f15SHerbert Xu goto unlock;
3196de62f15SHerbert Xu
32034c86f4cSHerbert Xu atomic_dec(&pask->nokey_refcnt);
32134c86f4cSHerbert Xu atomic_set(&ask->nokey_refcnt, 0);
3226de62f15SHerbert Xu
3236de62f15SHerbert Xu err = 0;
3246de62f15SHerbert Xu
3256de62f15SHerbert Xu unlock:
3266de62f15SHerbert Xu release_sock(psk);
327ad46d7e3SHerbert Xu unlock_child:
328ad46d7e3SHerbert Xu release_sock(sk);
3296de62f15SHerbert Xu
3306de62f15SHerbert Xu return err;
3316de62f15SHerbert Xu }
3326de62f15SHerbert Xu
hash_sendmsg_nokey(struct socket * sock,struct msghdr * msg,size_t size)3336de62f15SHerbert Xu static int hash_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
3346de62f15SHerbert Xu size_t size)
3356de62f15SHerbert Xu {
3366de62f15SHerbert Xu int err;
3376de62f15SHerbert Xu
3386de62f15SHerbert Xu err = hash_check_key(sock);
3396de62f15SHerbert Xu if (err)
3406de62f15SHerbert Xu return err;
3416de62f15SHerbert Xu
3426de62f15SHerbert Xu return hash_sendmsg(sock, msg, size);
3436de62f15SHerbert Xu }
3446de62f15SHerbert Xu
hash_recvmsg_nokey(struct socket * sock,struct msghdr * msg,size_t ignored,int flags)3456de62f15SHerbert Xu static int hash_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
3466de62f15SHerbert Xu size_t ignored, int flags)
3476de62f15SHerbert Xu {
3486de62f15SHerbert Xu int err;
3496de62f15SHerbert Xu
3506de62f15SHerbert Xu err = hash_check_key(sock);
3516de62f15SHerbert Xu if (err)
3526de62f15SHerbert Xu return err;
3536de62f15SHerbert Xu
3546de62f15SHerbert Xu return hash_recvmsg(sock, msg, ignored, flags);
3556de62f15SHerbert Xu }
3566de62f15SHerbert Xu
hash_accept_nokey(struct socket * sock,struct socket * newsock,int flags,bool kern)3576de62f15SHerbert Xu static int hash_accept_nokey(struct socket *sock, struct socket *newsock,
358cdfbabfbSDavid Howells int flags, bool kern)
3596de62f15SHerbert Xu {
3606de62f15SHerbert Xu int err;
3616de62f15SHerbert Xu
3626de62f15SHerbert Xu err = hash_check_key(sock);
3636de62f15SHerbert Xu if (err)
3646de62f15SHerbert Xu return err;
3656de62f15SHerbert Xu
366cdfbabfbSDavid Howells return hash_accept(sock, newsock, flags, kern);
3676de62f15SHerbert Xu }
3686de62f15SHerbert Xu
3696de62f15SHerbert Xu static struct proto_ops algif_hash_ops_nokey = {
3706de62f15SHerbert Xu .family = PF_ALG,
3716de62f15SHerbert Xu
3726de62f15SHerbert Xu .connect = sock_no_connect,
3736de62f15SHerbert Xu .socketpair = sock_no_socketpair,
3746de62f15SHerbert Xu .getname = sock_no_getname,
3756de62f15SHerbert Xu .ioctl = sock_no_ioctl,
3766de62f15SHerbert Xu .listen = sock_no_listen,
3776de62f15SHerbert Xu .shutdown = sock_no_shutdown,
3786de62f15SHerbert Xu .mmap = sock_no_mmap,
3796de62f15SHerbert Xu .bind = sock_no_bind,
3806de62f15SHerbert Xu
3816de62f15SHerbert Xu .release = af_alg_release,
3826de62f15SHerbert Xu .sendmsg = hash_sendmsg_nokey,
3836de62f15SHerbert Xu .recvmsg = hash_recvmsg_nokey,
3846de62f15SHerbert Xu .accept = hash_accept_nokey,
3856de62f15SHerbert Xu };
3866de62f15SHerbert Xu
hash_bind(const char * name,u32 type,u32 mask)387fe869cdbSHerbert Xu static void *hash_bind(const char *name, u32 type, u32 mask)
388fe869cdbSHerbert Xu {
3899fa68f62SEric Biggers return crypto_alloc_ahash(name, type, mask);
390fe869cdbSHerbert Xu }
391fe869cdbSHerbert Xu
hash_release(void * private)392fe869cdbSHerbert Xu static void hash_release(void *private)
393fe869cdbSHerbert Xu {
3949fa68f62SEric Biggers crypto_free_ahash(private);
395fe869cdbSHerbert Xu }
396fe869cdbSHerbert Xu
hash_setkey(void * private,const u8 * key,unsigned int keylen)397fe869cdbSHerbert Xu static int hash_setkey(void *private, const u8 *key, unsigned int keylen)
398fe869cdbSHerbert Xu {
3999fa68f62SEric Biggers return crypto_ahash_setkey(private, key, keylen);
400fe869cdbSHerbert Xu }
401fe869cdbSHerbert Xu
hash_sock_destruct(struct sock * sk)402f1d84af1SHerbert Xu static void hash_sock_destruct(struct sock *sk)
403fe869cdbSHerbert Xu {
404fe869cdbSHerbert Xu struct alg_sock *ask = alg_sk(sk);
405fe869cdbSHerbert Xu struct hash_ctx *ctx = ask->private;
406fe869cdbSHerbert Xu
407493b2ed3SHerbert Xu hash_free_result(sk, ctx);
408fe869cdbSHerbert Xu sock_kfree_s(sk, ctx, ctx->len);
409fe869cdbSHerbert Xu af_alg_release_parent(sk);
410fe869cdbSHerbert Xu }
411fe869cdbSHerbert Xu
hash_accept_parent_nokey(void * private,struct sock * sk)412f1d84af1SHerbert Xu static int hash_accept_parent_nokey(void *private, struct sock *sk)
413fe869cdbSHerbert Xu {
4149fa68f62SEric Biggers struct crypto_ahash *tfm = private;
415fe869cdbSHerbert Xu struct alg_sock *ask = alg_sk(sk);
4169fa68f62SEric Biggers struct hash_ctx *ctx;
4179fa68f62SEric Biggers unsigned int len = sizeof(*ctx) + crypto_ahash_reqsize(tfm);
418fe869cdbSHerbert Xu
419fe869cdbSHerbert Xu ctx = sock_kmalloc(sk, len, GFP_KERNEL);
420fe869cdbSHerbert Xu if (!ctx)
421fe869cdbSHerbert Xu return -ENOMEM;
422fe869cdbSHerbert Xu
423493b2ed3SHerbert Xu ctx->result = NULL;
424fe869cdbSHerbert Xu ctx->len = len;
425fcb90d51SLothar Rubusch ctx->more = false;
4262c3f8b16SGilad Ben-Yossef crypto_init_wait(&ctx->wait);
427fe869cdbSHerbert Xu
428fe869cdbSHerbert Xu ask->private = ctx;
429fe869cdbSHerbert Xu
4309fa68f62SEric Biggers ahash_request_set_tfm(&ctx->req, tfm);
431fe869cdbSHerbert Xu ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
4322c3f8b16SGilad Ben-Yossef crypto_req_done, &ctx->wait);
433fe869cdbSHerbert Xu
434fe869cdbSHerbert Xu sk->sk_destruct = hash_sock_destruct;
435fe869cdbSHerbert Xu
436fe869cdbSHerbert Xu return 0;
437fe869cdbSHerbert Xu }
438fe869cdbSHerbert Xu
hash_accept_parent(void * private,struct sock * sk)4396de62f15SHerbert Xu static int hash_accept_parent(void *private, struct sock *sk)
4406de62f15SHerbert Xu {
4419fa68f62SEric Biggers struct crypto_ahash *tfm = private;
4426de62f15SHerbert Xu
4439fa68f62SEric Biggers if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
4446de62f15SHerbert Xu return -ENOKEY;
4456de62f15SHerbert Xu
446f1d84af1SHerbert Xu return hash_accept_parent_nokey(private, sk);
4476de62f15SHerbert Xu }
4486de62f15SHerbert Xu
449fe869cdbSHerbert Xu static const struct af_alg_type algif_type_hash = {
450fe869cdbSHerbert Xu .bind = hash_bind,
451fe869cdbSHerbert Xu .release = hash_release,
452fe869cdbSHerbert Xu .setkey = hash_setkey,
453fe869cdbSHerbert Xu .accept = hash_accept_parent,
4546de62f15SHerbert Xu .accept_nokey = hash_accept_parent_nokey,
455fe869cdbSHerbert Xu .ops = &algif_hash_ops,
4566de62f15SHerbert Xu .ops_nokey = &algif_hash_ops_nokey,
457fe869cdbSHerbert Xu .name = "hash",
458fe869cdbSHerbert Xu .owner = THIS_MODULE
459fe869cdbSHerbert Xu };
460fe869cdbSHerbert Xu
algif_hash_init(void)461fe869cdbSHerbert Xu static int __init algif_hash_init(void)
462fe869cdbSHerbert Xu {
463fe869cdbSHerbert Xu return af_alg_register_type(&algif_type_hash);
464fe869cdbSHerbert Xu }
465fe869cdbSHerbert Xu
algif_hash_exit(void)466fe869cdbSHerbert Xu static void __exit algif_hash_exit(void)
467fe869cdbSHerbert Xu {
468fe869cdbSHerbert Xu int err = af_alg_unregister_type(&algif_type_hash);
469fe869cdbSHerbert Xu BUG_ON(err);
470fe869cdbSHerbert Xu }
471fe869cdbSHerbert Xu
472fe869cdbSHerbert Xu module_init(algif_hash_init);
473fe869cdbSHerbert Xu module_exit(algif_hash_exit);
474fe869cdbSHerbert Xu MODULE_LICENSE("GPL");
475