162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * algif_hash: User-space interface for hash algorithms 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This file provides the user-space API for hash algorithms. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <crypto/hash.h> 1162306a36Sopenharmony_ci#include <crypto/if_alg.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/mm.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/net.h> 1762306a36Sopenharmony_ci#include <net/sock.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistruct hash_ctx { 2062306a36Sopenharmony_ci struct af_alg_sgl sgl; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci u8 *result; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci struct crypto_wait wait; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci unsigned int len; 2762306a36Sopenharmony_ci bool more; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci struct ahash_request req; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic int hash_alloc_result(struct sock *sk, struct hash_ctx *ctx) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci unsigned ds; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (ctx->result) 3762306a36Sopenharmony_ci return 0; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req)); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci ctx->result = sock_kmalloc(sk, ds, GFP_KERNEL); 4262306a36Sopenharmony_ci if (!ctx->result) 4362306a36Sopenharmony_ci return -ENOMEM; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci memset(ctx->result, 0, ds); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci return 0; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic void hash_free_result(struct sock *sk, struct hash_ctx *ctx) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci unsigned ds; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (!ctx->result) 5562306a36Sopenharmony_ci return; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req)); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci sock_kzfree_s(sk, ctx->result, ds); 6062306a36Sopenharmony_ci ctx->result = NULL; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic int hash_sendmsg(struct socket *sock, struct msghdr *msg, 6462306a36Sopenharmony_ci size_t ignored) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct sock *sk = sock->sk; 6762306a36Sopenharmony_ci struct alg_sock *ask = alg_sk(sk); 6862306a36Sopenharmony_ci struct hash_ctx *ctx = ask->private; 6962306a36Sopenharmony_ci ssize_t copied = 0; 7062306a36Sopenharmony_ci size_t len, max_pages, npages; 7162306a36Sopenharmony_ci bool continuing, need_init = false; 7262306a36Sopenharmony_ci int err; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci max_pages = min_t(size_t, ALG_MAX_PAGES, 7562306a36Sopenharmony_ci DIV_ROUND_UP(sk->sk_sndbuf, PAGE_SIZE)); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci lock_sock(sk); 7862306a36Sopenharmony_ci continuing = ctx->more; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (!continuing) { 8162306a36Sopenharmony_ci /* Discard a previous request that wasn't marked MSG_MORE. */ 8262306a36Sopenharmony_ci hash_free_result(sk, ctx); 8362306a36Sopenharmony_ci if (!msg_data_left(msg)) 8462306a36Sopenharmony_ci goto done; /* Zero-length; don't start new req */ 8562306a36Sopenharmony_ci need_init = true; 8662306a36Sopenharmony_ci } else if (!msg_data_left(msg)) { 8762306a36Sopenharmony_ci /* 8862306a36Sopenharmony_ci * No data - finalise the prev req if MSG_MORE so any error 8962306a36Sopenharmony_ci * comes out here. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_ci if (!(msg->msg_flags & MSG_MORE)) { 9262306a36Sopenharmony_ci err = hash_alloc_result(sk, ctx); 9362306a36Sopenharmony_ci if (err) 9462306a36Sopenharmony_ci goto unlock_free_result; 9562306a36Sopenharmony_ci ahash_request_set_crypt(&ctx->req, NULL, 9662306a36Sopenharmony_ci ctx->result, 0); 9762306a36Sopenharmony_ci err = crypto_wait_req(crypto_ahash_final(&ctx->req), 9862306a36Sopenharmony_ci &ctx->wait); 9962306a36Sopenharmony_ci if (err) 10062306a36Sopenharmony_ci goto unlock_free_result; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci goto done_more; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci while (msg_data_left(msg)) { 10662306a36Sopenharmony_ci ctx->sgl.sgt.sgl = ctx->sgl.sgl; 10762306a36Sopenharmony_ci ctx->sgl.sgt.nents = 0; 10862306a36Sopenharmony_ci ctx->sgl.sgt.orig_nents = 0; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci err = -EIO; 11162306a36Sopenharmony_ci npages = iov_iter_npages(&msg->msg_iter, max_pages); 11262306a36Sopenharmony_ci if (npages == 0) 11362306a36Sopenharmony_ci goto unlock_free; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci sg_init_table(ctx->sgl.sgl, npages); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci ctx->sgl.need_unpin = iov_iter_extract_will_pin(&msg->msg_iter); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci err = extract_iter_to_sg(&msg->msg_iter, LONG_MAX, 12062306a36Sopenharmony_ci &ctx->sgl.sgt, npages, 0); 12162306a36Sopenharmony_ci if (err < 0) 12262306a36Sopenharmony_ci goto unlock_free; 12362306a36Sopenharmony_ci len = err; 12462306a36Sopenharmony_ci sg_mark_end(ctx->sgl.sgt.sgl + ctx->sgl.sgt.nents - 1); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (!msg_data_left(msg)) { 12762306a36Sopenharmony_ci err = hash_alloc_result(sk, ctx); 12862306a36Sopenharmony_ci if (err) 12962306a36Sopenharmony_ci goto unlock_free; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci ahash_request_set_crypt(&ctx->req, ctx->sgl.sgt.sgl, 13362306a36Sopenharmony_ci ctx->result, len); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (!msg_data_left(msg) && !continuing && 13662306a36Sopenharmony_ci !(msg->msg_flags & MSG_MORE)) { 13762306a36Sopenharmony_ci err = crypto_ahash_digest(&ctx->req); 13862306a36Sopenharmony_ci } else { 13962306a36Sopenharmony_ci if (need_init) { 14062306a36Sopenharmony_ci err = crypto_wait_req( 14162306a36Sopenharmony_ci crypto_ahash_init(&ctx->req), 14262306a36Sopenharmony_ci &ctx->wait); 14362306a36Sopenharmony_ci if (err) 14462306a36Sopenharmony_ci goto unlock_free; 14562306a36Sopenharmony_ci need_init = false; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (msg_data_left(msg) || (msg->msg_flags & MSG_MORE)) 14962306a36Sopenharmony_ci err = crypto_ahash_update(&ctx->req); 15062306a36Sopenharmony_ci else 15162306a36Sopenharmony_ci err = crypto_ahash_finup(&ctx->req); 15262306a36Sopenharmony_ci continuing = true; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci err = crypto_wait_req(err, &ctx->wait); 15662306a36Sopenharmony_ci if (err) 15762306a36Sopenharmony_ci goto unlock_free; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci copied += len; 16062306a36Sopenharmony_ci af_alg_free_sg(&ctx->sgl); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cidone_more: 16462306a36Sopenharmony_ci ctx->more = msg->msg_flags & MSG_MORE; 16562306a36Sopenharmony_cidone: 16662306a36Sopenharmony_ci err = 0; 16762306a36Sopenharmony_ciunlock: 16862306a36Sopenharmony_ci release_sock(sk); 16962306a36Sopenharmony_ci return copied ?: err; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ciunlock_free: 17262306a36Sopenharmony_ci af_alg_free_sg(&ctx->sgl); 17362306a36Sopenharmony_ciunlock_free_result: 17462306a36Sopenharmony_ci hash_free_result(sk, ctx); 17562306a36Sopenharmony_ci ctx->more = false; 17662306a36Sopenharmony_ci goto unlock; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic int hash_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, 18062306a36Sopenharmony_ci int flags) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct sock *sk = sock->sk; 18362306a36Sopenharmony_ci struct alg_sock *ask = alg_sk(sk); 18462306a36Sopenharmony_ci struct hash_ctx *ctx = ask->private; 18562306a36Sopenharmony_ci unsigned ds = crypto_ahash_digestsize(crypto_ahash_reqtfm(&ctx->req)); 18662306a36Sopenharmony_ci bool result; 18762306a36Sopenharmony_ci int err; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (len > ds) 19062306a36Sopenharmony_ci len = ds; 19162306a36Sopenharmony_ci else if (len < ds) 19262306a36Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci lock_sock(sk); 19562306a36Sopenharmony_ci result = ctx->result; 19662306a36Sopenharmony_ci err = hash_alloc_result(sk, ctx); 19762306a36Sopenharmony_ci if (err) 19862306a36Sopenharmony_ci goto unlock; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (!result && !ctx->more) { 20362306a36Sopenharmony_ci err = crypto_wait_req(crypto_ahash_init(&ctx->req), 20462306a36Sopenharmony_ci &ctx->wait); 20562306a36Sopenharmony_ci if (err) 20662306a36Sopenharmony_ci goto unlock; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (!result || ctx->more) { 21062306a36Sopenharmony_ci ctx->more = false; 21162306a36Sopenharmony_ci err = crypto_wait_req(crypto_ahash_final(&ctx->req), 21262306a36Sopenharmony_ci &ctx->wait); 21362306a36Sopenharmony_ci if (err) 21462306a36Sopenharmony_ci goto unlock; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci err = memcpy_to_msg(msg, ctx->result, len); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ciunlock: 22062306a36Sopenharmony_ci hash_free_result(sk, ctx); 22162306a36Sopenharmony_ci release_sock(sk); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci return err ?: len; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic int hash_accept(struct socket *sock, struct socket *newsock, int flags, 22762306a36Sopenharmony_ci bool kern) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci struct sock *sk = sock->sk; 23062306a36Sopenharmony_ci struct alg_sock *ask = alg_sk(sk); 23162306a36Sopenharmony_ci struct hash_ctx *ctx = ask->private; 23262306a36Sopenharmony_ci struct ahash_request *req = &ctx->req; 23362306a36Sopenharmony_ci struct crypto_ahash *tfm; 23462306a36Sopenharmony_ci struct sock *sk2; 23562306a36Sopenharmony_ci struct alg_sock *ask2; 23662306a36Sopenharmony_ci struct hash_ctx *ctx2; 23762306a36Sopenharmony_ci char *state; 23862306a36Sopenharmony_ci bool more; 23962306a36Sopenharmony_ci int err; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci tfm = crypto_ahash_reqtfm(req); 24262306a36Sopenharmony_ci state = kmalloc(crypto_ahash_statesize(tfm), GFP_KERNEL); 24362306a36Sopenharmony_ci err = -ENOMEM; 24462306a36Sopenharmony_ci if (!state) 24562306a36Sopenharmony_ci goto out; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci lock_sock(sk); 24862306a36Sopenharmony_ci more = ctx->more; 24962306a36Sopenharmony_ci err = more ? crypto_ahash_export(req, state) : 0; 25062306a36Sopenharmony_ci release_sock(sk); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (err) 25362306a36Sopenharmony_ci goto out_free_state; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci err = af_alg_accept(ask->parent, newsock, kern); 25662306a36Sopenharmony_ci if (err) 25762306a36Sopenharmony_ci goto out_free_state; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci sk2 = newsock->sk; 26062306a36Sopenharmony_ci ask2 = alg_sk(sk2); 26162306a36Sopenharmony_ci ctx2 = ask2->private; 26262306a36Sopenharmony_ci ctx2->more = more; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (!more) 26562306a36Sopenharmony_ci goto out_free_state; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci err = crypto_ahash_import(&ctx2->req, state); 26862306a36Sopenharmony_ci if (err) { 26962306a36Sopenharmony_ci sock_orphan(sk2); 27062306a36Sopenharmony_ci sock_put(sk2); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ciout_free_state: 27462306a36Sopenharmony_ci kfree_sensitive(state); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ciout: 27762306a36Sopenharmony_ci return err; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic struct proto_ops algif_hash_ops = { 28162306a36Sopenharmony_ci .family = PF_ALG, 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci .connect = sock_no_connect, 28462306a36Sopenharmony_ci .socketpair = sock_no_socketpair, 28562306a36Sopenharmony_ci .getname = sock_no_getname, 28662306a36Sopenharmony_ci .ioctl = sock_no_ioctl, 28762306a36Sopenharmony_ci .listen = sock_no_listen, 28862306a36Sopenharmony_ci .shutdown = sock_no_shutdown, 28962306a36Sopenharmony_ci .mmap = sock_no_mmap, 29062306a36Sopenharmony_ci .bind = sock_no_bind, 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci .release = af_alg_release, 29362306a36Sopenharmony_ci .sendmsg = hash_sendmsg, 29462306a36Sopenharmony_ci .recvmsg = hash_recvmsg, 29562306a36Sopenharmony_ci .accept = hash_accept, 29662306a36Sopenharmony_ci}; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic int hash_check_key(struct socket *sock) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci int err = 0; 30162306a36Sopenharmony_ci struct sock *psk; 30262306a36Sopenharmony_ci struct alg_sock *pask; 30362306a36Sopenharmony_ci struct crypto_ahash *tfm; 30462306a36Sopenharmony_ci struct sock *sk = sock->sk; 30562306a36Sopenharmony_ci struct alg_sock *ask = alg_sk(sk); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci lock_sock(sk); 30862306a36Sopenharmony_ci if (!atomic_read(&ask->nokey_refcnt)) 30962306a36Sopenharmony_ci goto unlock_child; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci psk = ask->parent; 31262306a36Sopenharmony_ci pask = alg_sk(ask->parent); 31362306a36Sopenharmony_ci tfm = pask->private; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci err = -ENOKEY; 31662306a36Sopenharmony_ci lock_sock_nested(psk, SINGLE_DEPTH_NESTING); 31762306a36Sopenharmony_ci if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) 31862306a36Sopenharmony_ci goto unlock; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci atomic_dec(&pask->nokey_refcnt); 32162306a36Sopenharmony_ci atomic_set(&ask->nokey_refcnt, 0); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci err = 0; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ciunlock: 32662306a36Sopenharmony_ci release_sock(psk); 32762306a36Sopenharmony_ciunlock_child: 32862306a36Sopenharmony_ci release_sock(sk); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci return err; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic int hash_sendmsg_nokey(struct socket *sock, struct msghdr *msg, 33462306a36Sopenharmony_ci size_t size) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci int err; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci err = hash_check_key(sock); 33962306a36Sopenharmony_ci if (err) 34062306a36Sopenharmony_ci return err; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci return hash_sendmsg(sock, msg, size); 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic int hash_recvmsg_nokey(struct socket *sock, struct msghdr *msg, 34662306a36Sopenharmony_ci size_t ignored, int flags) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci int err; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci err = hash_check_key(sock); 35162306a36Sopenharmony_ci if (err) 35262306a36Sopenharmony_ci return err; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci return hash_recvmsg(sock, msg, ignored, flags); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic int hash_accept_nokey(struct socket *sock, struct socket *newsock, 35862306a36Sopenharmony_ci int flags, bool kern) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci int err; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci err = hash_check_key(sock); 36362306a36Sopenharmony_ci if (err) 36462306a36Sopenharmony_ci return err; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci return hash_accept(sock, newsock, flags, kern); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic struct proto_ops algif_hash_ops_nokey = { 37062306a36Sopenharmony_ci .family = PF_ALG, 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci .connect = sock_no_connect, 37362306a36Sopenharmony_ci .socketpair = sock_no_socketpair, 37462306a36Sopenharmony_ci .getname = sock_no_getname, 37562306a36Sopenharmony_ci .ioctl = sock_no_ioctl, 37662306a36Sopenharmony_ci .listen = sock_no_listen, 37762306a36Sopenharmony_ci .shutdown = sock_no_shutdown, 37862306a36Sopenharmony_ci .mmap = sock_no_mmap, 37962306a36Sopenharmony_ci .bind = sock_no_bind, 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci .release = af_alg_release, 38262306a36Sopenharmony_ci .sendmsg = hash_sendmsg_nokey, 38362306a36Sopenharmony_ci .recvmsg = hash_recvmsg_nokey, 38462306a36Sopenharmony_ci .accept = hash_accept_nokey, 38562306a36Sopenharmony_ci}; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic void *hash_bind(const char *name, u32 type, u32 mask) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci return crypto_alloc_ahash(name, type, mask); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic void hash_release(void *private) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci crypto_free_ahash(private); 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic int hash_setkey(void *private, const u8 *key, unsigned int keylen) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci return crypto_ahash_setkey(private, key, keylen); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic void hash_sock_destruct(struct sock *sk) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci struct alg_sock *ask = alg_sk(sk); 40562306a36Sopenharmony_ci struct hash_ctx *ctx = ask->private; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci hash_free_result(sk, ctx); 40862306a36Sopenharmony_ci sock_kfree_s(sk, ctx, ctx->len); 40962306a36Sopenharmony_ci af_alg_release_parent(sk); 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic int hash_accept_parent_nokey(void *private, struct sock *sk) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct crypto_ahash *tfm = private; 41562306a36Sopenharmony_ci struct alg_sock *ask = alg_sk(sk); 41662306a36Sopenharmony_ci struct hash_ctx *ctx; 41762306a36Sopenharmony_ci unsigned int len = sizeof(*ctx) + crypto_ahash_reqsize(tfm); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci ctx = sock_kmalloc(sk, len, GFP_KERNEL); 42062306a36Sopenharmony_ci if (!ctx) 42162306a36Sopenharmony_ci return -ENOMEM; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci ctx->result = NULL; 42462306a36Sopenharmony_ci ctx->len = len; 42562306a36Sopenharmony_ci ctx->more = false; 42662306a36Sopenharmony_ci crypto_init_wait(&ctx->wait); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci ask->private = ctx; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci ahash_request_set_tfm(&ctx->req, tfm); 43162306a36Sopenharmony_ci ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG, 43262306a36Sopenharmony_ci crypto_req_done, &ctx->wait); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci sk->sk_destruct = hash_sock_destruct; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return 0; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int hash_accept_parent(void *private, struct sock *sk) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci struct crypto_ahash *tfm = private; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) 44462306a36Sopenharmony_ci return -ENOKEY; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci return hash_accept_parent_nokey(private, sk); 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic const struct af_alg_type algif_type_hash = { 45062306a36Sopenharmony_ci .bind = hash_bind, 45162306a36Sopenharmony_ci .release = hash_release, 45262306a36Sopenharmony_ci .setkey = hash_setkey, 45362306a36Sopenharmony_ci .accept = hash_accept_parent, 45462306a36Sopenharmony_ci .accept_nokey = hash_accept_parent_nokey, 45562306a36Sopenharmony_ci .ops = &algif_hash_ops, 45662306a36Sopenharmony_ci .ops_nokey = &algif_hash_ops_nokey, 45762306a36Sopenharmony_ci .name = "hash", 45862306a36Sopenharmony_ci .owner = THIS_MODULE 45962306a36Sopenharmony_ci}; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic int __init algif_hash_init(void) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci return af_alg_register_type(&algif_type_hash); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic void __exit algif_hash_exit(void) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci int err = af_alg_unregister_type(&algif_type_hash); 46962306a36Sopenharmony_ci BUG_ON(err); 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cimodule_init(algif_hash_init); 47362306a36Sopenharmony_cimodule_exit(algif_hash_exit); 47462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 475