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