xref: /openbmc/linux/crypto/algif_hash.c (revision 9c829203)
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