18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * algif_aead: User-space interface for AEAD algorithms
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2014, Stephan Mueller <smueller@chronox.de>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * This file provides the user-space API for AEAD ciphers.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * The following concept of the memory management is used:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The kernel maintains two SGLs, the TX SGL and the RX SGL. The TX SGL is
128c2ecf20Sopenharmony_ci * filled by user space with the data submitted via sendpage/sendmsg. Filling
138c2ecf20Sopenharmony_ci * up the TX SGL does not cause a crypto operation -- the data will only be
148c2ecf20Sopenharmony_ci * tracked by the kernel. Upon receipt of one recvmsg call, the caller must
158c2ecf20Sopenharmony_ci * provide a buffer which is tracked with the RX SGL.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * During the processing of the recvmsg operation, the cipher request is
188c2ecf20Sopenharmony_ci * allocated and prepared. As part of the recvmsg operation, the processed
198c2ecf20Sopenharmony_ci * TX buffers are extracted from the TX SGL into a separate SGL.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * After the completion of the crypto operation, the RX SGL and the cipher
228c2ecf20Sopenharmony_ci * request is released. The extracted TX SGL parts are released together with
238c2ecf20Sopenharmony_ci * the RX SGL release.
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h>
278c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h>
288c2ecf20Sopenharmony_ci#include <crypto/if_alg.h>
298c2ecf20Sopenharmony_ci#include <crypto/skcipher.h>
308c2ecf20Sopenharmony_ci#include <crypto/null.h>
318c2ecf20Sopenharmony_ci#include <linux/init.h>
328c2ecf20Sopenharmony_ci#include <linux/list.h>
338c2ecf20Sopenharmony_ci#include <linux/kernel.h>
348c2ecf20Sopenharmony_ci#include <linux/mm.h>
358c2ecf20Sopenharmony_ci#include <linux/module.h>
368c2ecf20Sopenharmony_ci#include <linux/net.h>
378c2ecf20Sopenharmony_ci#include <net/sock.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistruct aead_tfm {
408c2ecf20Sopenharmony_ci	struct crypto_aead *aead;
418c2ecf20Sopenharmony_ci	struct crypto_sync_skcipher *null_tfm;
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic inline bool aead_sufficient_data(struct sock *sk)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	struct alg_sock *ask = alg_sk(sk);
478c2ecf20Sopenharmony_ci	struct sock *psk = ask->parent;
488c2ecf20Sopenharmony_ci	struct alg_sock *pask = alg_sk(psk);
498c2ecf20Sopenharmony_ci	struct af_alg_ctx *ctx = ask->private;
508c2ecf20Sopenharmony_ci	struct aead_tfm *aeadc = pask->private;
518c2ecf20Sopenharmony_ci	struct crypto_aead *tfm = aeadc->aead;
528c2ecf20Sopenharmony_ci	unsigned int as = crypto_aead_authsize(tfm);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	/*
558c2ecf20Sopenharmony_ci	 * The minimum amount of memory needed for an AEAD cipher is
568c2ecf20Sopenharmony_ci	 * the AAD and in case of decryption the tag.
578c2ecf20Sopenharmony_ci	 */
588c2ecf20Sopenharmony_ci	return ctx->used >= ctx->aead_assoclen + (ctx->enc ? 0 : as);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic int aead_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
648c2ecf20Sopenharmony_ci	struct alg_sock *ask = alg_sk(sk);
658c2ecf20Sopenharmony_ci	struct sock *psk = ask->parent;
668c2ecf20Sopenharmony_ci	struct alg_sock *pask = alg_sk(psk);
678c2ecf20Sopenharmony_ci	struct aead_tfm *aeadc = pask->private;
688c2ecf20Sopenharmony_ci	struct crypto_aead *tfm = aeadc->aead;
698c2ecf20Sopenharmony_ci	unsigned int ivsize = crypto_aead_ivsize(tfm);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	return af_alg_sendmsg(sock, msg, size, ivsize);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic int crypto_aead_copy_sgl(struct crypto_sync_skcipher *null_tfm,
758c2ecf20Sopenharmony_ci				struct scatterlist *src,
768c2ecf20Sopenharmony_ci				struct scatterlist *dst, unsigned int len)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	skcipher_request_set_sync_tfm(skreq, null_tfm);
818c2ecf20Sopenharmony_ci	skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_SLEEP,
828c2ecf20Sopenharmony_ci				      NULL, NULL);
838c2ecf20Sopenharmony_ci	skcipher_request_set_crypt(skreq, src, dst, len, NULL);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	return crypto_skcipher_encrypt(skreq);
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
898c2ecf20Sopenharmony_ci			 size_t ignored, int flags)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
928c2ecf20Sopenharmony_ci	struct alg_sock *ask = alg_sk(sk);
938c2ecf20Sopenharmony_ci	struct sock *psk = ask->parent;
948c2ecf20Sopenharmony_ci	struct alg_sock *pask = alg_sk(psk);
958c2ecf20Sopenharmony_ci	struct af_alg_ctx *ctx = ask->private;
968c2ecf20Sopenharmony_ci	struct aead_tfm *aeadc = pask->private;
978c2ecf20Sopenharmony_ci	struct crypto_aead *tfm = aeadc->aead;
988c2ecf20Sopenharmony_ci	struct crypto_sync_skcipher *null_tfm = aeadc->null_tfm;
998c2ecf20Sopenharmony_ci	unsigned int i, as = crypto_aead_authsize(tfm);
1008c2ecf20Sopenharmony_ci	struct af_alg_async_req *areq;
1018c2ecf20Sopenharmony_ci	struct af_alg_tsgl *tsgl, *tmp;
1028c2ecf20Sopenharmony_ci	struct scatterlist *rsgl_src, *tsgl_src = NULL;
1038c2ecf20Sopenharmony_ci	int err = 0;
1048c2ecf20Sopenharmony_ci	size_t used = 0;		/* [in]  TX bufs to be en/decrypted */
1058c2ecf20Sopenharmony_ci	size_t outlen = 0;		/* [out] RX bufs produced by kernel */
1068c2ecf20Sopenharmony_ci	size_t usedpages = 0;		/* [in]  RX bufs to be used from user */
1078c2ecf20Sopenharmony_ci	size_t processed = 0;		/* [in]  TX bufs to be consumed */
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (!ctx->init || ctx->more) {
1108c2ecf20Sopenharmony_ci		err = af_alg_wait_for_data(sk, flags, 0);
1118c2ecf20Sopenharmony_ci		if (err)
1128c2ecf20Sopenharmony_ci			return err;
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	/*
1168c2ecf20Sopenharmony_ci	 * Data length provided by caller via sendmsg/sendpage that has not
1178c2ecf20Sopenharmony_ci	 * yet been processed.
1188c2ecf20Sopenharmony_ci	 */
1198c2ecf20Sopenharmony_ci	used = ctx->used;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/*
1228c2ecf20Sopenharmony_ci	 * Make sure sufficient data is present -- note, the same check is
1238c2ecf20Sopenharmony_ci	 * also present in sendmsg/sendpage. The checks in sendpage/sendmsg
1248c2ecf20Sopenharmony_ci	 * shall provide an information to the data sender that something is
1258c2ecf20Sopenharmony_ci	 * wrong, but they are irrelevant to maintain the kernel integrity.
1268c2ecf20Sopenharmony_ci	 * We need this check here too in case user space decides to not honor
1278c2ecf20Sopenharmony_ci	 * the error message in sendmsg/sendpage and still call recvmsg. This
1288c2ecf20Sopenharmony_ci	 * check here protects the kernel integrity.
1298c2ecf20Sopenharmony_ci	 */
1308c2ecf20Sopenharmony_ci	if (!aead_sufficient_data(sk))
1318c2ecf20Sopenharmony_ci		return -EINVAL;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	/*
1348c2ecf20Sopenharmony_ci	 * Calculate the minimum output buffer size holding the result of the
1358c2ecf20Sopenharmony_ci	 * cipher operation. When encrypting data, the receiving buffer is
1368c2ecf20Sopenharmony_ci	 * larger by the tag length compared to the input buffer as the
1378c2ecf20Sopenharmony_ci	 * encryption operation generates the tag. For decryption, the input
1388c2ecf20Sopenharmony_ci	 * buffer provides the tag which is consumed resulting in only the
1398c2ecf20Sopenharmony_ci	 * plaintext without a buffer for the tag returned to the caller.
1408c2ecf20Sopenharmony_ci	 */
1418c2ecf20Sopenharmony_ci	if (ctx->enc)
1428c2ecf20Sopenharmony_ci		outlen = used + as;
1438c2ecf20Sopenharmony_ci	else
1448c2ecf20Sopenharmony_ci		outlen = used - as;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/*
1478c2ecf20Sopenharmony_ci	 * The cipher operation input data is reduced by the associated data
1488c2ecf20Sopenharmony_ci	 * length as this data is processed separately later on.
1498c2ecf20Sopenharmony_ci	 */
1508c2ecf20Sopenharmony_ci	used -= ctx->aead_assoclen;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	/* Allocate cipher request for current operation. */
1538c2ecf20Sopenharmony_ci	areq = af_alg_alloc_areq(sk, sizeof(struct af_alg_async_req) +
1548c2ecf20Sopenharmony_ci				     crypto_aead_reqsize(tfm));
1558c2ecf20Sopenharmony_ci	if (IS_ERR(areq))
1568c2ecf20Sopenharmony_ci		return PTR_ERR(areq);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/* convert iovecs of output buffers into RX SGL */
1598c2ecf20Sopenharmony_ci	err = af_alg_get_rsgl(sk, msg, flags, areq, outlen, &usedpages);
1608c2ecf20Sopenharmony_ci	if (err)
1618c2ecf20Sopenharmony_ci		goto free;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/*
1648c2ecf20Sopenharmony_ci	 * Ensure output buffer is sufficiently large. If the caller provides
1658c2ecf20Sopenharmony_ci	 * less buffer space, only use the relative required input size. This
1668c2ecf20Sopenharmony_ci	 * allows AIO operation where the caller sent all data to be processed
1678c2ecf20Sopenharmony_ci	 * and the AIO operation performs the operation on the different chunks
1688c2ecf20Sopenharmony_ci	 * of the input data.
1698c2ecf20Sopenharmony_ci	 */
1708c2ecf20Sopenharmony_ci	if (usedpages < outlen) {
1718c2ecf20Sopenharmony_ci		size_t less = outlen - usedpages;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci		if (used < less) {
1748c2ecf20Sopenharmony_ci			err = -EINVAL;
1758c2ecf20Sopenharmony_ci			goto free;
1768c2ecf20Sopenharmony_ci		}
1778c2ecf20Sopenharmony_ci		used -= less;
1788c2ecf20Sopenharmony_ci		outlen -= less;
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	processed = used + ctx->aead_assoclen;
1828c2ecf20Sopenharmony_ci	list_for_each_entry_safe(tsgl, tmp, &ctx->tsgl_list, list) {
1838c2ecf20Sopenharmony_ci		for (i = 0; i < tsgl->cur; i++) {
1848c2ecf20Sopenharmony_ci			struct scatterlist *process_sg = tsgl->sg + i;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci			if (!(process_sg->length) || !sg_page(process_sg))
1878c2ecf20Sopenharmony_ci				continue;
1888c2ecf20Sopenharmony_ci			tsgl_src = process_sg;
1898c2ecf20Sopenharmony_ci			break;
1908c2ecf20Sopenharmony_ci		}
1918c2ecf20Sopenharmony_ci		if (tsgl_src)
1928c2ecf20Sopenharmony_ci			break;
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci	if (processed && !tsgl_src) {
1958c2ecf20Sopenharmony_ci		err = -EFAULT;
1968c2ecf20Sopenharmony_ci		goto free;
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	/*
2008c2ecf20Sopenharmony_ci	 * Copy of AAD from source to destination
2018c2ecf20Sopenharmony_ci	 *
2028c2ecf20Sopenharmony_ci	 * The AAD is copied to the destination buffer without change. Even
2038c2ecf20Sopenharmony_ci	 * when user space uses an in-place cipher operation, the kernel
2048c2ecf20Sopenharmony_ci	 * will copy the data as it does not see whether such in-place operation
2058c2ecf20Sopenharmony_ci	 * is initiated.
2068c2ecf20Sopenharmony_ci	 *
2078c2ecf20Sopenharmony_ci	 * To ensure efficiency, the following implementation ensure that the
2088c2ecf20Sopenharmony_ci	 * ciphers are invoked to perform a crypto operation in-place. This
2098c2ecf20Sopenharmony_ci	 * is achieved by memory management specified as follows.
2108c2ecf20Sopenharmony_ci	 */
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	/* Use the RX SGL as source (and destination) for crypto op. */
2138c2ecf20Sopenharmony_ci	rsgl_src = areq->first_rsgl.sgl.sg;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	if (ctx->enc) {
2168c2ecf20Sopenharmony_ci		/*
2178c2ecf20Sopenharmony_ci		 * Encryption operation - The in-place cipher operation is
2188c2ecf20Sopenharmony_ci		 * achieved by the following operation:
2198c2ecf20Sopenharmony_ci		 *
2208c2ecf20Sopenharmony_ci		 * TX SGL: AAD || PT
2218c2ecf20Sopenharmony_ci		 *	    |	   |
2228c2ecf20Sopenharmony_ci		 *	    | copy |
2238c2ecf20Sopenharmony_ci		 *	    v	   v
2248c2ecf20Sopenharmony_ci		 * RX SGL: AAD || PT || Tag
2258c2ecf20Sopenharmony_ci		 */
2268c2ecf20Sopenharmony_ci		err = crypto_aead_copy_sgl(null_tfm, tsgl_src,
2278c2ecf20Sopenharmony_ci					   areq->first_rsgl.sgl.sg, processed);
2288c2ecf20Sopenharmony_ci		if (err)
2298c2ecf20Sopenharmony_ci			goto free;
2308c2ecf20Sopenharmony_ci		af_alg_pull_tsgl(sk, processed, NULL, 0);
2318c2ecf20Sopenharmony_ci	} else {
2328c2ecf20Sopenharmony_ci		/*
2338c2ecf20Sopenharmony_ci		 * Decryption operation - To achieve an in-place cipher
2348c2ecf20Sopenharmony_ci		 * operation, the following  SGL structure is used:
2358c2ecf20Sopenharmony_ci		 *
2368c2ecf20Sopenharmony_ci		 * TX SGL: AAD || CT || Tag
2378c2ecf20Sopenharmony_ci		 *	    |	   |	 ^
2388c2ecf20Sopenharmony_ci		 *	    | copy |	 | Create SGL link.
2398c2ecf20Sopenharmony_ci		 *	    v	   v	 |
2408c2ecf20Sopenharmony_ci		 * RX SGL: AAD || CT ----+
2418c2ecf20Sopenharmony_ci		 */
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci		 /* Copy AAD || CT to RX SGL buffer for in-place operation. */
2448c2ecf20Sopenharmony_ci		err = crypto_aead_copy_sgl(null_tfm, tsgl_src,
2458c2ecf20Sopenharmony_ci					   areq->first_rsgl.sgl.sg, outlen);
2468c2ecf20Sopenharmony_ci		if (err)
2478c2ecf20Sopenharmony_ci			goto free;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci		/* Create TX SGL for tag and chain it to RX SGL. */
2508c2ecf20Sopenharmony_ci		areq->tsgl_entries = af_alg_count_tsgl(sk, processed,
2518c2ecf20Sopenharmony_ci						       processed - as);
2528c2ecf20Sopenharmony_ci		if (!areq->tsgl_entries)
2538c2ecf20Sopenharmony_ci			areq->tsgl_entries = 1;
2548c2ecf20Sopenharmony_ci		areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl),
2558c2ecf20Sopenharmony_ci							 areq->tsgl_entries),
2568c2ecf20Sopenharmony_ci					  GFP_KERNEL);
2578c2ecf20Sopenharmony_ci		if (!areq->tsgl) {
2588c2ecf20Sopenharmony_ci			err = -ENOMEM;
2598c2ecf20Sopenharmony_ci			goto free;
2608c2ecf20Sopenharmony_ci		}
2618c2ecf20Sopenharmony_ci		sg_init_table(areq->tsgl, areq->tsgl_entries);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci		/* Release TX SGL, except for tag data and reassign tag data. */
2648c2ecf20Sopenharmony_ci		af_alg_pull_tsgl(sk, processed, areq->tsgl, processed - as);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci		/* chain the areq TX SGL holding the tag with RX SGL */
2678c2ecf20Sopenharmony_ci		if (usedpages) {
2688c2ecf20Sopenharmony_ci			/* RX SGL present */
2698c2ecf20Sopenharmony_ci			struct af_alg_sgl *sgl_prev = &areq->last_rsgl->sgl;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci			sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1);
2728c2ecf20Sopenharmony_ci			sg_chain(sgl_prev->sg, sgl_prev->npages + 1,
2738c2ecf20Sopenharmony_ci				 areq->tsgl);
2748c2ecf20Sopenharmony_ci		} else
2758c2ecf20Sopenharmony_ci			/* no RX SGL present (e.g. authentication only) */
2768c2ecf20Sopenharmony_ci			rsgl_src = areq->tsgl;
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/* Initialize the crypto operation */
2808c2ecf20Sopenharmony_ci	aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src,
2818c2ecf20Sopenharmony_ci			       areq->first_rsgl.sgl.sg, used, ctx->iv);
2828c2ecf20Sopenharmony_ci	aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen);
2838c2ecf20Sopenharmony_ci	aead_request_set_tfm(&areq->cra_u.aead_req, tfm);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) {
2868c2ecf20Sopenharmony_ci		/* AIO operation */
2878c2ecf20Sopenharmony_ci		sock_hold(sk);
2888c2ecf20Sopenharmony_ci		areq->iocb = msg->msg_iocb;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci		/* Remember output size that will be generated. */
2918c2ecf20Sopenharmony_ci		areq->outlen = outlen;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci		aead_request_set_callback(&areq->cra_u.aead_req,
2948c2ecf20Sopenharmony_ci					  CRYPTO_TFM_REQ_MAY_SLEEP,
2958c2ecf20Sopenharmony_ci					  af_alg_async_cb, areq);
2968c2ecf20Sopenharmony_ci		err = ctx->enc ? crypto_aead_encrypt(&areq->cra_u.aead_req) :
2978c2ecf20Sopenharmony_ci				 crypto_aead_decrypt(&areq->cra_u.aead_req);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		/* AIO operation in progress */
3008c2ecf20Sopenharmony_ci		if (err == -EINPROGRESS)
3018c2ecf20Sopenharmony_ci			return -EIOCBQUEUED;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci		sock_put(sk);
3048c2ecf20Sopenharmony_ci	} else {
3058c2ecf20Sopenharmony_ci		/* Synchronous operation */
3068c2ecf20Sopenharmony_ci		aead_request_set_callback(&areq->cra_u.aead_req,
3078c2ecf20Sopenharmony_ci					  CRYPTO_TFM_REQ_MAY_SLEEP |
3088c2ecf20Sopenharmony_ci					  CRYPTO_TFM_REQ_MAY_BACKLOG,
3098c2ecf20Sopenharmony_ci					  crypto_req_done, &ctx->wait);
3108c2ecf20Sopenharmony_ci		err = crypto_wait_req(ctx->enc ?
3118c2ecf20Sopenharmony_ci				crypto_aead_encrypt(&areq->cra_u.aead_req) :
3128c2ecf20Sopenharmony_ci				crypto_aead_decrypt(&areq->cra_u.aead_req),
3138c2ecf20Sopenharmony_ci				&ctx->wait);
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cifree:
3188c2ecf20Sopenharmony_ci	af_alg_free_resources(areq);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	return err ? err : outlen;
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic int aead_recvmsg(struct socket *sock, struct msghdr *msg,
3248c2ecf20Sopenharmony_ci			size_t ignored, int flags)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
3278c2ecf20Sopenharmony_ci	int ret = 0;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	lock_sock(sk);
3308c2ecf20Sopenharmony_ci	while (msg_data_left(msg)) {
3318c2ecf20Sopenharmony_ci		int err = _aead_recvmsg(sock, msg, ignored, flags);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		/*
3348c2ecf20Sopenharmony_ci		 * This error covers -EIOCBQUEUED which implies that we can
3358c2ecf20Sopenharmony_ci		 * only handle one AIO request. If the caller wants to have
3368c2ecf20Sopenharmony_ci		 * multiple AIO requests in parallel, he must make multiple
3378c2ecf20Sopenharmony_ci		 * separate AIO calls.
3388c2ecf20Sopenharmony_ci		 *
3398c2ecf20Sopenharmony_ci		 * Also return the error if no data has been processed so far.
3408c2ecf20Sopenharmony_ci		 */
3418c2ecf20Sopenharmony_ci		if (err <= 0) {
3428c2ecf20Sopenharmony_ci			if (err == -EIOCBQUEUED || err == -EBADMSG || !ret)
3438c2ecf20Sopenharmony_ci				ret = err;
3448c2ecf20Sopenharmony_ci			goto out;
3458c2ecf20Sopenharmony_ci		}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci		ret += err;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ciout:
3518c2ecf20Sopenharmony_ci	af_alg_wmem_wakeup(sk);
3528c2ecf20Sopenharmony_ci	release_sock(sk);
3538c2ecf20Sopenharmony_ci	return ret;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic struct proto_ops algif_aead_ops = {
3578c2ecf20Sopenharmony_ci	.family		=	PF_ALG,
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	.connect	=	sock_no_connect,
3608c2ecf20Sopenharmony_ci	.socketpair	=	sock_no_socketpair,
3618c2ecf20Sopenharmony_ci	.getname	=	sock_no_getname,
3628c2ecf20Sopenharmony_ci	.ioctl		=	sock_no_ioctl,
3638c2ecf20Sopenharmony_ci	.listen		=	sock_no_listen,
3648c2ecf20Sopenharmony_ci	.shutdown	=	sock_no_shutdown,
3658c2ecf20Sopenharmony_ci	.mmap		=	sock_no_mmap,
3668c2ecf20Sopenharmony_ci	.bind		=	sock_no_bind,
3678c2ecf20Sopenharmony_ci	.accept		=	sock_no_accept,
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	.release	=	af_alg_release,
3708c2ecf20Sopenharmony_ci	.sendmsg	=	aead_sendmsg,
3718c2ecf20Sopenharmony_ci	.sendpage	=	af_alg_sendpage,
3728c2ecf20Sopenharmony_ci	.recvmsg	=	aead_recvmsg,
3738c2ecf20Sopenharmony_ci	.poll		=	af_alg_poll,
3748c2ecf20Sopenharmony_ci};
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic int aead_check_key(struct socket *sock)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	int err = 0;
3798c2ecf20Sopenharmony_ci	struct sock *psk;
3808c2ecf20Sopenharmony_ci	struct alg_sock *pask;
3818c2ecf20Sopenharmony_ci	struct aead_tfm *tfm;
3828c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
3838c2ecf20Sopenharmony_ci	struct alg_sock *ask = alg_sk(sk);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	lock_sock(sk);
3868c2ecf20Sopenharmony_ci	if (!atomic_read(&ask->nokey_refcnt))
3878c2ecf20Sopenharmony_ci		goto unlock_child;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	psk = ask->parent;
3908c2ecf20Sopenharmony_ci	pask = alg_sk(ask->parent);
3918c2ecf20Sopenharmony_ci	tfm = pask->private;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	err = -ENOKEY;
3948c2ecf20Sopenharmony_ci	lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
3958c2ecf20Sopenharmony_ci	if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY)
3968c2ecf20Sopenharmony_ci		goto unlock;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	atomic_dec(&pask->nokey_refcnt);
3998c2ecf20Sopenharmony_ci	atomic_set(&ask->nokey_refcnt, 0);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	err = 0;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ciunlock:
4048c2ecf20Sopenharmony_ci	release_sock(psk);
4058c2ecf20Sopenharmony_ciunlock_child:
4068c2ecf20Sopenharmony_ci	release_sock(sk);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	return err;
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic int aead_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
4128c2ecf20Sopenharmony_ci				  size_t size)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	int err;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	err = aead_check_key(sock);
4178c2ecf20Sopenharmony_ci	if (err)
4188c2ecf20Sopenharmony_ci		return err;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	return aead_sendmsg(sock, msg, size);
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_cistatic ssize_t aead_sendpage_nokey(struct socket *sock, struct page *page,
4248c2ecf20Sopenharmony_ci				       int offset, size_t size, int flags)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	int err;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	err = aead_check_key(sock);
4298c2ecf20Sopenharmony_ci	if (err)
4308c2ecf20Sopenharmony_ci		return err;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	return af_alg_sendpage(sock, page, offset, size, flags);
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic int aead_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
4368c2ecf20Sopenharmony_ci				  size_t ignored, int flags)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	int err;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	err = aead_check_key(sock);
4418c2ecf20Sopenharmony_ci	if (err)
4428c2ecf20Sopenharmony_ci		return err;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	return aead_recvmsg(sock, msg, ignored, flags);
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic struct proto_ops algif_aead_ops_nokey = {
4488c2ecf20Sopenharmony_ci	.family		=	PF_ALG,
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	.connect	=	sock_no_connect,
4518c2ecf20Sopenharmony_ci	.socketpair	=	sock_no_socketpair,
4528c2ecf20Sopenharmony_ci	.getname	=	sock_no_getname,
4538c2ecf20Sopenharmony_ci	.ioctl		=	sock_no_ioctl,
4548c2ecf20Sopenharmony_ci	.listen		=	sock_no_listen,
4558c2ecf20Sopenharmony_ci	.shutdown	=	sock_no_shutdown,
4568c2ecf20Sopenharmony_ci	.mmap		=	sock_no_mmap,
4578c2ecf20Sopenharmony_ci	.bind		=	sock_no_bind,
4588c2ecf20Sopenharmony_ci	.accept		=	sock_no_accept,
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	.release	=	af_alg_release,
4618c2ecf20Sopenharmony_ci	.sendmsg	=	aead_sendmsg_nokey,
4628c2ecf20Sopenharmony_ci	.sendpage	=	aead_sendpage_nokey,
4638c2ecf20Sopenharmony_ci	.recvmsg	=	aead_recvmsg_nokey,
4648c2ecf20Sopenharmony_ci	.poll		=	af_alg_poll,
4658c2ecf20Sopenharmony_ci};
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic void *aead_bind(const char *name, u32 type, u32 mask)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	struct aead_tfm *tfm;
4708c2ecf20Sopenharmony_ci	struct crypto_aead *aead;
4718c2ecf20Sopenharmony_ci	struct crypto_sync_skcipher *null_tfm;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
4748c2ecf20Sopenharmony_ci	if (!tfm)
4758c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	aead = crypto_alloc_aead(name, type, mask);
4788c2ecf20Sopenharmony_ci	if (IS_ERR(aead)) {
4798c2ecf20Sopenharmony_ci		kfree(tfm);
4808c2ecf20Sopenharmony_ci		return ERR_CAST(aead);
4818c2ecf20Sopenharmony_ci	}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	null_tfm = crypto_get_default_null_skcipher();
4848c2ecf20Sopenharmony_ci	if (IS_ERR(null_tfm)) {
4858c2ecf20Sopenharmony_ci		crypto_free_aead(aead);
4868c2ecf20Sopenharmony_ci		kfree(tfm);
4878c2ecf20Sopenharmony_ci		return ERR_CAST(null_tfm);
4888c2ecf20Sopenharmony_ci	}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	tfm->aead = aead;
4918c2ecf20Sopenharmony_ci	tfm->null_tfm = null_tfm;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	return tfm;
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_cistatic void aead_release(void *private)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	struct aead_tfm *tfm = private;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	crypto_free_aead(tfm->aead);
5018c2ecf20Sopenharmony_ci	crypto_put_default_null_skcipher();
5028c2ecf20Sopenharmony_ci	kfree(tfm);
5038c2ecf20Sopenharmony_ci}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_cistatic int aead_setauthsize(void *private, unsigned int authsize)
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	struct aead_tfm *tfm = private;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	return crypto_aead_setauthsize(tfm->aead, authsize);
5108c2ecf20Sopenharmony_ci}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_cistatic int aead_setkey(void *private, const u8 *key, unsigned int keylen)
5138c2ecf20Sopenharmony_ci{
5148c2ecf20Sopenharmony_ci	struct aead_tfm *tfm = private;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	return crypto_aead_setkey(tfm->aead, key, keylen);
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_cistatic void aead_sock_destruct(struct sock *sk)
5208c2ecf20Sopenharmony_ci{
5218c2ecf20Sopenharmony_ci	struct alg_sock *ask = alg_sk(sk);
5228c2ecf20Sopenharmony_ci	struct af_alg_ctx *ctx = ask->private;
5238c2ecf20Sopenharmony_ci	struct sock *psk = ask->parent;
5248c2ecf20Sopenharmony_ci	struct alg_sock *pask = alg_sk(psk);
5258c2ecf20Sopenharmony_ci	struct aead_tfm *aeadc = pask->private;
5268c2ecf20Sopenharmony_ci	struct crypto_aead *tfm = aeadc->aead;
5278c2ecf20Sopenharmony_ci	unsigned int ivlen = crypto_aead_ivsize(tfm);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	af_alg_pull_tsgl(sk, ctx->used, NULL, 0);
5308c2ecf20Sopenharmony_ci	sock_kzfree_s(sk, ctx->iv, ivlen);
5318c2ecf20Sopenharmony_ci	sock_kfree_s(sk, ctx, ctx->len);
5328c2ecf20Sopenharmony_ci	af_alg_release_parent(sk);
5338c2ecf20Sopenharmony_ci}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_cistatic int aead_accept_parent_nokey(void *private, struct sock *sk)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	struct af_alg_ctx *ctx;
5388c2ecf20Sopenharmony_ci	struct alg_sock *ask = alg_sk(sk);
5398c2ecf20Sopenharmony_ci	struct aead_tfm *tfm = private;
5408c2ecf20Sopenharmony_ci	struct crypto_aead *aead = tfm->aead;
5418c2ecf20Sopenharmony_ci	unsigned int len = sizeof(*ctx);
5428c2ecf20Sopenharmony_ci	unsigned int ivlen = crypto_aead_ivsize(aead);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	ctx = sock_kmalloc(sk, len, GFP_KERNEL);
5458c2ecf20Sopenharmony_ci	if (!ctx)
5468c2ecf20Sopenharmony_ci		return -ENOMEM;
5478c2ecf20Sopenharmony_ci	memset(ctx, 0, len);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	ctx->iv = sock_kmalloc(sk, ivlen, GFP_KERNEL);
5508c2ecf20Sopenharmony_ci	if (!ctx->iv) {
5518c2ecf20Sopenharmony_ci		sock_kfree_s(sk, ctx, len);
5528c2ecf20Sopenharmony_ci		return -ENOMEM;
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci	memset(ctx->iv, 0, ivlen);
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ctx->tsgl_list);
5578c2ecf20Sopenharmony_ci	ctx->len = len;
5588c2ecf20Sopenharmony_ci	crypto_init_wait(&ctx->wait);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	ask->private = ctx;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	sk->sk_destruct = aead_sock_destruct;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	return 0;
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_cistatic int aead_accept_parent(void *private, struct sock *sk)
5688c2ecf20Sopenharmony_ci{
5698c2ecf20Sopenharmony_ci	struct aead_tfm *tfm = private;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY)
5728c2ecf20Sopenharmony_ci		return -ENOKEY;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	return aead_accept_parent_nokey(private, sk);
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_cistatic const struct af_alg_type algif_type_aead = {
5788c2ecf20Sopenharmony_ci	.bind		=	aead_bind,
5798c2ecf20Sopenharmony_ci	.release	=	aead_release,
5808c2ecf20Sopenharmony_ci	.setkey		=	aead_setkey,
5818c2ecf20Sopenharmony_ci	.setauthsize	=	aead_setauthsize,
5828c2ecf20Sopenharmony_ci	.accept		=	aead_accept_parent,
5838c2ecf20Sopenharmony_ci	.accept_nokey	=	aead_accept_parent_nokey,
5848c2ecf20Sopenharmony_ci	.ops		=	&algif_aead_ops,
5858c2ecf20Sopenharmony_ci	.ops_nokey	=	&algif_aead_ops_nokey,
5868c2ecf20Sopenharmony_ci	.name		=	"aead",
5878c2ecf20Sopenharmony_ci	.owner		=	THIS_MODULE
5888c2ecf20Sopenharmony_ci};
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_cistatic int __init algif_aead_init(void)
5918c2ecf20Sopenharmony_ci{
5928c2ecf20Sopenharmony_ci	return af_alg_register_type(&algif_type_aead);
5938c2ecf20Sopenharmony_ci}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_cistatic void __exit algif_aead_exit(void)
5968c2ecf20Sopenharmony_ci{
5978c2ecf20Sopenharmony_ci	int err = af_alg_unregister_type(&algif_type_aead);
5988c2ecf20Sopenharmony_ci	BUG_ON(err);
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cimodule_init(algif_aead_init);
6028c2ecf20Sopenharmony_cimodule_exit(algif_aead_exit);
6038c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
6048c2ecf20Sopenharmony_ciMODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
6058c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AEAD kernel crypto API user space interface");
606