162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * algif_aead: User-space interface for AEAD algorithms 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2014, Stephan Mueller <smueller@chronox.de> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This file provides the user-space API for AEAD ciphers. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * The following concept of the memory management is used: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * The kernel maintains two SGLs, the TX SGL and the RX SGL. The TX SGL is 1262306a36Sopenharmony_ci * filled by user space with the data submitted via sendmsg (maybe with 1362306a36Sopenharmony_ci * MSG_SPLICE_PAGES). Filling up the TX SGL does not cause a crypto operation 1462306a36Sopenharmony_ci * -- the data will only be tracked by the kernel. Upon receipt of one recvmsg 1562306a36Sopenharmony_ci * call, the caller must provide a buffer which is tracked with the RX SGL. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * During the processing of the recvmsg operation, the cipher request is 1862306a36Sopenharmony_ci * allocated and prepared. As part of the recvmsg operation, the processed 1962306a36Sopenharmony_ci * TX buffers are extracted from the TX SGL into a separate SGL. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * After the completion of the crypto operation, the RX SGL and the cipher 2262306a36Sopenharmony_ci * request is released. The extracted TX SGL parts are released together with 2362306a36Sopenharmony_ci * the RX SGL release. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <crypto/internal/aead.h> 2762306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 2862306a36Sopenharmony_ci#include <crypto/if_alg.h> 2962306a36Sopenharmony_ci#include <crypto/skcipher.h> 3062306a36Sopenharmony_ci#include <crypto/null.h> 3162306a36Sopenharmony_ci#include <linux/init.h> 3262306a36Sopenharmony_ci#include <linux/list.h> 3362306a36Sopenharmony_ci#include <linux/kernel.h> 3462306a36Sopenharmony_ci#include <linux/mm.h> 3562306a36Sopenharmony_ci#include <linux/module.h> 3662306a36Sopenharmony_ci#include <linux/net.h> 3762306a36Sopenharmony_ci#include <net/sock.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistruct aead_tfm { 4062306a36Sopenharmony_ci struct crypto_aead *aead; 4162306a36Sopenharmony_ci struct crypto_sync_skcipher *null_tfm; 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic inline bool aead_sufficient_data(struct sock *sk) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct alg_sock *ask = alg_sk(sk); 4762306a36Sopenharmony_ci struct sock *psk = ask->parent; 4862306a36Sopenharmony_ci struct alg_sock *pask = alg_sk(psk); 4962306a36Sopenharmony_ci struct af_alg_ctx *ctx = ask->private; 5062306a36Sopenharmony_ci struct aead_tfm *aeadc = pask->private; 5162306a36Sopenharmony_ci struct crypto_aead *tfm = aeadc->aead; 5262306a36Sopenharmony_ci unsigned int as = crypto_aead_authsize(tfm); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* 5562306a36Sopenharmony_ci * The minimum amount of memory needed for an AEAD cipher is 5662306a36Sopenharmony_ci * the AAD and in case of decryption the tag. 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ci return ctx->used >= ctx->aead_assoclen + (ctx->enc ? 0 : as); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic int aead_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci struct sock *sk = sock->sk; 6462306a36Sopenharmony_ci struct alg_sock *ask = alg_sk(sk); 6562306a36Sopenharmony_ci struct sock *psk = ask->parent; 6662306a36Sopenharmony_ci struct alg_sock *pask = alg_sk(psk); 6762306a36Sopenharmony_ci struct aead_tfm *aeadc = pask->private; 6862306a36Sopenharmony_ci struct crypto_aead *tfm = aeadc->aead; 6962306a36Sopenharmony_ci unsigned int ivsize = crypto_aead_ivsize(tfm); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return af_alg_sendmsg(sock, msg, size, ivsize); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int crypto_aead_copy_sgl(struct crypto_sync_skcipher *null_tfm, 7562306a36Sopenharmony_ci struct scatterlist *src, 7662306a36Sopenharmony_ci struct scatterlist *dst, unsigned int len) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci skcipher_request_set_sync_tfm(skreq, null_tfm); 8162306a36Sopenharmony_ci skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_SLEEP, 8262306a36Sopenharmony_ci NULL, NULL); 8362306a36Sopenharmony_ci skcipher_request_set_crypt(skreq, src, dst, len, NULL); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return crypto_skcipher_encrypt(skreq); 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic int _aead_recvmsg(struct socket *sock, struct msghdr *msg, 8962306a36Sopenharmony_ci size_t ignored, int flags) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct sock *sk = sock->sk; 9262306a36Sopenharmony_ci struct alg_sock *ask = alg_sk(sk); 9362306a36Sopenharmony_ci struct sock *psk = ask->parent; 9462306a36Sopenharmony_ci struct alg_sock *pask = alg_sk(psk); 9562306a36Sopenharmony_ci struct af_alg_ctx *ctx = ask->private; 9662306a36Sopenharmony_ci struct aead_tfm *aeadc = pask->private; 9762306a36Sopenharmony_ci struct crypto_aead *tfm = aeadc->aead; 9862306a36Sopenharmony_ci struct crypto_sync_skcipher *null_tfm = aeadc->null_tfm; 9962306a36Sopenharmony_ci unsigned int i, as = crypto_aead_authsize(tfm); 10062306a36Sopenharmony_ci struct af_alg_async_req *areq; 10162306a36Sopenharmony_ci struct af_alg_tsgl *tsgl, *tmp; 10262306a36Sopenharmony_ci struct scatterlist *rsgl_src, *tsgl_src = NULL; 10362306a36Sopenharmony_ci int err = 0; 10462306a36Sopenharmony_ci size_t used = 0; /* [in] TX bufs to be en/decrypted */ 10562306a36Sopenharmony_ci size_t outlen = 0; /* [out] RX bufs produced by kernel */ 10662306a36Sopenharmony_ci size_t usedpages = 0; /* [in] RX bufs to be used from user */ 10762306a36Sopenharmony_ci size_t processed = 0; /* [in] TX bufs to be consumed */ 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (!ctx->init || ctx->more) { 11062306a36Sopenharmony_ci err = af_alg_wait_for_data(sk, flags, 0); 11162306a36Sopenharmony_ci if (err) 11262306a36Sopenharmony_ci return err; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* 11662306a36Sopenharmony_ci * Data length provided by caller via sendmsg that has not yet been 11762306a36Sopenharmony_ci * processed. 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci used = ctx->used; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* 12262306a36Sopenharmony_ci * Make sure sufficient data is present -- note, the same check is also 12362306a36Sopenharmony_ci * present in sendmsg. The checks in sendmsg shall provide an 12462306a36Sopenharmony_ci * information to the data sender that something is wrong, but they are 12562306a36Sopenharmony_ci * irrelevant to maintain the kernel integrity. We need this check 12662306a36Sopenharmony_ci * here too in case user space decides to not honor the error message 12762306a36Sopenharmony_ci * in sendmsg and still call recvmsg. This check here protects the 12862306a36Sopenharmony_ci * kernel integrity. 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci if (!aead_sufficient_data(sk)) 13162306a36Sopenharmony_ci return -EINVAL; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* 13462306a36Sopenharmony_ci * Calculate the minimum output buffer size holding the result of the 13562306a36Sopenharmony_ci * cipher operation. When encrypting data, the receiving buffer is 13662306a36Sopenharmony_ci * larger by the tag length compared to the input buffer as the 13762306a36Sopenharmony_ci * encryption operation generates the tag. For decryption, the input 13862306a36Sopenharmony_ci * buffer provides the tag which is consumed resulting in only the 13962306a36Sopenharmony_ci * plaintext without a buffer for the tag returned to the caller. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci if (ctx->enc) 14262306a36Sopenharmony_ci outlen = used + as; 14362306a36Sopenharmony_ci else 14462306a36Sopenharmony_ci outlen = used - as; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * The cipher operation input data is reduced by the associated data 14862306a36Sopenharmony_ci * length as this data is processed separately later on. 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci used -= ctx->aead_assoclen; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* Allocate cipher request for current operation. */ 15362306a36Sopenharmony_ci areq = af_alg_alloc_areq(sk, sizeof(struct af_alg_async_req) + 15462306a36Sopenharmony_ci crypto_aead_reqsize(tfm)); 15562306a36Sopenharmony_ci if (IS_ERR(areq)) 15662306a36Sopenharmony_ci return PTR_ERR(areq); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* convert iovecs of output buffers into RX SGL */ 15962306a36Sopenharmony_ci err = af_alg_get_rsgl(sk, msg, flags, areq, outlen, &usedpages); 16062306a36Sopenharmony_ci if (err) 16162306a36Sopenharmony_ci goto free; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* 16462306a36Sopenharmony_ci * Ensure output buffer is sufficiently large. If the caller provides 16562306a36Sopenharmony_ci * less buffer space, only use the relative required input size. This 16662306a36Sopenharmony_ci * allows AIO operation where the caller sent all data to be processed 16762306a36Sopenharmony_ci * and the AIO operation performs the operation on the different chunks 16862306a36Sopenharmony_ci * of the input data. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ci if (usedpages < outlen) { 17162306a36Sopenharmony_ci size_t less = outlen - usedpages; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (used < less) { 17462306a36Sopenharmony_ci err = -EINVAL; 17562306a36Sopenharmony_ci goto free; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci used -= less; 17862306a36Sopenharmony_ci outlen -= less; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci processed = used + ctx->aead_assoclen; 18262306a36Sopenharmony_ci list_for_each_entry_safe(tsgl, tmp, &ctx->tsgl_list, list) { 18362306a36Sopenharmony_ci for (i = 0; i < tsgl->cur; i++) { 18462306a36Sopenharmony_ci struct scatterlist *process_sg = tsgl->sg + i; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (!(process_sg->length) || !sg_page(process_sg)) 18762306a36Sopenharmony_ci continue; 18862306a36Sopenharmony_ci tsgl_src = process_sg; 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci if (tsgl_src) 19262306a36Sopenharmony_ci break; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci if (processed && !tsgl_src) { 19562306a36Sopenharmony_ci err = -EFAULT; 19662306a36Sopenharmony_ci goto free; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* 20062306a36Sopenharmony_ci * Copy of AAD from source to destination 20162306a36Sopenharmony_ci * 20262306a36Sopenharmony_ci * The AAD is copied to the destination buffer without change. Even 20362306a36Sopenharmony_ci * when user space uses an in-place cipher operation, the kernel 20462306a36Sopenharmony_ci * will copy the data as it does not see whether such in-place operation 20562306a36Sopenharmony_ci * is initiated. 20662306a36Sopenharmony_ci * 20762306a36Sopenharmony_ci * To ensure efficiency, the following implementation ensure that the 20862306a36Sopenharmony_ci * ciphers are invoked to perform a crypto operation in-place. This 20962306a36Sopenharmony_ci * is achieved by memory management specified as follows. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* Use the RX SGL as source (and destination) for crypto op. */ 21362306a36Sopenharmony_ci rsgl_src = areq->first_rsgl.sgl.sgt.sgl; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (ctx->enc) { 21662306a36Sopenharmony_ci /* 21762306a36Sopenharmony_ci * Encryption operation - The in-place cipher operation is 21862306a36Sopenharmony_ci * achieved by the following operation: 21962306a36Sopenharmony_ci * 22062306a36Sopenharmony_ci * TX SGL: AAD || PT 22162306a36Sopenharmony_ci * | | 22262306a36Sopenharmony_ci * | copy | 22362306a36Sopenharmony_ci * v v 22462306a36Sopenharmony_ci * RX SGL: AAD || PT || Tag 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ci err = crypto_aead_copy_sgl(null_tfm, tsgl_src, 22762306a36Sopenharmony_ci areq->first_rsgl.sgl.sgt.sgl, 22862306a36Sopenharmony_ci processed); 22962306a36Sopenharmony_ci if (err) 23062306a36Sopenharmony_ci goto free; 23162306a36Sopenharmony_ci af_alg_pull_tsgl(sk, processed, NULL, 0); 23262306a36Sopenharmony_ci } else { 23362306a36Sopenharmony_ci /* 23462306a36Sopenharmony_ci * Decryption operation - To achieve an in-place cipher 23562306a36Sopenharmony_ci * operation, the following SGL structure is used: 23662306a36Sopenharmony_ci * 23762306a36Sopenharmony_ci * TX SGL: AAD || CT || Tag 23862306a36Sopenharmony_ci * | | ^ 23962306a36Sopenharmony_ci * | copy | | Create SGL link. 24062306a36Sopenharmony_ci * v v | 24162306a36Sopenharmony_ci * RX SGL: AAD || CT ----+ 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* Copy AAD || CT to RX SGL buffer for in-place operation. */ 24562306a36Sopenharmony_ci err = crypto_aead_copy_sgl(null_tfm, tsgl_src, 24662306a36Sopenharmony_ci areq->first_rsgl.sgl.sgt.sgl, 24762306a36Sopenharmony_ci outlen); 24862306a36Sopenharmony_ci if (err) 24962306a36Sopenharmony_ci goto free; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Create TX SGL for tag and chain it to RX SGL. */ 25262306a36Sopenharmony_ci areq->tsgl_entries = af_alg_count_tsgl(sk, processed, 25362306a36Sopenharmony_ci processed - as); 25462306a36Sopenharmony_ci if (!areq->tsgl_entries) 25562306a36Sopenharmony_ci areq->tsgl_entries = 1; 25662306a36Sopenharmony_ci areq->tsgl = sock_kmalloc(sk, array_size(sizeof(*areq->tsgl), 25762306a36Sopenharmony_ci areq->tsgl_entries), 25862306a36Sopenharmony_ci GFP_KERNEL); 25962306a36Sopenharmony_ci if (!areq->tsgl) { 26062306a36Sopenharmony_ci err = -ENOMEM; 26162306a36Sopenharmony_ci goto free; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci sg_init_table(areq->tsgl, areq->tsgl_entries); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* Release TX SGL, except for tag data and reassign tag data. */ 26662306a36Sopenharmony_ci af_alg_pull_tsgl(sk, processed, areq->tsgl, processed - as); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* chain the areq TX SGL holding the tag with RX SGL */ 26962306a36Sopenharmony_ci if (usedpages) { 27062306a36Sopenharmony_ci /* RX SGL present */ 27162306a36Sopenharmony_ci struct af_alg_sgl *sgl_prev = &areq->last_rsgl->sgl; 27262306a36Sopenharmony_ci struct scatterlist *sg = sgl_prev->sgt.sgl; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci sg_unmark_end(sg + sgl_prev->sgt.nents - 1); 27562306a36Sopenharmony_ci sg_chain(sg, sgl_prev->sgt.nents + 1, areq->tsgl); 27662306a36Sopenharmony_ci } else 27762306a36Sopenharmony_ci /* no RX SGL present (e.g. authentication only) */ 27862306a36Sopenharmony_ci rsgl_src = areq->tsgl; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Initialize the crypto operation */ 28262306a36Sopenharmony_ci aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src, 28362306a36Sopenharmony_ci areq->first_rsgl.sgl.sgt.sgl, used, ctx->iv); 28462306a36Sopenharmony_ci aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen); 28562306a36Sopenharmony_ci aead_request_set_tfm(&areq->cra_u.aead_req, tfm); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { 28862306a36Sopenharmony_ci /* AIO operation */ 28962306a36Sopenharmony_ci sock_hold(sk); 29062306a36Sopenharmony_ci areq->iocb = msg->msg_iocb; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* Remember output size that will be generated. */ 29362306a36Sopenharmony_ci areq->outlen = outlen; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci aead_request_set_callback(&areq->cra_u.aead_req, 29662306a36Sopenharmony_ci CRYPTO_TFM_REQ_MAY_SLEEP, 29762306a36Sopenharmony_ci af_alg_async_cb, areq); 29862306a36Sopenharmony_ci err = ctx->enc ? crypto_aead_encrypt(&areq->cra_u.aead_req) : 29962306a36Sopenharmony_ci crypto_aead_decrypt(&areq->cra_u.aead_req); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* AIO operation in progress */ 30262306a36Sopenharmony_ci if (err == -EINPROGRESS) 30362306a36Sopenharmony_ci return -EIOCBQUEUED; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci sock_put(sk); 30662306a36Sopenharmony_ci } else { 30762306a36Sopenharmony_ci /* Synchronous operation */ 30862306a36Sopenharmony_ci aead_request_set_callback(&areq->cra_u.aead_req, 30962306a36Sopenharmony_ci CRYPTO_TFM_REQ_MAY_SLEEP | 31062306a36Sopenharmony_ci CRYPTO_TFM_REQ_MAY_BACKLOG, 31162306a36Sopenharmony_ci crypto_req_done, &ctx->wait); 31262306a36Sopenharmony_ci err = crypto_wait_req(ctx->enc ? 31362306a36Sopenharmony_ci crypto_aead_encrypt(&areq->cra_u.aead_req) : 31462306a36Sopenharmony_ci crypto_aead_decrypt(&areq->cra_u.aead_req), 31562306a36Sopenharmony_ci &ctx->wait); 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cifree: 32062306a36Sopenharmony_ci af_alg_free_resources(areq); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci return err ? err : outlen; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic int aead_recvmsg(struct socket *sock, struct msghdr *msg, 32662306a36Sopenharmony_ci size_t ignored, int flags) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct sock *sk = sock->sk; 32962306a36Sopenharmony_ci int ret = 0; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci lock_sock(sk); 33262306a36Sopenharmony_ci while (msg_data_left(msg)) { 33362306a36Sopenharmony_ci int err = _aead_recvmsg(sock, msg, ignored, flags); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* 33662306a36Sopenharmony_ci * This error covers -EIOCBQUEUED which implies that we can 33762306a36Sopenharmony_ci * only handle one AIO request. If the caller wants to have 33862306a36Sopenharmony_ci * multiple AIO requests in parallel, he must make multiple 33962306a36Sopenharmony_ci * separate AIO calls. 34062306a36Sopenharmony_ci * 34162306a36Sopenharmony_ci * Also return the error if no data has been processed so far. 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_ci if (err <= 0) { 34462306a36Sopenharmony_ci if (err == -EIOCBQUEUED || err == -EBADMSG || !ret) 34562306a36Sopenharmony_ci ret = err; 34662306a36Sopenharmony_ci goto out; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci ret += err; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ciout: 35362306a36Sopenharmony_ci af_alg_wmem_wakeup(sk); 35462306a36Sopenharmony_ci release_sock(sk); 35562306a36Sopenharmony_ci return ret; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic struct proto_ops algif_aead_ops = { 35962306a36Sopenharmony_ci .family = PF_ALG, 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci .connect = sock_no_connect, 36262306a36Sopenharmony_ci .socketpair = sock_no_socketpair, 36362306a36Sopenharmony_ci .getname = sock_no_getname, 36462306a36Sopenharmony_ci .ioctl = sock_no_ioctl, 36562306a36Sopenharmony_ci .listen = sock_no_listen, 36662306a36Sopenharmony_ci .shutdown = sock_no_shutdown, 36762306a36Sopenharmony_ci .mmap = sock_no_mmap, 36862306a36Sopenharmony_ci .bind = sock_no_bind, 36962306a36Sopenharmony_ci .accept = sock_no_accept, 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci .release = af_alg_release, 37262306a36Sopenharmony_ci .sendmsg = aead_sendmsg, 37362306a36Sopenharmony_ci .recvmsg = aead_recvmsg, 37462306a36Sopenharmony_ci .poll = af_alg_poll, 37562306a36Sopenharmony_ci}; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic int aead_check_key(struct socket *sock) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci int err = 0; 38062306a36Sopenharmony_ci struct sock *psk; 38162306a36Sopenharmony_ci struct alg_sock *pask; 38262306a36Sopenharmony_ci struct aead_tfm *tfm; 38362306a36Sopenharmony_ci struct sock *sk = sock->sk; 38462306a36Sopenharmony_ci struct alg_sock *ask = alg_sk(sk); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci lock_sock(sk); 38762306a36Sopenharmony_ci if (!atomic_read(&ask->nokey_refcnt)) 38862306a36Sopenharmony_ci goto unlock_child; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci psk = ask->parent; 39162306a36Sopenharmony_ci pask = alg_sk(ask->parent); 39262306a36Sopenharmony_ci tfm = pask->private; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci err = -ENOKEY; 39562306a36Sopenharmony_ci lock_sock_nested(psk, SINGLE_DEPTH_NESTING); 39662306a36Sopenharmony_ci if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY) 39762306a36Sopenharmony_ci goto unlock; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci atomic_dec(&pask->nokey_refcnt); 40062306a36Sopenharmony_ci atomic_set(&ask->nokey_refcnt, 0); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci err = 0; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ciunlock: 40562306a36Sopenharmony_ci release_sock(psk); 40662306a36Sopenharmony_ciunlock_child: 40762306a36Sopenharmony_ci release_sock(sk); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci return err; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic int aead_sendmsg_nokey(struct socket *sock, struct msghdr *msg, 41362306a36Sopenharmony_ci size_t size) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci int err; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci err = aead_check_key(sock); 41862306a36Sopenharmony_ci if (err) 41962306a36Sopenharmony_ci return err; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci return aead_sendmsg(sock, msg, size); 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic int aead_recvmsg_nokey(struct socket *sock, struct msghdr *msg, 42562306a36Sopenharmony_ci size_t ignored, int flags) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci int err; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci err = aead_check_key(sock); 43062306a36Sopenharmony_ci if (err) 43162306a36Sopenharmony_ci return err; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return aead_recvmsg(sock, msg, ignored, flags); 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic struct proto_ops algif_aead_ops_nokey = { 43762306a36Sopenharmony_ci .family = PF_ALG, 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci .connect = sock_no_connect, 44062306a36Sopenharmony_ci .socketpair = sock_no_socketpair, 44162306a36Sopenharmony_ci .getname = sock_no_getname, 44262306a36Sopenharmony_ci .ioctl = sock_no_ioctl, 44362306a36Sopenharmony_ci .listen = sock_no_listen, 44462306a36Sopenharmony_ci .shutdown = sock_no_shutdown, 44562306a36Sopenharmony_ci .mmap = sock_no_mmap, 44662306a36Sopenharmony_ci .bind = sock_no_bind, 44762306a36Sopenharmony_ci .accept = sock_no_accept, 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci .release = af_alg_release, 45062306a36Sopenharmony_ci .sendmsg = aead_sendmsg_nokey, 45162306a36Sopenharmony_ci .recvmsg = aead_recvmsg_nokey, 45262306a36Sopenharmony_ci .poll = af_alg_poll, 45362306a36Sopenharmony_ci}; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic void *aead_bind(const char *name, u32 type, u32 mask) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci struct aead_tfm *tfm; 45862306a36Sopenharmony_ci struct crypto_aead *aead; 45962306a36Sopenharmony_ci struct crypto_sync_skcipher *null_tfm; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); 46262306a36Sopenharmony_ci if (!tfm) 46362306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci aead = crypto_alloc_aead(name, type, mask); 46662306a36Sopenharmony_ci if (IS_ERR(aead)) { 46762306a36Sopenharmony_ci kfree(tfm); 46862306a36Sopenharmony_ci return ERR_CAST(aead); 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci null_tfm = crypto_get_default_null_skcipher(); 47262306a36Sopenharmony_ci if (IS_ERR(null_tfm)) { 47362306a36Sopenharmony_ci crypto_free_aead(aead); 47462306a36Sopenharmony_ci kfree(tfm); 47562306a36Sopenharmony_ci return ERR_CAST(null_tfm); 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci tfm->aead = aead; 47962306a36Sopenharmony_ci tfm->null_tfm = null_tfm; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci return tfm; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic void aead_release(void *private) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci struct aead_tfm *tfm = private; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci crypto_free_aead(tfm->aead); 48962306a36Sopenharmony_ci crypto_put_default_null_skcipher(); 49062306a36Sopenharmony_ci kfree(tfm); 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic int aead_setauthsize(void *private, unsigned int authsize) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct aead_tfm *tfm = private; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return crypto_aead_setauthsize(tfm->aead, authsize); 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic int aead_setkey(void *private, const u8 *key, unsigned int keylen) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct aead_tfm *tfm = private; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci return crypto_aead_setkey(tfm->aead, key, keylen); 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic void aead_sock_destruct(struct sock *sk) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci struct alg_sock *ask = alg_sk(sk); 51062306a36Sopenharmony_ci struct af_alg_ctx *ctx = ask->private; 51162306a36Sopenharmony_ci struct sock *psk = ask->parent; 51262306a36Sopenharmony_ci struct alg_sock *pask = alg_sk(psk); 51362306a36Sopenharmony_ci struct aead_tfm *aeadc = pask->private; 51462306a36Sopenharmony_ci struct crypto_aead *tfm = aeadc->aead; 51562306a36Sopenharmony_ci unsigned int ivlen = crypto_aead_ivsize(tfm); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci af_alg_pull_tsgl(sk, ctx->used, NULL, 0); 51862306a36Sopenharmony_ci sock_kzfree_s(sk, ctx->iv, ivlen); 51962306a36Sopenharmony_ci sock_kfree_s(sk, ctx, ctx->len); 52062306a36Sopenharmony_ci af_alg_release_parent(sk); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic int aead_accept_parent_nokey(void *private, struct sock *sk) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct af_alg_ctx *ctx; 52662306a36Sopenharmony_ci struct alg_sock *ask = alg_sk(sk); 52762306a36Sopenharmony_ci struct aead_tfm *tfm = private; 52862306a36Sopenharmony_ci struct crypto_aead *aead = tfm->aead; 52962306a36Sopenharmony_ci unsigned int len = sizeof(*ctx); 53062306a36Sopenharmony_ci unsigned int ivlen = crypto_aead_ivsize(aead); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci ctx = sock_kmalloc(sk, len, GFP_KERNEL); 53362306a36Sopenharmony_ci if (!ctx) 53462306a36Sopenharmony_ci return -ENOMEM; 53562306a36Sopenharmony_ci memset(ctx, 0, len); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci ctx->iv = sock_kmalloc(sk, ivlen, GFP_KERNEL); 53862306a36Sopenharmony_ci if (!ctx->iv) { 53962306a36Sopenharmony_ci sock_kfree_s(sk, ctx, len); 54062306a36Sopenharmony_ci return -ENOMEM; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci memset(ctx->iv, 0, ivlen); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci INIT_LIST_HEAD(&ctx->tsgl_list); 54562306a36Sopenharmony_ci ctx->len = len; 54662306a36Sopenharmony_ci crypto_init_wait(&ctx->wait); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci ask->private = ctx; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci sk->sk_destruct = aead_sock_destruct; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci return 0; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic int aead_accept_parent(void *private, struct sock *sk) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci struct aead_tfm *tfm = private; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY) 56062306a36Sopenharmony_ci return -ENOKEY; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return aead_accept_parent_nokey(private, sk); 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic const struct af_alg_type algif_type_aead = { 56662306a36Sopenharmony_ci .bind = aead_bind, 56762306a36Sopenharmony_ci .release = aead_release, 56862306a36Sopenharmony_ci .setkey = aead_setkey, 56962306a36Sopenharmony_ci .setauthsize = aead_setauthsize, 57062306a36Sopenharmony_ci .accept = aead_accept_parent, 57162306a36Sopenharmony_ci .accept_nokey = aead_accept_parent_nokey, 57262306a36Sopenharmony_ci .ops = &algif_aead_ops, 57362306a36Sopenharmony_ci .ops_nokey = &algif_aead_ops_nokey, 57462306a36Sopenharmony_ci .name = "aead", 57562306a36Sopenharmony_ci .owner = THIS_MODULE 57662306a36Sopenharmony_ci}; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic int __init algif_aead_init(void) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci return af_alg_register_type(&algif_type_aead); 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_cistatic void __exit algif_aead_exit(void) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci int err = af_alg_unregister_type(&algif_type_aead); 58662306a36Sopenharmony_ci BUG_ON(err); 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cimodule_init(algif_aead_init); 59062306a36Sopenharmony_cimodule_exit(algif_aead_exit); 59162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 59262306a36Sopenharmony_ciMODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>"); 59362306a36Sopenharmony_ciMODULE_DESCRIPTION("AEAD kernel crypto API user space interface"); 594