18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/** 38c2ecf20Sopenharmony_ci * net/tipc/crypto.c: TIPC crypto for key handling & packet en/decryption 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2019, Ericsson AB 68c2ecf20Sopenharmony_ci * All rights reserved. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 98c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 128c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 148c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 158c2ecf20Sopenharmony_ci * documentation and/or other materials provided with the distribution. 168c2ecf20Sopenharmony_ci * 3. Neither the names of the copyright holders nor the names of its 178c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived from 188c2ecf20Sopenharmony_ci * this software without specific prior written permission. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 218c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free 228c2ecf20Sopenharmony_ci * Software Foundation. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 258c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 268c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 278c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 288c2ecf20Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 298c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 308c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 318c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 328c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 338c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 348c2ecf20Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <crypto/aead.h> 388c2ecf20Sopenharmony_ci#include <crypto/aes.h> 398c2ecf20Sopenharmony_ci#include <crypto/rng.h> 408c2ecf20Sopenharmony_ci#include "crypto.h" 418c2ecf20Sopenharmony_ci#include "msg.h" 428c2ecf20Sopenharmony_ci#include "bcast.h" 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define TIPC_TX_GRACE_PERIOD msecs_to_jiffies(5000) /* 5s */ 458c2ecf20Sopenharmony_ci#define TIPC_TX_LASTING_TIME msecs_to_jiffies(10000) /* 10s */ 468c2ecf20Sopenharmony_ci#define TIPC_RX_ACTIVE_LIM msecs_to_jiffies(3000) /* 3s */ 478c2ecf20Sopenharmony_ci#define TIPC_RX_PASSIVE_LIM msecs_to_jiffies(15000) /* 15s */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define TIPC_MAX_TFMS_DEF 10 508c2ecf20Sopenharmony_ci#define TIPC_MAX_TFMS_LIM 1000 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define TIPC_REKEYING_INTV_DEF (60 * 24) /* default: 1 day */ 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/** 558c2ecf20Sopenharmony_ci * TIPC Key ids 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_cienum { 588c2ecf20Sopenharmony_ci KEY_MASTER = 0, 598c2ecf20Sopenharmony_ci KEY_MIN = KEY_MASTER, 608c2ecf20Sopenharmony_ci KEY_1 = 1, 618c2ecf20Sopenharmony_ci KEY_2, 628c2ecf20Sopenharmony_ci KEY_3, 638c2ecf20Sopenharmony_ci KEY_MAX = KEY_3, 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/** 678c2ecf20Sopenharmony_ci * TIPC Crypto statistics 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_cienum { 708c2ecf20Sopenharmony_ci STAT_OK, 718c2ecf20Sopenharmony_ci STAT_NOK, 728c2ecf20Sopenharmony_ci STAT_ASYNC, 738c2ecf20Sopenharmony_ci STAT_ASYNC_OK, 748c2ecf20Sopenharmony_ci STAT_ASYNC_NOK, 758c2ecf20Sopenharmony_ci STAT_BADKEYS, /* tx only */ 768c2ecf20Sopenharmony_ci STAT_BADMSGS = STAT_BADKEYS, /* rx only */ 778c2ecf20Sopenharmony_ci STAT_NOKEYS, 788c2ecf20Sopenharmony_ci STAT_SWITCHES, 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci MAX_STATS, 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* TIPC crypto statistics' header */ 848c2ecf20Sopenharmony_cistatic const char *hstats[MAX_STATS] = {"ok", "nok", "async", "async_ok", 858c2ecf20Sopenharmony_ci "async_nok", "badmsgs", "nokeys", 868c2ecf20Sopenharmony_ci "switches"}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* Max TFMs number per key */ 898c2ecf20Sopenharmony_ciint sysctl_tipc_max_tfms __read_mostly = TIPC_MAX_TFMS_DEF; 908c2ecf20Sopenharmony_ci/* Key exchange switch, default: on */ 918c2ecf20Sopenharmony_ciint sysctl_tipc_key_exchange_enabled __read_mostly = 1; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/** 948c2ecf20Sopenharmony_ci * struct tipc_key - TIPC keys' status indicator 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * 7 6 5 4 3 2 1 0 978c2ecf20Sopenharmony_ci * +-----+-----+-----+-----+-----+-----+-----+-----+ 988c2ecf20Sopenharmony_ci * key: | (reserved)|passive idx| active idx|pending idx| 998c2ecf20Sopenharmony_ci * +-----+-----+-----+-----+-----+-----+-----+-----+ 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_cistruct tipc_key { 1028c2ecf20Sopenharmony_ci#define KEY_BITS (2) 1038c2ecf20Sopenharmony_ci#define KEY_MASK ((1 << KEY_BITS) - 1) 1048c2ecf20Sopenharmony_ci union { 1058c2ecf20Sopenharmony_ci struct { 1068c2ecf20Sopenharmony_ci#if defined(__LITTLE_ENDIAN_BITFIELD) 1078c2ecf20Sopenharmony_ci u8 pending:2, 1088c2ecf20Sopenharmony_ci active:2, 1098c2ecf20Sopenharmony_ci passive:2, /* rx only */ 1108c2ecf20Sopenharmony_ci reserved:2; 1118c2ecf20Sopenharmony_ci#elif defined(__BIG_ENDIAN_BITFIELD) 1128c2ecf20Sopenharmony_ci u8 reserved:2, 1138c2ecf20Sopenharmony_ci passive:2, /* rx only */ 1148c2ecf20Sopenharmony_ci active:2, 1158c2ecf20Sopenharmony_ci pending:2; 1168c2ecf20Sopenharmony_ci#else 1178c2ecf20Sopenharmony_ci#error "Please fix <asm/byteorder.h>" 1188c2ecf20Sopenharmony_ci#endif 1198c2ecf20Sopenharmony_ci } __packed; 1208c2ecf20Sopenharmony_ci u8 keys; 1218c2ecf20Sopenharmony_ci }; 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/** 1258c2ecf20Sopenharmony_ci * struct tipc_tfm - TIPC TFM structure to form a list of TFMs 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_cistruct tipc_tfm { 1288c2ecf20Sopenharmony_ci struct crypto_aead *tfm; 1298c2ecf20Sopenharmony_ci struct list_head list; 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/** 1338c2ecf20Sopenharmony_ci * struct tipc_aead - TIPC AEAD key structure 1348c2ecf20Sopenharmony_ci * @tfm_entry: per-cpu pointer to one entry in TFM list 1358c2ecf20Sopenharmony_ci * @crypto: TIPC crypto owns this key 1368c2ecf20Sopenharmony_ci * @cloned: reference to the source key in case cloning 1378c2ecf20Sopenharmony_ci * @users: the number of the key users (TX/RX) 1388c2ecf20Sopenharmony_ci * @salt: the key's SALT value 1398c2ecf20Sopenharmony_ci * @authsize: authentication tag size (max = 16) 1408c2ecf20Sopenharmony_ci * @mode: crypto mode is applied to the key 1418c2ecf20Sopenharmony_ci * @hint[]: a hint for user key 1428c2ecf20Sopenharmony_ci * @rcu: struct rcu_head 1438c2ecf20Sopenharmony_ci * @key: the aead key 1448c2ecf20Sopenharmony_ci * @gen: the key's generation 1458c2ecf20Sopenharmony_ci * @seqno: the key seqno (cluster scope) 1468c2ecf20Sopenharmony_ci * @refcnt: the key reference counter 1478c2ecf20Sopenharmony_ci */ 1488c2ecf20Sopenharmony_cistruct tipc_aead { 1498c2ecf20Sopenharmony_ci#define TIPC_AEAD_HINT_LEN (5) 1508c2ecf20Sopenharmony_ci struct tipc_tfm * __percpu *tfm_entry; 1518c2ecf20Sopenharmony_ci struct tipc_crypto *crypto; 1528c2ecf20Sopenharmony_ci struct tipc_aead *cloned; 1538c2ecf20Sopenharmony_ci atomic_t users; 1548c2ecf20Sopenharmony_ci u32 salt; 1558c2ecf20Sopenharmony_ci u8 authsize; 1568c2ecf20Sopenharmony_ci u8 mode; 1578c2ecf20Sopenharmony_ci char hint[2 * TIPC_AEAD_HINT_LEN + 1]; 1588c2ecf20Sopenharmony_ci struct rcu_head rcu; 1598c2ecf20Sopenharmony_ci struct tipc_aead_key *key; 1608c2ecf20Sopenharmony_ci u16 gen; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci atomic64_t seqno ____cacheline_aligned; 1638c2ecf20Sopenharmony_ci refcount_t refcnt ____cacheline_aligned; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci} ____cacheline_aligned; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/** 1688c2ecf20Sopenharmony_ci * struct tipc_crypto_stats - TIPC Crypto statistics 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_cistruct tipc_crypto_stats { 1718c2ecf20Sopenharmony_ci unsigned int stat[MAX_STATS]; 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci/** 1758c2ecf20Sopenharmony_ci * struct tipc_crypto - TIPC TX/RX crypto structure 1768c2ecf20Sopenharmony_ci * @net: struct net 1778c2ecf20Sopenharmony_ci * @node: TIPC node (RX) 1788c2ecf20Sopenharmony_ci * @aead: array of pointers to AEAD keys for encryption/decryption 1798c2ecf20Sopenharmony_ci * @peer_rx_active: replicated peer RX active key index 1808c2ecf20Sopenharmony_ci * @key_gen: TX/RX key generation 1818c2ecf20Sopenharmony_ci * @key: the key states 1828c2ecf20Sopenharmony_ci * @skey_mode: session key's mode 1838c2ecf20Sopenharmony_ci * @skey: received session key 1848c2ecf20Sopenharmony_ci * @wq: common workqueue on TX crypto 1858c2ecf20Sopenharmony_ci * @work: delayed work sched for TX/RX 1868c2ecf20Sopenharmony_ci * @key_distr: key distributing state 1878c2ecf20Sopenharmony_ci * @rekeying_intv: rekeying interval (in minutes) 1888c2ecf20Sopenharmony_ci * @stats: the crypto statistics 1898c2ecf20Sopenharmony_ci * @name: the crypto name 1908c2ecf20Sopenharmony_ci * @sndnxt: the per-peer sndnxt (TX) 1918c2ecf20Sopenharmony_ci * @timer1: general timer 1 (jiffies) 1928c2ecf20Sopenharmony_ci * @timer2: general timer 2 (jiffies) 1938c2ecf20Sopenharmony_ci * @working: the crypto is working or not 1948c2ecf20Sopenharmony_ci * @key_master: flag indicates if master key exists 1958c2ecf20Sopenharmony_ci * @legacy_user: flag indicates if a peer joins w/o master key (for bwd comp.) 1968c2ecf20Sopenharmony_ci * @nokey: no key indication 1978c2ecf20Sopenharmony_ci * @lock: tipc_key lock 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_cistruct tipc_crypto { 2008c2ecf20Sopenharmony_ci struct net *net; 2018c2ecf20Sopenharmony_ci struct tipc_node *node; 2028c2ecf20Sopenharmony_ci struct tipc_aead __rcu *aead[KEY_MAX + 1]; 2038c2ecf20Sopenharmony_ci atomic_t peer_rx_active; 2048c2ecf20Sopenharmony_ci u16 key_gen; 2058c2ecf20Sopenharmony_ci struct tipc_key key; 2068c2ecf20Sopenharmony_ci u8 skey_mode; 2078c2ecf20Sopenharmony_ci struct tipc_aead_key *skey; 2088c2ecf20Sopenharmony_ci struct workqueue_struct *wq; 2098c2ecf20Sopenharmony_ci struct delayed_work work; 2108c2ecf20Sopenharmony_ci#define KEY_DISTR_SCHED 1 2118c2ecf20Sopenharmony_ci#define KEY_DISTR_COMPL 2 2128c2ecf20Sopenharmony_ci atomic_t key_distr; 2138c2ecf20Sopenharmony_ci u32 rekeying_intv; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci struct tipc_crypto_stats __percpu *stats; 2168c2ecf20Sopenharmony_ci char name[48]; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci atomic64_t sndnxt ____cacheline_aligned; 2198c2ecf20Sopenharmony_ci unsigned long timer1; 2208c2ecf20Sopenharmony_ci unsigned long timer2; 2218c2ecf20Sopenharmony_ci union { 2228c2ecf20Sopenharmony_ci struct { 2238c2ecf20Sopenharmony_ci u8 working:1; 2248c2ecf20Sopenharmony_ci u8 key_master:1; 2258c2ecf20Sopenharmony_ci u8 legacy_user:1; 2268c2ecf20Sopenharmony_ci u8 nokey: 1; 2278c2ecf20Sopenharmony_ci }; 2288c2ecf20Sopenharmony_ci u8 flags; 2298c2ecf20Sopenharmony_ci }; 2308c2ecf20Sopenharmony_ci spinlock_t lock; /* crypto lock */ 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci} ____cacheline_aligned; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/* struct tipc_crypto_tx_ctx - TX context for callbacks */ 2358c2ecf20Sopenharmony_cistruct tipc_crypto_tx_ctx { 2368c2ecf20Sopenharmony_ci struct tipc_aead *aead; 2378c2ecf20Sopenharmony_ci struct tipc_bearer *bearer; 2388c2ecf20Sopenharmony_ci struct tipc_media_addr dst; 2398c2ecf20Sopenharmony_ci}; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/* struct tipc_crypto_rx_ctx - RX context for callbacks */ 2428c2ecf20Sopenharmony_cistruct tipc_crypto_rx_ctx { 2438c2ecf20Sopenharmony_ci struct tipc_aead *aead; 2448c2ecf20Sopenharmony_ci struct tipc_bearer *bearer; 2458c2ecf20Sopenharmony_ci}; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic struct tipc_aead *tipc_aead_get(struct tipc_aead __rcu *aead); 2488c2ecf20Sopenharmony_cistatic inline void tipc_aead_put(struct tipc_aead *aead); 2498c2ecf20Sopenharmony_cistatic void tipc_aead_free(struct rcu_head *rp); 2508c2ecf20Sopenharmony_cistatic int tipc_aead_users(struct tipc_aead __rcu *aead); 2518c2ecf20Sopenharmony_cistatic void tipc_aead_users_inc(struct tipc_aead __rcu *aead, int lim); 2528c2ecf20Sopenharmony_cistatic void tipc_aead_users_dec(struct tipc_aead __rcu *aead, int lim); 2538c2ecf20Sopenharmony_cistatic void tipc_aead_users_set(struct tipc_aead __rcu *aead, int val); 2548c2ecf20Sopenharmony_cistatic struct crypto_aead *tipc_aead_tfm_next(struct tipc_aead *aead); 2558c2ecf20Sopenharmony_cistatic int tipc_aead_init(struct tipc_aead **aead, struct tipc_aead_key *ukey, 2568c2ecf20Sopenharmony_ci u8 mode); 2578c2ecf20Sopenharmony_cistatic int tipc_aead_clone(struct tipc_aead **dst, struct tipc_aead *src); 2588c2ecf20Sopenharmony_cistatic void *tipc_aead_mem_alloc(struct crypto_aead *tfm, 2598c2ecf20Sopenharmony_ci unsigned int crypto_ctx_size, 2608c2ecf20Sopenharmony_ci u8 **iv, struct aead_request **req, 2618c2ecf20Sopenharmony_ci struct scatterlist **sg, int nsg); 2628c2ecf20Sopenharmony_cistatic int tipc_aead_encrypt(struct tipc_aead *aead, struct sk_buff *skb, 2638c2ecf20Sopenharmony_ci struct tipc_bearer *b, 2648c2ecf20Sopenharmony_ci struct tipc_media_addr *dst, 2658c2ecf20Sopenharmony_ci struct tipc_node *__dnode); 2668c2ecf20Sopenharmony_cistatic void tipc_aead_encrypt_done(struct crypto_async_request *base, int err); 2678c2ecf20Sopenharmony_cistatic int tipc_aead_decrypt(struct net *net, struct tipc_aead *aead, 2688c2ecf20Sopenharmony_ci struct sk_buff *skb, struct tipc_bearer *b); 2698c2ecf20Sopenharmony_cistatic void tipc_aead_decrypt_done(struct crypto_async_request *base, int err); 2708c2ecf20Sopenharmony_cistatic inline int tipc_ehdr_size(struct tipc_ehdr *ehdr); 2718c2ecf20Sopenharmony_cistatic int tipc_ehdr_build(struct net *net, struct tipc_aead *aead, 2728c2ecf20Sopenharmony_ci u8 tx_key, struct sk_buff *skb, 2738c2ecf20Sopenharmony_ci struct tipc_crypto *__rx); 2748c2ecf20Sopenharmony_cistatic inline void tipc_crypto_key_set_state(struct tipc_crypto *c, 2758c2ecf20Sopenharmony_ci u8 new_passive, 2768c2ecf20Sopenharmony_ci u8 new_active, 2778c2ecf20Sopenharmony_ci u8 new_pending); 2788c2ecf20Sopenharmony_cistatic int tipc_crypto_key_attach(struct tipc_crypto *c, 2798c2ecf20Sopenharmony_ci struct tipc_aead *aead, u8 pos, 2808c2ecf20Sopenharmony_ci bool master_key); 2818c2ecf20Sopenharmony_cistatic bool tipc_crypto_key_try_align(struct tipc_crypto *rx, u8 new_pending); 2828c2ecf20Sopenharmony_cistatic struct tipc_aead *tipc_crypto_key_pick_tx(struct tipc_crypto *tx, 2838c2ecf20Sopenharmony_ci struct tipc_crypto *rx, 2848c2ecf20Sopenharmony_ci struct sk_buff *skb, 2858c2ecf20Sopenharmony_ci u8 tx_key); 2868c2ecf20Sopenharmony_cistatic void tipc_crypto_key_synch(struct tipc_crypto *rx, struct sk_buff *skb); 2878c2ecf20Sopenharmony_cistatic int tipc_crypto_key_revoke(struct net *net, u8 tx_key); 2888c2ecf20Sopenharmony_cistatic inline void tipc_crypto_clone_msg(struct net *net, struct sk_buff *_skb, 2898c2ecf20Sopenharmony_ci struct tipc_bearer *b, 2908c2ecf20Sopenharmony_ci struct tipc_media_addr *dst, 2918c2ecf20Sopenharmony_ci struct tipc_node *__dnode, u8 type); 2928c2ecf20Sopenharmony_cistatic void tipc_crypto_rcv_complete(struct net *net, struct tipc_aead *aead, 2938c2ecf20Sopenharmony_ci struct tipc_bearer *b, 2948c2ecf20Sopenharmony_ci struct sk_buff **skb, int err); 2958c2ecf20Sopenharmony_cistatic void tipc_crypto_do_cmd(struct net *net, int cmd); 2968c2ecf20Sopenharmony_cistatic char *tipc_crypto_key_dump(struct tipc_crypto *c, char *buf); 2978c2ecf20Sopenharmony_cistatic char *tipc_key_change_dump(struct tipc_key old, struct tipc_key new, 2988c2ecf20Sopenharmony_ci char *buf); 2998c2ecf20Sopenharmony_cistatic int tipc_crypto_key_xmit(struct net *net, struct tipc_aead_key *skey, 3008c2ecf20Sopenharmony_ci u16 gen, u8 mode, u32 dnode); 3018c2ecf20Sopenharmony_cistatic bool tipc_crypto_key_rcv(struct tipc_crypto *rx, struct tipc_msg *hdr); 3028c2ecf20Sopenharmony_cistatic void tipc_crypto_work_tx(struct work_struct *work); 3038c2ecf20Sopenharmony_cistatic void tipc_crypto_work_rx(struct work_struct *work); 3048c2ecf20Sopenharmony_cistatic int tipc_aead_key_generate(struct tipc_aead_key *skey); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci#define is_tx(crypto) (!(crypto)->node) 3078c2ecf20Sopenharmony_ci#define is_rx(crypto) (!is_tx(crypto)) 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci#define key_next(cur) ((cur) % KEY_MAX + 1) 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci#define tipc_aead_rcu_ptr(rcu_ptr, lock) \ 3128c2ecf20Sopenharmony_ci rcu_dereference_protected((rcu_ptr), lockdep_is_held(lock)) 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci#define tipc_aead_rcu_replace(rcu_ptr, ptr, lock) \ 3158c2ecf20Sopenharmony_cido { \ 3168c2ecf20Sopenharmony_ci typeof(rcu_ptr) __tmp = rcu_dereference_protected((rcu_ptr), \ 3178c2ecf20Sopenharmony_ci lockdep_is_held(lock)); \ 3188c2ecf20Sopenharmony_ci rcu_assign_pointer((rcu_ptr), (ptr)); \ 3198c2ecf20Sopenharmony_ci tipc_aead_put(__tmp); \ 3208c2ecf20Sopenharmony_ci} while (0) 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci#define tipc_crypto_key_detach(rcu_ptr, lock) \ 3238c2ecf20Sopenharmony_ci tipc_aead_rcu_replace((rcu_ptr), NULL, lock) 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci/** 3268c2ecf20Sopenharmony_ci * tipc_aead_key_validate - Validate a AEAD user key 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ciint tipc_aead_key_validate(struct tipc_aead_key *ukey, struct genl_info *info) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci int keylen; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Check if algorithm exists */ 3338c2ecf20Sopenharmony_ci if (unlikely(!crypto_has_alg(ukey->alg_name, 0, 0))) { 3348c2ecf20Sopenharmony_ci GENL_SET_ERR_MSG(info, "unable to load the algorithm (module existed?)"); 3358c2ecf20Sopenharmony_ci return -ENODEV; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* Currently, we only support the "gcm(aes)" cipher algorithm */ 3398c2ecf20Sopenharmony_ci if (strcmp(ukey->alg_name, "gcm(aes)")) { 3408c2ecf20Sopenharmony_ci GENL_SET_ERR_MSG(info, "not supported yet the algorithm"); 3418c2ecf20Sopenharmony_ci return -ENOTSUPP; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* Check if key size is correct */ 3458c2ecf20Sopenharmony_ci keylen = ukey->keylen - TIPC_AES_GCM_SALT_SIZE; 3468c2ecf20Sopenharmony_ci if (unlikely(keylen != TIPC_AES_GCM_KEY_SIZE_128 && 3478c2ecf20Sopenharmony_ci keylen != TIPC_AES_GCM_KEY_SIZE_192 && 3488c2ecf20Sopenharmony_ci keylen != TIPC_AES_GCM_KEY_SIZE_256)) { 3498c2ecf20Sopenharmony_ci GENL_SET_ERR_MSG(info, "incorrect key length (20, 28 or 36 octets?)"); 3508c2ecf20Sopenharmony_ci return -EKEYREJECTED; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return 0; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci/** 3578c2ecf20Sopenharmony_ci * tipc_aead_key_generate - Generate new session key 3588c2ecf20Sopenharmony_ci * @skey: input/output key with new content 3598c2ecf20Sopenharmony_ci * 3608c2ecf20Sopenharmony_ci * Return: 0 in case of success, otherwise < 0 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_cistatic int tipc_aead_key_generate(struct tipc_aead_key *skey) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci int rc = 0; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* Fill the key's content with a random value via RNG cipher */ 3678c2ecf20Sopenharmony_ci rc = crypto_get_default_rng(); 3688c2ecf20Sopenharmony_ci if (likely(!rc)) { 3698c2ecf20Sopenharmony_ci rc = crypto_rng_get_bytes(crypto_default_rng, skey->key, 3708c2ecf20Sopenharmony_ci skey->keylen); 3718c2ecf20Sopenharmony_ci crypto_put_default_rng(); 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci return rc; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic struct tipc_aead *tipc_aead_get(struct tipc_aead __rcu *aead) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct tipc_aead *tmp; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci rcu_read_lock(); 3828c2ecf20Sopenharmony_ci tmp = rcu_dereference(aead); 3838c2ecf20Sopenharmony_ci if (unlikely(!tmp || !refcount_inc_not_zero(&tmp->refcnt))) 3848c2ecf20Sopenharmony_ci tmp = NULL; 3858c2ecf20Sopenharmony_ci rcu_read_unlock(); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci return tmp; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic inline void tipc_aead_put(struct tipc_aead *aead) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci if (aead && refcount_dec_and_test(&aead->refcnt)) 3938c2ecf20Sopenharmony_ci call_rcu(&aead->rcu, tipc_aead_free); 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci/** 3978c2ecf20Sopenharmony_ci * tipc_aead_free - Release AEAD key incl. all the TFMs in the list 3988c2ecf20Sopenharmony_ci * @rp: rcu head pointer 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_cistatic void tipc_aead_free(struct rcu_head *rp) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct tipc_aead *aead = container_of(rp, struct tipc_aead, rcu); 4038c2ecf20Sopenharmony_ci struct tipc_tfm *tfm_entry, *head, *tmp; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (aead->cloned) { 4068c2ecf20Sopenharmony_ci tipc_aead_put(aead->cloned); 4078c2ecf20Sopenharmony_ci } else { 4088c2ecf20Sopenharmony_ci head = *get_cpu_ptr(aead->tfm_entry); 4098c2ecf20Sopenharmony_ci put_cpu_ptr(aead->tfm_entry); 4108c2ecf20Sopenharmony_ci list_for_each_entry_safe(tfm_entry, tmp, &head->list, list) { 4118c2ecf20Sopenharmony_ci crypto_free_aead(tfm_entry->tfm); 4128c2ecf20Sopenharmony_ci list_del(&tfm_entry->list); 4138c2ecf20Sopenharmony_ci kfree(tfm_entry); 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci /* Free the head */ 4168c2ecf20Sopenharmony_ci crypto_free_aead(head->tfm); 4178c2ecf20Sopenharmony_ci list_del(&head->list); 4188c2ecf20Sopenharmony_ci kfree(head); 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci free_percpu(aead->tfm_entry); 4218c2ecf20Sopenharmony_ci kfree_sensitive(aead->key); 4228c2ecf20Sopenharmony_ci kfree(aead); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int tipc_aead_users(struct tipc_aead __rcu *aead) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct tipc_aead *tmp; 4288c2ecf20Sopenharmony_ci int users = 0; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci rcu_read_lock(); 4318c2ecf20Sopenharmony_ci tmp = rcu_dereference(aead); 4328c2ecf20Sopenharmony_ci if (tmp) 4338c2ecf20Sopenharmony_ci users = atomic_read(&tmp->users); 4348c2ecf20Sopenharmony_ci rcu_read_unlock(); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return users; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic void tipc_aead_users_inc(struct tipc_aead __rcu *aead, int lim) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct tipc_aead *tmp; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci rcu_read_lock(); 4448c2ecf20Sopenharmony_ci tmp = rcu_dereference(aead); 4458c2ecf20Sopenharmony_ci if (tmp) 4468c2ecf20Sopenharmony_ci atomic_add_unless(&tmp->users, 1, lim); 4478c2ecf20Sopenharmony_ci rcu_read_unlock(); 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic void tipc_aead_users_dec(struct tipc_aead __rcu *aead, int lim) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct tipc_aead *tmp; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci rcu_read_lock(); 4558c2ecf20Sopenharmony_ci tmp = rcu_dereference(aead); 4568c2ecf20Sopenharmony_ci if (tmp) 4578c2ecf20Sopenharmony_ci atomic_add_unless(&rcu_dereference(aead)->users, -1, lim); 4588c2ecf20Sopenharmony_ci rcu_read_unlock(); 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic void tipc_aead_users_set(struct tipc_aead __rcu *aead, int val) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct tipc_aead *tmp; 4648c2ecf20Sopenharmony_ci int cur; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci rcu_read_lock(); 4678c2ecf20Sopenharmony_ci tmp = rcu_dereference(aead); 4688c2ecf20Sopenharmony_ci if (tmp) { 4698c2ecf20Sopenharmony_ci do { 4708c2ecf20Sopenharmony_ci cur = atomic_read(&tmp->users); 4718c2ecf20Sopenharmony_ci if (cur == val) 4728c2ecf20Sopenharmony_ci break; 4738c2ecf20Sopenharmony_ci } while (atomic_cmpxchg(&tmp->users, cur, val) != cur); 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci rcu_read_unlock(); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci/** 4798c2ecf20Sopenharmony_ci * tipc_aead_tfm_next - Move TFM entry to the next one in list and return it 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_cistatic struct crypto_aead *tipc_aead_tfm_next(struct tipc_aead *aead) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci struct tipc_tfm **tfm_entry; 4848c2ecf20Sopenharmony_ci struct crypto_aead *tfm; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci tfm_entry = get_cpu_ptr(aead->tfm_entry); 4878c2ecf20Sopenharmony_ci *tfm_entry = list_next_entry(*tfm_entry, list); 4888c2ecf20Sopenharmony_ci tfm = (*tfm_entry)->tfm; 4898c2ecf20Sopenharmony_ci put_cpu_ptr(tfm_entry); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return tfm; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci/** 4958c2ecf20Sopenharmony_ci * tipc_aead_init - Initiate TIPC AEAD 4968c2ecf20Sopenharmony_ci * @aead: returned new TIPC AEAD key handle pointer 4978c2ecf20Sopenharmony_ci * @ukey: pointer to user key data 4988c2ecf20Sopenharmony_ci * @mode: the key mode 4998c2ecf20Sopenharmony_ci * 5008c2ecf20Sopenharmony_ci * Allocate a (list of) new cipher transformation (TFM) with the specific user 5018c2ecf20Sopenharmony_ci * key data if valid. The number of the allocated TFMs can be set via the sysfs 5028c2ecf20Sopenharmony_ci * "net/tipc/max_tfms" first. 5038c2ecf20Sopenharmony_ci * Also, all the other AEAD data are also initialized. 5048c2ecf20Sopenharmony_ci * 5058c2ecf20Sopenharmony_ci * Return: 0 if the initiation is successful, otherwise: < 0 5068c2ecf20Sopenharmony_ci */ 5078c2ecf20Sopenharmony_cistatic int tipc_aead_init(struct tipc_aead **aead, struct tipc_aead_key *ukey, 5088c2ecf20Sopenharmony_ci u8 mode) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci struct tipc_tfm *tfm_entry, *head; 5118c2ecf20Sopenharmony_ci struct crypto_aead *tfm; 5128c2ecf20Sopenharmony_ci struct tipc_aead *tmp; 5138c2ecf20Sopenharmony_ci int keylen, err, cpu; 5148c2ecf20Sopenharmony_ci int tfm_cnt = 0; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (unlikely(*aead)) 5178c2ecf20Sopenharmony_ci return -EEXIST; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci /* Allocate a new AEAD */ 5208c2ecf20Sopenharmony_ci tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC); 5218c2ecf20Sopenharmony_ci if (unlikely(!tmp)) 5228c2ecf20Sopenharmony_ci return -ENOMEM; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci /* The key consists of two parts: [AES-KEY][SALT] */ 5258c2ecf20Sopenharmony_ci keylen = ukey->keylen - TIPC_AES_GCM_SALT_SIZE; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* Allocate per-cpu TFM entry pointer */ 5288c2ecf20Sopenharmony_ci tmp->tfm_entry = alloc_percpu(struct tipc_tfm *); 5298c2ecf20Sopenharmony_ci if (!tmp->tfm_entry) { 5308c2ecf20Sopenharmony_ci kfree_sensitive(tmp); 5318c2ecf20Sopenharmony_ci return -ENOMEM; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* Make a list of TFMs with the user key data */ 5358c2ecf20Sopenharmony_ci do { 5368c2ecf20Sopenharmony_ci tfm = crypto_alloc_aead(ukey->alg_name, 0, 0); 5378c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) { 5388c2ecf20Sopenharmony_ci err = PTR_ERR(tfm); 5398c2ecf20Sopenharmony_ci break; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (unlikely(!tfm_cnt && 5438c2ecf20Sopenharmony_ci crypto_aead_ivsize(tfm) != TIPC_AES_GCM_IV_SIZE)) { 5448c2ecf20Sopenharmony_ci crypto_free_aead(tfm); 5458c2ecf20Sopenharmony_ci err = -ENOTSUPP; 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci err = crypto_aead_setauthsize(tfm, TIPC_AES_GCM_TAG_SIZE); 5508c2ecf20Sopenharmony_ci err |= crypto_aead_setkey(tfm, ukey->key, keylen); 5518c2ecf20Sopenharmony_ci if (unlikely(err)) { 5528c2ecf20Sopenharmony_ci crypto_free_aead(tfm); 5538c2ecf20Sopenharmony_ci break; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci tfm_entry = kmalloc(sizeof(*tfm_entry), GFP_KERNEL); 5578c2ecf20Sopenharmony_ci if (unlikely(!tfm_entry)) { 5588c2ecf20Sopenharmony_ci crypto_free_aead(tfm); 5598c2ecf20Sopenharmony_ci err = -ENOMEM; 5608c2ecf20Sopenharmony_ci break; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tfm_entry->list); 5638c2ecf20Sopenharmony_ci tfm_entry->tfm = tfm; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* First entry? */ 5668c2ecf20Sopenharmony_ci if (!tfm_cnt) { 5678c2ecf20Sopenharmony_ci head = tfm_entry; 5688c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 5698c2ecf20Sopenharmony_ci *per_cpu_ptr(tmp->tfm_entry, cpu) = head; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci } else { 5728c2ecf20Sopenharmony_ci list_add_tail(&tfm_entry->list, &head->list); 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci } while (++tfm_cnt < sysctl_tipc_max_tfms); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci /* Not any TFM is allocated? */ 5788c2ecf20Sopenharmony_ci if (!tfm_cnt) { 5798c2ecf20Sopenharmony_ci free_percpu(tmp->tfm_entry); 5808c2ecf20Sopenharmony_ci kfree_sensitive(tmp); 5818c2ecf20Sopenharmony_ci return err; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci /* Form a hex string of some last bytes as the key's hint */ 5858c2ecf20Sopenharmony_ci bin2hex(tmp->hint, ukey->key + keylen - TIPC_AEAD_HINT_LEN, 5868c2ecf20Sopenharmony_ci TIPC_AEAD_HINT_LEN); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* Initialize the other data */ 5898c2ecf20Sopenharmony_ci tmp->mode = mode; 5908c2ecf20Sopenharmony_ci tmp->cloned = NULL; 5918c2ecf20Sopenharmony_ci tmp->authsize = TIPC_AES_GCM_TAG_SIZE; 5928c2ecf20Sopenharmony_ci tmp->key = kmemdup(ukey, tipc_aead_key_size(ukey), GFP_KERNEL); 5938c2ecf20Sopenharmony_ci if (!tmp->key) { 5948c2ecf20Sopenharmony_ci tipc_aead_free(&tmp->rcu); 5958c2ecf20Sopenharmony_ci return -ENOMEM; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci memcpy(&tmp->salt, ukey->key + keylen, TIPC_AES_GCM_SALT_SIZE); 5988c2ecf20Sopenharmony_ci atomic_set(&tmp->users, 0); 5998c2ecf20Sopenharmony_ci atomic64_set(&tmp->seqno, 0); 6008c2ecf20Sopenharmony_ci refcount_set(&tmp->refcnt, 1); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci *aead = tmp; 6038c2ecf20Sopenharmony_ci return 0; 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci/** 6078c2ecf20Sopenharmony_ci * tipc_aead_clone - Clone a TIPC AEAD key 6088c2ecf20Sopenharmony_ci * @dst: dest key for the cloning 6098c2ecf20Sopenharmony_ci * @src: source key to clone from 6108c2ecf20Sopenharmony_ci * 6118c2ecf20Sopenharmony_ci * Make a "copy" of the source AEAD key data to the dest, the TFMs list is 6128c2ecf20Sopenharmony_ci * common for the keys. 6138c2ecf20Sopenharmony_ci * A reference to the source is hold in the "cloned" pointer for the later 6148c2ecf20Sopenharmony_ci * freeing purposes. 6158c2ecf20Sopenharmony_ci * 6168c2ecf20Sopenharmony_ci * Note: this must be done in cluster-key mode only! 6178c2ecf20Sopenharmony_ci * Return: 0 in case of success, otherwise < 0 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_cistatic int tipc_aead_clone(struct tipc_aead **dst, struct tipc_aead *src) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci struct tipc_aead *aead; 6228c2ecf20Sopenharmony_ci int cpu; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (!src) 6258c2ecf20Sopenharmony_ci return -ENOKEY; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (src->mode != CLUSTER_KEY) 6288c2ecf20Sopenharmony_ci return -EINVAL; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (unlikely(*dst)) 6318c2ecf20Sopenharmony_ci return -EEXIST; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci aead = kzalloc(sizeof(*aead), GFP_ATOMIC); 6348c2ecf20Sopenharmony_ci if (unlikely(!aead)) 6358c2ecf20Sopenharmony_ci return -ENOMEM; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci aead->tfm_entry = alloc_percpu_gfp(struct tipc_tfm *, GFP_ATOMIC); 6388c2ecf20Sopenharmony_ci if (unlikely(!aead->tfm_entry)) { 6398c2ecf20Sopenharmony_ci kfree_sensitive(aead); 6408c2ecf20Sopenharmony_ci return -ENOMEM; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 6448c2ecf20Sopenharmony_ci *per_cpu_ptr(aead->tfm_entry, cpu) = 6458c2ecf20Sopenharmony_ci *per_cpu_ptr(src->tfm_entry, cpu); 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci memcpy(aead->hint, src->hint, sizeof(src->hint)); 6498c2ecf20Sopenharmony_ci aead->mode = src->mode; 6508c2ecf20Sopenharmony_ci aead->salt = src->salt; 6518c2ecf20Sopenharmony_ci aead->authsize = src->authsize; 6528c2ecf20Sopenharmony_ci atomic_set(&aead->users, 0); 6538c2ecf20Sopenharmony_ci atomic64_set(&aead->seqno, 0); 6548c2ecf20Sopenharmony_ci refcount_set(&aead->refcnt, 1); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci WARN_ON(!refcount_inc_not_zero(&src->refcnt)); 6578c2ecf20Sopenharmony_ci aead->cloned = src; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci *dst = aead; 6608c2ecf20Sopenharmony_ci return 0; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci/** 6648c2ecf20Sopenharmony_ci * tipc_aead_mem_alloc - Allocate memory for AEAD request operations 6658c2ecf20Sopenharmony_ci * @tfm: cipher handle to be registered with the request 6668c2ecf20Sopenharmony_ci * @crypto_ctx_size: size of crypto context for callback 6678c2ecf20Sopenharmony_ci * @iv: returned pointer to IV data 6688c2ecf20Sopenharmony_ci * @req: returned pointer to AEAD request data 6698c2ecf20Sopenharmony_ci * @sg: returned pointer to SG lists 6708c2ecf20Sopenharmony_ci * @nsg: number of SG lists to be allocated 6718c2ecf20Sopenharmony_ci * 6728c2ecf20Sopenharmony_ci * Allocate memory to store the crypto context data, AEAD request, IV and SG 6738c2ecf20Sopenharmony_ci * lists, the memory layout is as follows: 6748c2ecf20Sopenharmony_ci * crypto_ctx || iv || aead_req || sg[] 6758c2ecf20Sopenharmony_ci * 6768c2ecf20Sopenharmony_ci * Return: the pointer to the memory areas in case of success, otherwise NULL 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_cistatic void *tipc_aead_mem_alloc(struct crypto_aead *tfm, 6798c2ecf20Sopenharmony_ci unsigned int crypto_ctx_size, 6808c2ecf20Sopenharmony_ci u8 **iv, struct aead_request **req, 6818c2ecf20Sopenharmony_ci struct scatterlist **sg, int nsg) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci unsigned int iv_size, req_size; 6848c2ecf20Sopenharmony_ci unsigned int len; 6858c2ecf20Sopenharmony_ci u8 *mem; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci iv_size = crypto_aead_ivsize(tfm); 6888c2ecf20Sopenharmony_ci req_size = sizeof(**req) + crypto_aead_reqsize(tfm); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci len = crypto_ctx_size; 6918c2ecf20Sopenharmony_ci len += iv_size; 6928c2ecf20Sopenharmony_ci len += crypto_aead_alignmask(tfm) & ~(crypto_tfm_ctx_alignment() - 1); 6938c2ecf20Sopenharmony_ci len = ALIGN(len, crypto_tfm_ctx_alignment()); 6948c2ecf20Sopenharmony_ci len += req_size; 6958c2ecf20Sopenharmony_ci len = ALIGN(len, __alignof__(struct scatterlist)); 6968c2ecf20Sopenharmony_ci len += nsg * sizeof(**sg); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci mem = kmalloc(len, GFP_ATOMIC); 6998c2ecf20Sopenharmony_ci if (!mem) 7008c2ecf20Sopenharmony_ci return NULL; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci *iv = (u8 *)PTR_ALIGN(mem + crypto_ctx_size, 7038c2ecf20Sopenharmony_ci crypto_aead_alignmask(tfm) + 1); 7048c2ecf20Sopenharmony_ci *req = (struct aead_request *)PTR_ALIGN(*iv + iv_size, 7058c2ecf20Sopenharmony_ci crypto_tfm_ctx_alignment()); 7068c2ecf20Sopenharmony_ci *sg = (struct scatterlist *)PTR_ALIGN((u8 *)*req + req_size, 7078c2ecf20Sopenharmony_ci __alignof__(struct scatterlist)); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci return (void *)mem; 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci/** 7138c2ecf20Sopenharmony_ci * tipc_aead_encrypt - Encrypt a message 7148c2ecf20Sopenharmony_ci * @aead: TIPC AEAD key for the message encryption 7158c2ecf20Sopenharmony_ci * @skb: the input/output skb 7168c2ecf20Sopenharmony_ci * @b: TIPC bearer where the message will be delivered after the encryption 7178c2ecf20Sopenharmony_ci * @dst: the destination media address 7188c2ecf20Sopenharmony_ci * @__dnode: TIPC dest node if "known" 7198c2ecf20Sopenharmony_ci * 7208c2ecf20Sopenharmony_ci * Return: 7218c2ecf20Sopenharmony_ci * 0 : if the encryption has completed 7228c2ecf20Sopenharmony_ci * -EINPROGRESS/-EBUSY : if a callback will be performed 7238c2ecf20Sopenharmony_ci * < 0 : the encryption has failed 7248c2ecf20Sopenharmony_ci */ 7258c2ecf20Sopenharmony_cistatic int tipc_aead_encrypt(struct tipc_aead *aead, struct sk_buff *skb, 7268c2ecf20Sopenharmony_ci struct tipc_bearer *b, 7278c2ecf20Sopenharmony_ci struct tipc_media_addr *dst, 7288c2ecf20Sopenharmony_ci struct tipc_node *__dnode) 7298c2ecf20Sopenharmony_ci{ 7308c2ecf20Sopenharmony_ci struct crypto_aead *tfm = tipc_aead_tfm_next(aead); 7318c2ecf20Sopenharmony_ci struct tipc_crypto_tx_ctx *tx_ctx; 7328c2ecf20Sopenharmony_ci struct aead_request *req; 7338c2ecf20Sopenharmony_ci struct sk_buff *trailer; 7348c2ecf20Sopenharmony_ci struct scatterlist *sg; 7358c2ecf20Sopenharmony_ci struct tipc_ehdr *ehdr; 7368c2ecf20Sopenharmony_ci int ehsz, len, tailen, nsg, rc; 7378c2ecf20Sopenharmony_ci void *ctx; 7388c2ecf20Sopenharmony_ci u32 salt; 7398c2ecf20Sopenharmony_ci u8 *iv; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci /* Make sure message len at least 4-byte aligned */ 7428c2ecf20Sopenharmony_ci len = ALIGN(skb->len, 4); 7438c2ecf20Sopenharmony_ci tailen = len - skb->len + aead->authsize; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* Expand skb tail for authentication tag: 7468c2ecf20Sopenharmony_ci * As for simplicity, we'd have made sure skb having enough tailroom 7478c2ecf20Sopenharmony_ci * for authentication tag @skb allocation. Even when skb is nonlinear 7488c2ecf20Sopenharmony_ci * but there is no frag_list, it should be still fine! 7498c2ecf20Sopenharmony_ci * Otherwise, we must cow it to be a writable buffer with the tailroom. 7508c2ecf20Sopenharmony_ci */ 7518c2ecf20Sopenharmony_ci SKB_LINEAR_ASSERT(skb); 7528c2ecf20Sopenharmony_ci if (tailen > skb_tailroom(skb)) { 7538c2ecf20Sopenharmony_ci pr_debug("TX(): skb tailroom is not enough: %d, requires: %d\n", 7548c2ecf20Sopenharmony_ci skb_tailroom(skb), tailen); 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (unlikely(!skb_cloned(skb) && tailen <= skb_tailroom(skb))) { 7588c2ecf20Sopenharmony_ci nsg = 1; 7598c2ecf20Sopenharmony_ci trailer = skb; 7608c2ecf20Sopenharmony_ci } else { 7618c2ecf20Sopenharmony_ci /* TODO: We could avoid skb_cow_data() if skb has no frag_list 7628c2ecf20Sopenharmony_ci * e.g. by skb_fill_page_desc() to add another page to the skb 7638c2ecf20Sopenharmony_ci * with the wanted tailen... However, page skbs look not often, 7648c2ecf20Sopenharmony_ci * so take it easy now! 7658c2ecf20Sopenharmony_ci * Cloned skbs e.g. from link_xmit() seems no choice though :( 7668c2ecf20Sopenharmony_ci */ 7678c2ecf20Sopenharmony_ci nsg = skb_cow_data(skb, tailen, &trailer); 7688c2ecf20Sopenharmony_ci if (unlikely(nsg < 0)) { 7698c2ecf20Sopenharmony_ci pr_err("TX: skb_cow_data() returned %d\n", nsg); 7708c2ecf20Sopenharmony_ci return nsg; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci pskb_put(skb, trailer, tailen); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci /* Allocate memory for the AEAD operation */ 7778c2ecf20Sopenharmony_ci ctx = tipc_aead_mem_alloc(tfm, sizeof(*tx_ctx), &iv, &req, &sg, nsg); 7788c2ecf20Sopenharmony_ci if (unlikely(!ctx)) 7798c2ecf20Sopenharmony_ci return -ENOMEM; 7808c2ecf20Sopenharmony_ci TIPC_SKB_CB(skb)->crypto_ctx = ctx; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci /* Map skb to the sg lists */ 7838c2ecf20Sopenharmony_ci sg_init_table(sg, nsg); 7848c2ecf20Sopenharmony_ci rc = skb_to_sgvec(skb, sg, 0, skb->len); 7858c2ecf20Sopenharmony_ci if (unlikely(rc < 0)) { 7868c2ecf20Sopenharmony_ci pr_err("TX: skb_to_sgvec() returned %d, nsg %d!\n", rc, nsg); 7878c2ecf20Sopenharmony_ci goto exit; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci /* Prepare IV: [SALT (4 octets)][SEQNO (8 octets)] 7918c2ecf20Sopenharmony_ci * In case we're in cluster-key mode, SALT is varied by xor-ing with 7928c2ecf20Sopenharmony_ci * the source address (or w0 of id), otherwise with the dest address 7938c2ecf20Sopenharmony_ci * if dest is known. 7948c2ecf20Sopenharmony_ci */ 7958c2ecf20Sopenharmony_ci ehdr = (struct tipc_ehdr *)skb->data; 7968c2ecf20Sopenharmony_ci salt = aead->salt; 7978c2ecf20Sopenharmony_ci if (aead->mode == CLUSTER_KEY) 7988c2ecf20Sopenharmony_ci salt ^= ehdr->addr; /* __be32 */ 7998c2ecf20Sopenharmony_ci else if (__dnode) 8008c2ecf20Sopenharmony_ci salt ^= tipc_node_get_addr(__dnode); 8018c2ecf20Sopenharmony_ci memcpy(iv, &salt, 4); 8028c2ecf20Sopenharmony_ci memcpy(iv + 4, (u8 *)&ehdr->seqno, 8); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci /* Prepare request */ 8058c2ecf20Sopenharmony_ci ehsz = tipc_ehdr_size(ehdr); 8068c2ecf20Sopenharmony_ci aead_request_set_tfm(req, tfm); 8078c2ecf20Sopenharmony_ci aead_request_set_ad(req, ehsz); 8088c2ecf20Sopenharmony_ci aead_request_set_crypt(req, sg, sg, len - ehsz, iv); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci /* Set callback function & data */ 8118c2ecf20Sopenharmony_ci aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, 8128c2ecf20Sopenharmony_ci tipc_aead_encrypt_done, skb); 8138c2ecf20Sopenharmony_ci tx_ctx = (struct tipc_crypto_tx_ctx *)ctx; 8148c2ecf20Sopenharmony_ci tx_ctx->aead = aead; 8158c2ecf20Sopenharmony_ci tx_ctx->bearer = b; 8168c2ecf20Sopenharmony_ci memcpy(&tx_ctx->dst, dst, sizeof(*dst)); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci /* Hold bearer */ 8198c2ecf20Sopenharmony_ci if (unlikely(!tipc_bearer_hold(b))) { 8208c2ecf20Sopenharmony_ci rc = -ENODEV; 8218c2ecf20Sopenharmony_ci goto exit; 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci /* Now, do encrypt */ 8258c2ecf20Sopenharmony_ci rc = crypto_aead_encrypt(req); 8268c2ecf20Sopenharmony_ci if (rc == -EINPROGRESS || rc == -EBUSY) 8278c2ecf20Sopenharmony_ci return rc; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci tipc_bearer_put(b); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ciexit: 8328c2ecf20Sopenharmony_ci kfree(ctx); 8338c2ecf20Sopenharmony_ci TIPC_SKB_CB(skb)->crypto_ctx = NULL; 8348c2ecf20Sopenharmony_ci return rc; 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic void tipc_aead_encrypt_done(struct crypto_async_request *base, int err) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci struct sk_buff *skb = base->data; 8408c2ecf20Sopenharmony_ci struct tipc_crypto_tx_ctx *tx_ctx = TIPC_SKB_CB(skb)->crypto_ctx; 8418c2ecf20Sopenharmony_ci struct tipc_bearer *b = tx_ctx->bearer; 8428c2ecf20Sopenharmony_ci struct tipc_aead *aead = tx_ctx->aead; 8438c2ecf20Sopenharmony_ci struct tipc_crypto *tx = aead->crypto; 8448c2ecf20Sopenharmony_ci struct net *net = tx->net; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci switch (err) { 8478c2ecf20Sopenharmony_ci case 0: 8488c2ecf20Sopenharmony_ci this_cpu_inc(tx->stats->stat[STAT_ASYNC_OK]); 8498c2ecf20Sopenharmony_ci rcu_read_lock(); 8508c2ecf20Sopenharmony_ci if (likely(test_bit(0, &b->up))) 8518c2ecf20Sopenharmony_ci b->media->send_msg(net, skb, b, &tx_ctx->dst); 8528c2ecf20Sopenharmony_ci else 8538c2ecf20Sopenharmony_ci kfree_skb(skb); 8548c2ecf20Sopenharmony_ci rcu_read_unlock(); 8558c2ecf20Sopenharmony_ci break; 8568c2ecf20Sopenharmony_ci case -EINPROGRESS: 8578c2ecf20Sopenharmony_ci return; 8588c2ecf20Sopenharmony_ci default: 8598c2ecf20Sopenharmony_ci this_cpu_inc(tx->stats->stat[STAT_ASYNC_NOK]); 8608c2ecf20Sopenharmony_ci kfree_skb(skb); 8618c2ecf20Sopenharmony_ci break; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci kfree(tx_ctx); 8658c2ecf20Sopenharmony_ci tipc_bearer_put(b); 8668c2ecf20Sopenharmony_ci tipc_aead_put(aead); 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci/** 8708c2ecf20Sopenharmony_ci * tipc_aead_decrypt - Decrypt an encrypted message 8718c2ecf20Sopenharmony_ci * @net: struct net 8728c2ecf20Sopenharmony_ci * @aead: TIPC AEAD for the message decryption 8738c2ecf20Sopenharmony_ci * @skb: the input/output skb 8748c2ecf20Sopenharmony_ci * @b: TIPC bearer where the message has been received 8758c2ecf20Sopenharmony_ci * 8768c2ecf20Sopenharmony_ci * Return: 8778c2ecf20Sopenharmony_ci * 0 : if the decryption has completed 8788c2ecf20Sopenharmony_ci * -EINPROGRESS/-EBUSY : if a callback will be performed 8798c2ecf20Sopenharmony_ci * < 0 : the decryption has failed 8808c2ecf20Sopenharmony_ci */ 8818c2ecf20Sopenharmony_cistatic int tipc_aead_decrypt(struct net *net, struct tipc_aead *aead, 8828c2ecf20Sopenharmony_ci struct sk_buff *skb, struct tipc_bearer *b) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci struct tipc_crypto_rx_ctx *rx_ctx; 8858c2ecf20Sopenharmony_ci struct aead_request *req; 8868c2ecf20Sopenharmony_ci struct crypto_aead *tfm; 8878c2ecf20Sopenharmony_ci struct sk_buff *unused; 8888c2ecf20Sopenharmony_ci struct scatterlist *sg; 8898c2ecf20Sopenharmony_ci struct tipc_ehdr *ehdr; 8908c2ecf20Sopenharmony_ci int ehsz, nsg, rc; 8918c2ecf20Sopenharmony_ci void *ctx; 8928c2ecf20Sopenharmony_ci u32 salt; 8938c2ecf20Sopenharmony_ci u8 *iv; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci if (unlikely(!aead)) 8968c2ecf20Sopenharmony_ci return -ENOKEY; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci nsg = skb_cow_data(skb, 0, &unused); 8998c2ecf20Sopenharmony_ci if (unlikely(nsg < 0)) { 9008c2ecf20Sopenharmony_ci pr_err("RX: skb_cow_data() returned %d\n", nsg); 9018c2ecf20Sopenharmony_ci return nsg; 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci /* Allocate memory for the AEAD operation */ 9058c2ecf20Sopenharmony_ci tfm = tipc_aead_tfm_next(aead); 9068c2ecf20Sopenharmony_ci ctx = tipc_aead_mem_alloc(tfm, sizeof(*rx_ctx), &iv, &req, &sg, nsg); 9078c2ecf20Sopenharmony_ci if (unlikely(!ctx)) 9088c2ecf20Sopenharmony_ci return -ENOMEM; 9098c2ecf20Sopenharmony_ci TIPC_SKB_CB(skb)->crypto_ctx = ctx; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci /* Map skb to the sg lists */ 9128c2ecf20Sopenharmony_ci sg_init_table(sg, nsg); 9138c2ecf20Sopenharmony_ci rc = skb_to_sgvec(skb, sg, 0, skb->len); 9148c2ecf20Sopenharmony_ci if (unlikely(rc < 0)) { 9158c2ecf20Sopenharmony_ci pr_err("RX: skb_to_sgvec() returned %d, nsg %d\n", rc, nsg); 9168c2ecf20Sopenharmony_ci goto exit; 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci /* Reconstruct IV: */ 9208c2ecf20Sopenharmony_ci ehdr = (struct tipc_ehdr *)skb->data; 9218c2ecf20Sopenharmony_ci salt = aead->salt; 9228c2ecf20Sopenharmony_ci if (aead->mode == CLUSTER_KEY) 9238c2ecf20Sopenharmony_ci salt ^= ehdr->addr; /* __be32 */ 9248c2ecf20Sopenharmony_ci else if (ehdr->destined) 9258c2ecf20Sopenharmony_ci salt ^= tipc_own_addr(net); 9268c2ecf20Sopenharmony_ci memcpy(iv, &salt, 4); 9278c2ecf20Sopenharmony_ci memcpy(iv + 4, (u8 *)&ehdr->seqno, 8); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* Prepare request */ 9308c2ecf20Sopenharmony_ci ehsz = tipc_ehdr_size(ehdr); 9318c2ecf20Sopenharmony_ci aead_request_set_tfm(req, tfm); 9328c2ecf20Sopenharmony_ci aead_request_set_ad(req, ehsz); 9338c2ecf20Sopenharmony_ci aead_request_set_crypt(req, sg, sg, skb->len - ehsz, iv); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci /* Set callback function & data */ 9368c2ecf20Sopenharmony_ci aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, 9378c2ecf20Sopenharmony_ci tipc_aead_decrypt_done, skb); 9388c2ecf20Sopenharmony_ci rx_ctx = (struct tipc_crypto_rx_ctx *)ctx; 9398c2ecf20Sopenharmony_ci rx_ctx->aead = aead; 9408c2ecf20Sopenharmony_ci rx_ctx->bearer = b; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci /* Hold bearer */ 9438c2ecf20Sopenharmony_ci if (unlikely(!tipc_bearer_hold(b))) { 9448c2ecf20Sopenharmony_ci rc = -ENODEV; 9458c2ecf20Sopenharmony_ci goto exit; 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci /* Now, do decrypt */ 9498c2ecf20Sopenharmony_ci rc = crypto_aead_decrypt(req); 9508c2ecf20Sopenharmony_ci if (rc == -EINPROGRESS || rc == -EBUSY) 9518c2ecf20Sopenharmony_ci return rc; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci tipc_bearer_put(b); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ciexit: 9568c2ecf20Sopenharmony_ci kfree(ctx); 9578c2ecf20Sopenharmony_ci TIPC_SKB_CB(skb)->crypto_ctx = NULL; 9588c2ecf20Sopenharmony_ci return rc; 9598c2ecf20Sopenharmony_ci} 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_cistatic void tipc_aead_decrypt_done(struct crypto_async_request *base, int err) 9628c2ecf20Sopenharmony_ci{ 9638c2ecf20Sopenharmony_ci struct sk_buff *skb = base->data; 9648c2ecf20Sopenharmony_ci struct tipc_crypto_rx_ctx *rx_ctx = TIPC_SKB_CB(skb)->crypto_ctx; 9658c2ecf20Sopenharmony_ci struct tipc_bearer *b = rx_ctx->bearer; 9668c2ecf20Sopenharmony_ci struct tipc_aead *aead = rx_ctx->aead; 9678c2ecf20Sopenharmony_ci struct tipc_crypto_stats __percpu *stats = aead->crypto->stats; 9688c2ecf20Sopenharmony_ci struct net *net = aead->crypto->net; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci switch (err) { 9718c2ecf20Sopenharmony_ci case 0: 9728c2ecf20Sopenharmony_ci this_cpu_inc(stats->stat[STAT_ASYNC_OK]); 9738c2ecf20Sopenharmony_ci break; 9748c2ecf20Sopenharmony_ci case -EINPROGRESS: 9758c2ecf20Sopenharmony_ci return; 9768c2ecf20Sopenharmony_ci default: 9778c2ecf20Sopenharmony_ci this_cpu_inc(stats->stat[STAT_ASYNC_NOK]); 9788c2ecf20Sopenharmony_ci break; 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci kfree(rx_ctx); 9828c2ecf20Sopenharmony_ci tipc_crypto_rcv_complete(net, aead, b, &skb, err); 9838c2ecf20Sopenharmony_ci if (likely(skb)) { 9848c2ecf20Sopenharmony_ci if (likely(test_bit(0, &b->up))) 9858c2ecf20Sopenharmony_ci tipc_rcv(net, skb, b); 9868c2ecf20Sopenharmony_ci else 9878c2ecf20Sopenharmony_ci kfree_skb(skb); 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci tipc_bearer_put(b); 9918c2ecf20Sopenharmony_ci} 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_cistatic inline int tipc_ehdr_size(struct tipc_ehdr *ehdr) 9948c2ecf20Sopenharmony_ci{ 9958c2ecf20Sopenharmony_ci return (ehdr->user != LINK_CONFIG) ? EHDR_SIZE : EHDR_CFG_SIZE; 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci/** 9998c2ecf20Sopenharmony_ci * tipc_ehdr_validate - Validate an encryption message 10008c2ecf20Sopenharmony_ci * @skb: the message buffer 10018c2ecf20Sopenharmony_ci * 10028c2ecf20Sopenharmony_ci * Returns "true" if this is a valid encryption message, otherwise "false" 10038c2ecf20Sopenharmony_ci */ 10048c2ecf20Sopenharmony_cibool tipc_ehdr_validate(struct sk_buff *skb) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci struct tipc_ehdr *ehdr; 10078c2ecf20Sopenharmony_ci int ehsz; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (unlikely(!pskb_may_pull(skb, EHDR_MIN_SIZE))) 10108c2ecf20Sopenharmony_ci return false; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci ehdr = (struct tipc_ehdr *)skb->data; 10138c2ecf20Sopenharmony_ci if (unlikely(ehdr->version != TIPC_EVERSION)) 10148c2ecf20Sopenharmony_ci return false; 10158c2ecf20Sopenharmony_ci ehsz = tipc_ehdr_size(ehdr); 10168c2ecf20Sopenharmony_ci if (unlikely(!pskb_may_pull(skb, ehsz))) 10178c2ecf20Sopenharmony_ci return false; 10188c2ecf20Sopenharmony_ci if (unlikely(skb->len <= ehsz + TIPC_AES_GCM_TAG_SIZE)) 10198c2ecf20Sopenharmony_ci return false; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci return true; 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci/** 10258c2ecf20Sopenharmony_ci * tipc_ehdr_build - Build TIPC encryption message header 10268c2ecf20Sopenharmony_ci * @net: struct net 10278c2ecf20Sopenharmony_ci * @aead: TX AEAD key to be used for the message encryption 10288c2ecf20Sopenharmony_ci * @tx_key: key id used for the message encryption 10298c2ecf20Sopenharmony_ci * @skb: input/output message skb 10308c2ecf20Sopenharmony_ci * @__rx: RX crypto handle if dest is "known" 10318c2ecf20Sopenharmony_ci * 10328c2ecf20Sopenharmony_ci * Return: the header size if the building is successful, otherwise < 0 10338c2ecf20Sopenharmony_ci */ 10348c2ecf20Sopenharmony_cistatic int tipc_ehdr_build(struct net *net, struct tipc_aead *aead, 10358c2ecf20Sopenharmony_ci u8 tx_key, struct sk_buff *skb, 10368c2ecf20Sopenharmony_ci struct tipc_crypto *__rx) 10378c2ecf20Sopenharmony_ci{ 10388c2ecf20Sopenharmony_ci struct tipc_msg *hdr = buf_msg(skb); 10398c2ecf20Sopenharmony_ci struct tipc_ehdr *ehdr; 10408c2ecf20Sopenharmony_ci u32 user = msg_user(hdr); 10418c2ecf20Sopenharmony_ci u64 seqno; 10428c2ecf20Sopenharmony_ci int ehsz; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci /* Make room for encryption header */ 10458c2ecf20Sopenharmony_ci ehsz = (user != LINK_CONFIG) ? EHDR_SIZE : EHDR_CFG_SIZE; 10468c2ecf20Sopenharmony_ci WARN_ON(skb_headroom(skb) < ehsz); 10478c2ecf20Sopenharmony_ci ehdr = (struct tipc_ehdr *)skb_push(skb, ehsz); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci /* Obtain a seqno first: 10508c2ecf20Sopenharmony_ci * Use the key seqno (= cluster wise) if dest is unknown or we're in 10518c2ecf20Sopenharmony_ci * cluster key mode, otherwise it's better for a per-peer seqno! 10528c2ecf20Sopenharmony_ci */ 10538c2ecf20Sopenharmony_ci if (!__rx || aead->mode == CLUSTER_KEY) 10548c2ecf20Sopenharmony_ci seqno = atomic64_inc_return(&aead->seqno); 10558c2ecf20Sopenharmony_ci else 10568c2ecf20Sopenharmony_ci seqno = atomic64_inc_return(&__rx->sndnxt); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci /* Revoke the key if seqno is wrapped around */ 10598c2ecf20Sopenharmony_ci if (unlikely(!seqno)) 10608c2ecf20Sopenharmony_ci return tipc_crypto_key_revoke(net, tx_key); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci /* Word 1-2 */ 10638c2ecf20Sopenharmony_ci ehdr->seqno = cpu_to_be64(seqno); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci /* Words 0, 3- */ 10668c2ecf20Sopenharmony_ci ehdr->version = TIPC_EVERSION; 10678c2ecf20Sopenharmony_ci ehdr->user = 0; 10688c2ecf20Sopenharmony_ci ehdr->keepalive = 0; 10698c2ecf20Sopenharmony_ci ehdr->tx_key = tx_key; 10708c2ecf20Sopenharmony_ci ehdr->destined = (__rx) ? 1 : 0; 10718c2ecf20Sopenharmony_ci ehdr->rx_key_active = (__rx) ? __rx->key.active : 0; 10728c2ecf20Sopenharmony_ci ehdr->rx_nokey = (__rx) ? __rx->nokey : 0; 10738c2ecf20Sopenharmony_ci ehdr->master_key = aead->crypto->key_master; 10748c2ecf20Sopenharmony_ci ehdr->reserved_1 = 0; 10758c2ecf20Sopenharmony_ci ehdr->reserved_2 = 0; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci switch (user) { 10788c2ecf20Sopenharmony_ci case LINK_CONFIG: 10798c2ecf20Sopenharmony_ci ehdr->user = LINK_CONFIG; 10808c2ecf20Sopenharmony_ci memcpy(ehdr->id, tipc_own_id(net), NODE_ID_LEN); 10818c2ecf20Sopenharmony_ci break; 10828c2ecf20Sopenharmony_ci default: 10838c2ecf20Sopenharmony_ci if (user == LINK_PROTOCOL && msg_type(hdr) == STATE_MSG) { 10848c2ecf20Sopenharmony_ci ehdr->user = LINK_PROTOCOL; 10858c2ecf20Sopenharmony_ci ehdr->keepalive = msg_is_keepalive(hdr); 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci ehdr->addr = hdr->hdr[3]; 10888c2ecf20Sopenharmony_ci break; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci return ehsz; 10928c2ecf20Sopenharmony_ci} 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_cistatic inline void tipc_crypto_key_set_state(struct tipc_crypto *c, 10958c2ecf20Sopenharmony_ci u8 new_passive, 10968c2ecf20Sopenharmony_ci u8 new_active, 10978c2ecf20Sopenharmony_ci u8 new_pending) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci struct tipc_key old = c->key; 11008c2ecf20Sopenharmony_ci char buf[32]; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci c->key.keys = ((new_passive & KEY_MASK) << (KEY_BITS * 2)) | 11038c2ecf20Sopenharmony_ci ((new_active & KEY_MASK) << (KEY_BITS)) | 11048c2ecf20Sopenharmony_ci ((new_pending & KEY_MASK)); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci pr_debug("%s: key changing %s ::%pS\n", c->name, 11078c2ecf20Sopenharmony_ci tipc_key_change_dump(old, c->key, buf), 11088c2ecf20Sopenharmony_ci __builtin_return_address(0)); 11098c2ecf20Sopenharmony_ci} 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci/** 11128c2ecf20Sopenharmony_ci * tipc_crypto_key_init - Initiate a new user / AEAD key 11138c2ecf20Sopenharmony_ci * @c: TIPC crypto to which new key is attached 11148c2ecf20Sopenharmony_ci * @ukey: the user key 11158c2ecf20Sopenharmony_ci * @mode: the key mode (CLUSTER_KEY or PER_NODE_KEY) 11168c2ecf20Sopenharmony_ci * @master_key: specify this is a cluster master key 11178c2ecf20Sopenharmony_ci * 11188c2ecf20Sopenharmony_ci * A new TIPC AEAD key will be allocated and initiated with the specified user 11198c2ecf20Sopenharmony_ci * key, then attached to the TIPC crypto. 11208c2ecf20Sopenharmony_ci * 11218c2ecf20Sopenharmony_ci * Return: new key id in case of success, otherwise: < 0 11228c2ecf20Sopenharmony_ci */ 11238c2ecf20Sopenharmony_ciint tipc_crypto_key_init(struct tipc_crypto *c, struct tipc_aead_key *ukey, 11248c2ecf20Sopenharmony_ci u8 mode, bool master_key) 11258c2ecf20Sopenharmony_ci{ 11268c2ecf20Sopenharmony_ci struct tipc_aead *aead = NULL; 11278c2ecf20Sopenharmony_ci int rc = 0; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci /* Initiate with the new user key */ 11308c2ecf20Sopenharmony_ci rc = tipc_aead_init(&aead, ukey, mode); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci /* Attach it to the crypto */ 11338c2ecf20Sopenharmony_ci if (likely(!rc)) { 11348c2ecf20Sopenharmony_ci rc = tipc_crypto_key_attach(c, aead, 0, master_key); 11358c2ecf20Sopenharmony_ci if (rc < 0) 11368c2ecf20Sopenharmony_ci tipc_aead_free(&aead->rcu); 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci return rc; 11408c2ecf20Sopenharmony_ci} 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci/** 11438c2ecf20Sopenharmony_ci * tipc_crypto_key_attach - Attach a new AEAD key to TIPC crypto 11448c2ecf20Sopenharmony_ci * @c: TIPC crypto to which the new AEAD key is attached 11458c2ecf20Sopenharmony_ci * @aead: the new AEAD key pointer 11468c2ecf20Sopenharmony_ci * @pos: desired slot in the crypto key array, = 0 if any! 11478c2ecf20Sopenharmony_ci * @master_key: specify this is a cluster master key 11488c2ecf20Sopenharmony_ci * 11498c2ecf20Sopenharmony_ci * Return: new key id in case of success, otherwise: -EBUSY 11508c2ecf20Sopenharmony_ci */ 11518c2ecf20Sopenharmony_cistatic int tipc_crypto_key_attach(struct tipc_crypto *c, 11528c2ecf20Sopenharmony_ci struct tipc_aead *aead, u8 pos, 11538c2ecf20Sopenharmony_ci bool master_key) 11548c2ecf20Sopenharmony_ci{ 11558c2ecf20Sopenharmony_ci struct tipc_key key; 11568c2ecf20Sopenharmony_ci int rc = -EBUSY; 11578c2ecf20Sopenharmony_ci u8 new_key; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci spin_lock_bh(&c->lock); 11608c2ecf20Sopenharmony_ci key = c->key; 11618c2ecf20Sopenharmony_ci if (master_key) { 11628c2ecf20Sopenharmony_ci new_key = KEY_MASTER; 11638c2ecf20Sopenharmony_ci goto attach; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci if (key.active && key.passive) 11668c2ecf20Sopenharmony_ci goto exit; 11678c2ecf20Sopenharmony_ci if (key.pending) { 11688c2ecf20Sopenharmony_ci if (tipc_aead_users(c->aead[key.pending]) > 0) 11698c2ecf20Sopenharmony_ci goto exit; 11708c2ecf20Sopenharmony_ci /* if (pos): ok with replacing, will be aligned when needed */ 11718c2ecf20Sopenharmony_ci /* Replace it */ 11728c2ecf20Sopenharmony_ci new_key = key.pending; 11738c2ecf20Sopenharmony_ci } else { 11748c2ecf20Sopenharmony_ci if (pos) { 11758c2ecf20Sopenharmony_ci if (key.active && pos != key_next(key.active)) { 11768c2ecf20Sopenharmony_ci key.passive = pos; 11778c2ecf20Sopenharmony_ci new_key = pos; 11788c2ecf20Sopenharmony_ci goto attach; 11798c2ecf20Sopenharmony_ci } else if (!key.active && !key.passive) { 11808c2ecf20Sopenharmony_ci key.pending = pos; 11818c2ecf20Sopenharmony_ci new_key = pos; 11828c2ecf20Sopenharmony_ci goto attach; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci key.pending = key_next(key.active ?: key.passive); 11868c2ecf20Sopenharmony_ci new_key = key.pending; 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ciattach: 11908c2ecf20Sopenharmony_ci aead->crypto = c; 11918c2ecf20Sopenharmony_ci aead->gen = (is_tx(c)) ? ++c->key_gen : c->key_gen; 11928c2ecf20Sopenharmony_ci tipc_aead_rcu_replace(c->aead[new_key], aead, &c->lock); 11938c2ecf20Sopenharmony_ci if (likely(c->key.keys != key.keys)) 11948c2ecf20Sopenharmony_ci tipc_crypto_key_set_state(c, key.passive, key.active, 11958c2ecf20Sopenharmony_ci key.pending); 11968c2ecf20Sopenharmony_ci c->working = 1; 11978c2ecf20Sopenharmony_ci c->nokey = 0; 11988c2ecf20Sopenharmony_ci c->key_master |= master_key; 11998c2ecf20Sopenharmony_ci rc = new_key; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ciexit: 12028c2ecf20Sopenharmony_ci spin_unlock_bh(&c->lock); 12038c2ecf20Sopenharmony_ci return rc; 12048c2ecf20Sopenharmony_ci} 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_civoid tipc_crypto_key_flush(struct tipc_crypto *c) 12078c2ecf20Sopenharmony_ci{ 12088c2ecf20Sopenharmony_ci struct tipc_crypto *tx, *rx; 12098c2ecf20Sopenharmony_ci int k; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci spin_lock_bh(&c->lock); 12128c2ecf20Sopenharmony_ci if (is_rx(c)) { 12138c2ecf20Sopenharmony_ci /* Try to cancel pending work */ 12148c2ecf20Sopenharmony_ci rx = c; 12158c2ecf20Sopenharmony_ci tx = tipc_net(rx->net)->crypto_tx; 12168c2ecf20Sopenharmony_ci if (cancel_delayed_work(&rx->work)) { 12178c2ecf20Sopenharmony_ci kfree(rx->skey); 12188c2ecf20Sopenharmony_ci rx->skey = NULL; 12198c2ecf20Sopenharmony_ci atomic_xchg(&rx->key_distr, 0); 12208c2ecf20Sopenharmony_ci tipc_node_put(rx->node); 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci /* RX stopping => decrease TX key users if any */ 12238c2ecf20Sopenharmony_ci k = atomic_xchg(&rx->peer_rx_active, 0); 12248c2ecf20Sopenharmony_ci if (k) { 12258c2ecf20Sopenharmony_ci tipc_aead_users_dec(tx->aead[k], 0); 12268c2ecf20Sopenharmony_ci /* Mark the point TX key users changed */ 12278c2ecf20Sopenharmony_ci tx->timer1 = jiffies; 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci c->flags = 0; 12328c2ecf20Sopenharmony_ci tipc_crypto_key_set_state(c, 0, 0, 0); 12338c2ecf20Sopenharmony_ci for (k = KEY_MIN; k <= KEY_MAX; k++) 12348c2ecf20Sopenharmony_ci tipc_crypto_key_detach(c->aead[k], &c->lock); 12358c2ecf20Sopenharmony_ci atomic64_set(&c->sndnxt, 0); 12368c2ecf20Sopenharmony_ci spin_unlock_bh(&c->lock); 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci/** 12408c2ecf20Sopenharmony_ci * tipc_crypto_key_try_align - Align RX keys if possible 12418c2ecf20Sopenharmony_ci * @rx: RX crypto handle 12428c2ecf20Sopenharmony_ci * @new_pending: new pending slot if aligned (= TX key from peer) 12438c2ecf20Sopenharmony_ci * 12448c2ecf20Sopenharmony_ci * Peer has used an unknown key slot, this only happens when peer has left and 12458c2ecf20Sopenharmony_ci * rejoned, or we are newcomer. 12468c2ecf20Sopenharmony_ci * That means, there must be no active key but a pending key at unaligned slot. 12478c2ecf20Sopenharmony_ci * If so, we try to move the pending key to the new slot. 12488c2ecf20Sopenharmony_ci * Note: A potential passive key can exist, it will be shifted correspondingly! 12498c2ecf20Sopenharmony_ci * 12508c2ecf20Sopenharmony_ci * Return: "true" if key is successfully aligned, otherwise "false" 12518c2ecf20Sopenharmony_ci */ 12528c2ecf20Sopenharmony_cistatic bool tipc_crypto_key_try_align(struct tipc_crypto *rx, u8 new_pending) 12538c2ecf20Sopenharmony_ci{ 12548c2ecf20Sopenharmony_ci struct tipc_aead *tmp1, *tmp2 = NULL; 12558c2ecf20Sopenharmony_ci struct tipc_key key; 12568c2ecf20Sopenharmony_ci bool aligned = false; 12578c2ecf20Sopenharmony_ci u8 new_passive = 0; 12588c2ecf20Sopenharmony_ci int x; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci spin_lock(&rx->lock); 12618c2ecf20Sopenharmony_ci key = rx->key; 12628c2ecf20Sopenharmony_ci if (key.pending == new_pending) { 12638c2ecf20Sopenharmony_ci aligned = true; 12648c2ecf20Sopenharmony_ci goto exit; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci if (key.active) 12678c2ecf20Sopenharmony_ci goto exit; 12688c2ecf20Sopenharmony_ci if (!key.pending) 12698c2ecf20Sopenharmony_ci goto exit; 12708c2ecf20Sopenharmony_ci if (tipc_aead_users(rx->aead[key.pending]) > 0) 12718c2ecf20Sopenharmony_ci goto exit; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci /* Try to "isolate" this pending key first */ 12748c2ecf20Sopenharmony_ci tmp1 = tipc_aead_rcu_ptr(rx->aead[key.pending], &rx->lock); 12758c2ecf20Sopenharmony_ci if (!refcount_dec_if_one(&tmp1->refcnt)) 12768c2ecf20Sopenharmony_ci goto exit; 12778c2ecf20Sopenharmony_ci rcu_assign_pointer(rx->aead[key.pending], NULL); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci /* Move passive key if any */ 12808c2ecf20Sopenharmony_ci if (key.passive) { 12818c2ecf20Sopenharmony_ci tmp2 = rcu_replace_pointer(rx->aead[key.passive], tmp2, lockdep_is_held(&rx->lock)); 12828c2ecf20Sopenharmony_ci x = (key.passive - key.pending + new_pending) % KEY_MAX; 12838c2ecf20Sopenharmony_ci new_passive = (x <= 0) ? x + KEY_MAX : x; 12848c2ecf20Sopenharmony_ci } 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci /* Re-allocate the key(s) */ 12878c2ecf20Sopenharmony_ci tipc_crypto_key_set_state(rx, new_passive, 0, new_pending); 12888c2ecf20Sopenharmony_ci rcu_assign_pointer(rx->aead[new_pending], tmp1); 12898c2ecf20Sopenharmony_ci if (new_passive) 12908c2ecf20Sopenharmony_ci rcu_assign_pointer(rx->aead[new_passive], tmp2); 12918c2ecf20Sopenharmony_ci refcount_set(&tmp1->refcnt, 1); 12928c2ecf20Sopenharmony_ci aligned = true; 12938c2ecf20Sopenharmony_ci pr_info_ratelimited("%s: key[%d] -> key[%d]\n", rx->name, key.pending, 12948c2ecf20Sopenharmony_ci new_pending); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ciexit: 12978c2ecf20Sopenharmony_ci spin_unlock(&rx->lock); 12988c2ecf20Sopenharmony_ci return aligned; 12998c2ecf20Sopenharmony_ci} 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci/** 13028c2ecf20Sopenharmony_ci * tipc_crypto_key_pick_tx - Pick one TX key for message decryption 13038c2ecf20Sopenharmony_ci * @tx: TX crypto handle 13048c2ecf20Sopenharmony_ci * @rx: RX crypto handle (can be NULL) 13058c2ecf20Sopenharmony_ci * @skb: the message skb which will be decrypted later 13068c2ecf20Sopenharmony_ci * @tx_key: peer TX key id 13078c2ecf20Sopenharmony_ci * 13088c2ecf20Sopenharmony_ci * This function looks up the existing TX keys and pick one which is suitable 13098c2ecf20Sopenharmony_ci * for the message decryption, that must be a cluster key and not used before 13108c2ecf20Sopenharmony_ci * on the same message (i.e. recursive). 13118c2ecf20Sopenharmony_ci * 13128c2ecf20Sopenharmony_ci * Return: the TX AEAD key handle in case of success, otherwise NULL 13138c2ecf20Sopenharmony_ci */ 13148c2ecf20Sopenharmony_cistatic struct tipc_aead *tipc_crypto_key_pick_tx(struct tipc_crypto *tx, 13158c2ecf20Sopenharmony_ci struct tipc_crypto *rx, 13168c2ecf20Sopenharmony_ci struct sk_buff *skb, 13178c2ecf20Sopenharmony_ci u8 tx_key) 13188c2ecf20Sopenharmony_ci{ 13198c2ecf20Sopenharmony_ci struct tipc_skb_cb *skb_cb = TIPC_SKB_CB(skb); 13208c2ecf20Sopenharmony_ci struct tipc_aead *aead = NULL; 13218c2ecf20Sopenharmony_ci struct tipc_key key = tx->key; 13228c2ecf20Sopenharmony_ci u8 k, i = 0; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci /* Initialize data if not yet */ 13258c2ecf20Sopenharmony_ci if (!skb_cb->tx_clone_deferred) { 13268c2ecf20Sopenharmony_ci skb_cb->tx_clone_deferred = 1; 13278c2ecf20Sopenharmony_ci memset(&skb_cb->tx_clone_ctx, 0, sizeof(skb_cb->tx_clone_ctx)); 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci skb_cb->tx_clone_ctx.rx = rx; 13318c2ecf20Sopenharmony_ci if (++skb_cb->tx_clone_ctx.recurs > 2) 13328c2ecf20Sopenharmony_ci return NULL; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci /* Pick one TX key */ 13358c2ecf20Sopenharmony_ci spin_lock(&tx->lock); 13368c2ecf20Sopenharmony_ci if (tx_key == KEY_MASTER) { 13378c2ecf20Sopenharmony_ci aead = tipc_aead_rcu_ptr(tx->aead[KEY_MASTER], &tx->lock); 13388c2ecf20Sopenharmony_ci goto done; 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci do { 13418c2ecf20Sopenharmony_ci k = (i == 0) ? key.pending : 13428c2ecf20Sopenharmony_ci ((i == 1) ? key.active : key.passive); 13438c2ecf20Sopenharmony_ci if (!k) 13448c2ecf20Sopenharmony_ci continue; 13458c2ecf20Sopenharmony_ci aead = tipc_aead_rcu_ptr(tx->aead[k], &tx->lock); 13468c2ecf20Sopenharmony_ci if (!aead) 13478c2ecf20Sopenharmony_ci continue; 13488c2ecf20Sopenharmony_ci if (aead->mode != CLUSTER_KEY || 13498c2ecf20Sopenharmony_ci aead == skb_cb->tx_clone_ctx.last) { 13508c2ecf20Sopenharmony_ci aead = NULL; 13518c2ecf20Sopenharmony_ci continue; 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci /* Ok, found one cluster key */ 13548c2ecf20Sopenharmony_ci skb_cb->tx_clone_ctx.last = aead; 13558c2ecf20Sopenharmony_ci WARN_ON(skb->next); 13568c2ecf20Sopenharmony_ci skb->next = skb_clone(skb, GFP_ATOMIC); 13578c2ecf20Sopenharmony_ci if (unlikely(!skb->next)) 13588c2ecf20Sopenharmony_ci pr_warn("Failed to clone skb for next round if any\n"); 13598c2ecf20Sopenharmony_ci break; 13608c2ecf20Sopenharmony_ci } while (++i < 3); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_cidone: 13638c2ecf20Sopenharmony_ci if (likely(aead)) 13648c2ecf20Sopenharmony_ci WARN_ON(!refcount_inc_not_zero(&aead->refcnt)); 13658c2ecf20Sopenharmony_ci spin_unlock(&tx->lock); 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci return aead; 13688c2ecf20Sopenharmony_ci} 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci/** 13718c2ecf20Sopenharmony_ci * tipc_crypto_key_synch: Synch own key data according to peer key status 13728c2ecf20Sopenharmony_ci * @rx: RX crypto handle 13738c2ecf20Sopenharmony_ci * @skb: TIPCv2 message buffer (incl. the ehdr from peer) 13748c2ecf20Sopenharmony_ci * 13758c2ecf20Sopenharmony_ci * This function updates the peer node related data as the peer RX active key 13768c2ecf20Sopenharmony_ci * has changed, so the number of TX keys' users on this node are increased and 13778c2ecf20Sopenharmony_ci * decreased correspondingly. 13788c2ecf20Sopenharmony_ci * 13798c2ecf20Sopenharmony_ci * It also considers if peer has no key, then we need to make own master key 13808c2ecf20Sopenharmony_ci * (if any) taking over i.e. starting grace period and also trigger key 13818c2ecf20Sopenharmony_ci * distributing process. 13828c2ecf20Sopenharmony_ci * 13838c2ecf20Sopenharmony_ci * The "per-peer" sndnxt is also reset when the peer key has switched. 13848c2ecf20Sopenharmony_ci */ 13858c2ecf20Sopenharmony_cistatic void tipc_crypto_key_synch(struct tipc_crypto *rx, struct sk_buff *skb) 13868c2ecf20Sopenharmony_ci{ 13878c2ecf20Sopenharmony_ci struct tipc_ehdr *ehdr = (struct tipc_ehdr *)skb_network_header(skb); 13888c2ecf20Sopenharmony_ci struct tipc_crypto *tx = tipc_net(rx->net)->crypto_tx; 13898c2ecf20Sopenharmony_ci struct tipc_msg *hdr = buf_msg(skb); 13908c2ecf20Sopenharmony_ci u32 self = tipc_own_addr(rx->net); 13918c2ecf20Sopenharmony_ci u8 cur, new; 13928c2ecf20Sopenharmony_ci unsigned long delay; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci /* Update RX 'key_master' flag according to peer, also mark "legacy" if 13958c2ecf20Sopenharmony_ci * a peer has no master key. 13968c2ecf20Sopenharmony_ci */ 13978c2ecf20Sopenharmony_ci rx->key_master = ehdr->master_key; 13988c2ecf20Sopenharmony_ci if (!rx->key_master) 13998c2ecf20Sopenharmony_ci tx->legacy_user = 1; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci /* For later cases, apply only if message is destined to this node */ 14028c2ecf20Sopenharmony_ci if (!ehdr->destined || msg_short(hdr) || msg_destnode(hdr) != self) 14038c2ecf20Sopenharmony_ci return; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci /* Case 1: Peer has no keys, let's make master key take over */ 14068c2ecf20Sopenharmony_ci if (ehdr->rx_nokey) { 14078c2ecf20Sopenharmony_ci /* Set or extend grace period */ 14088c2ecf20Sopenharmony_ci tx->timer2 = jiffies; 14098c2ecf20Sopenharmony_ci /* Schedule key distributing for the peer if not yet */ 14108c2ecf20Sopenharmony_ci if (tx->key.keys && 14118c2ecf20Sopenharmony_ci !atomic_cmpxchg(&rx->key_distr, 0, KEY_DISTR_SCHED)) { 14128c2ecf20Sopenharmony_ci get_random_bytes(&delay, 2); 14138c2ecf20Sopenharmony_ci delay %= 5; 14148c2ecf20Sopenharmony_ci delay = msecs_to_jiffies(500 * ++delay); 14158c2ecf20Sopenharmony_ci if (queue_delayed_work(tx->wq, &rx->work, delay)) 14168c2ecf20Sopenharmony_ci tipc_node_get(rx->node); 14178c2ecf20Sopenharmony_ci } 14188c2ecf20Sopenharmony_ci } else { 14198c2ecf20Sopenharmony_ci /* Cancel a pending key distributing if any */ 14208c2ecf20Sopenharmony_ci atomic_xchg(&rx->key_distr, 0); 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci /* Case 2: Peer RX active key has changed, let's update own TX users */ 14248c2ecf20Sopenharmony_ci cur = atomic_read(&rx->peer_rx_active); 14258c2ecf20Sopenharmony_ci new = ehdr->rx_key_active; 14268c2ecf20Sopenharmony_ci if (tx->key.keys && 14278c2ecf20Sopenharmony_ci cur != new && 14288c2ecf20Sopenharmony_ci atomic_cmpxchg(&rx->peer_rx_active, cur, new) == cur) { 14298c2ecf20Sopenharmony_ci if (new) 14308c2ecf20Sopenharmony_ci tipc_aead_users_inc(tx->aead[new], INT_MAX); 14318c2ecf20Sopenharmony_ci if (cur) 14328c2ecf20Sopenharmony_ci tipc_aead_users_dec(tx->aead[cur], 0); 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci atomic64_set(&rx->sndnxt, 0); 14358c2ecf20Sopenharmony_ci /* Mark the point TX key users changed */ 14368c2ecf20Sopenharmony_ci tx->timer1 = jiffies; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci pr_debug("%s: key users changed %d-- %d++, peer %s\n", 14398c2ecf20Sopenharmony_ci tx->name, cur, new, rx->name); 14408c2ecf20Sopenharmony_ci } 14418c2ecf20Sopenharmony_ci} 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_cistatic int tipc_crypto_key_revoke(struct net *net, u8 tx_key) 14448c2ecf20Sopenharmony_ci{ 14458c2ecf20Sopenharmony_ci struct tipc_crypto *tx = tipc_net(net)->crypto_tx; 14468c2ecf20Sopenharmony_ci struct tipc_key key; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci spin_lock_bh(&tx->lock); 14498c2ecf20Sopenharmony_ci key = tx->key; 14508c2ecf20Sopenharmony_ci WARN_ON(!key.active || tx_key != key.active); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci /* Free the active key */ 14538c2ecf20Sopenharmony_ci tipc_crypto_key_set_state(tx, key.passive, 0, key.pending); 14548c2ecf20Sopenharmony_ci tipc_crypto_key_detach(tx->aead[key.active], &tx->lock); 14558c2ecf20Sopenharmony_ci spin_unlock_bh(&tx->lock); 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci pr_warn("%s: key is revoked\n", tx->name); 14588c2ecf20Sopenharmony_ci return -EKEYREVOKED; 14598c2ecf20Sopenharmony_ci} 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ciint tipc_crypto_start(struct tipc_crypto **crypto, struct net *net, 14628c2ecf20Sopenharmony_ci struct tipc_node *node) 14638c2ecf20Sopenharmony_ci{ 14648c2ecf20Sopenharmony_ci struct tipc_crypto *c; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci if (*crypto) 14678c2ecf20Sopenharmony_ci return -EEXIST; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci /* Allocate crypto */ 14708c2ecf20Sopenharmony_ci c = kzalloc(sizeof(*c), GFP_ATOMIC); 14718c2ecf20Sopenharmony_ci if (!c) 14728c2ecf20Sopenharmony_ci return -ENOMEM; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci /* Allocate workqueue on TX */ 14758c2ecf20Sopenharmony_ci if (!node) { 14768c2ecf20Sopenharmony_ci c->wq = alloc_ordered_workqueue("tipc_crypto", 0); 14778c2ecf20Sopenharmony_ci if (!c->wq) { 14788c2ecf20Sopenharmony_ci kfree(c); 14798c2ecf20Sopenharmony_ci return -ENOMEM; 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci /* Allocate statistic structure */ 14848c2ecf20Sopenharmony_ci c->stats = alloc_percpu_gfp(struct tipc_crypto_stats, GFP_ATOMIC); 14858c2ecf20Sopenharmony_ci if (!c->stats) { 14868c2ecf20Sopenharmony_ci if (c->wq) 14878c2ecf20Sopenharmony_ci destroy_workqueue(c->wq); 14888c2ecf20Sopenharmony_ci kfree_sensitive(c); 14898c2ecf20Sopenharmony_ci return -ENOMEM; 14908c2ecf20Sopenharmony_ci } 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci c->flags = 0; 14938c2ecf20Sopenharmony_ci c->net = net; 14948c2ecf20Sopenharmony_ci c->node = node; 14958c2ecf20Sopenharmony_ci get_random_bytes(&c->key_gen, 2); 14968c2ecf20Sopenharmony_ci tipc_crypto_key_set_state(c, 0, 0, 0); 14978c2ecf20Sopenharmony_ci atomic_set(&c->key_distr, 0); 14988c2ecf20Sopenharmony_ci atomic_set(&c->peer_rx_active, 0); 14998c2ecf20Sopenharmony_ci atomic64_set(&c->sndnxt, 0); 15008c2ecf20Sopenharmony_ci c->timer1 = jiffies; 15018c2ecf20Sopenharmony_ci c->timer2 = jiffies; 15028c2ecf20Sopenharmony_ci c->rekeying_intv = TIPC_REKEYING_INTV_DEF; 15038c2ecf20Sopenharmony_ci spin_lock_init(&c->lock); 15048c2ecf20Sopenharmony_ci scnprintf(c->name, 48, "%s(%s)", (is_rx(c)) ? "RX" : "TX", 15058c2ecf20Sopenharmony_ci (is_rx(c)) ? tipc_node_get_id_str(c->node) : 15068c2ecf20Sopenharmony_ci tipc_own_id_string(c->net)); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci if (is_rx(c)) 15098c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&c->work, tipc_crypto_work_rx); 15108c2ecf20Sopenharmony_ci else 15118c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&c->work, tipc_crypto_work_tx); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci *crypto = c; 15148c2ecf20Sopenharmony_ci return 0; 15158c2ecf20Sopenharmony_ci} 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_civoid tipc_crypto_stop(struct tipc_crypto **crypto) 15188c2ecf20Sopenharmony_ci{ 15198c2ecf20Sopenharmony_ci struct tipc_crypto *c = *crypto; 15208c2ecf20Sopenharmony_ci u8 k; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci if (!c) 15238c2ecf20Sopenharmony_ci return; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci /* Flush any queued works & destroy wq */ 15268c2ecf20Sopenharmony_ci if (is_tx(c)) { 15278c2ecf20Sopenharmony_ci c->rekeying_intv = 0; 15288c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&c->work); 15298c2ecf20Sopenharmony_ci destroy_workqueue(c->wq); 15308c2ecf20Sopenharmony_ci } 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci /* Release AEAD keys */ 15338c2ecf20Sopenharmony_ci rcu_read_lock(); 15348c2ecf20Sopenharmony_ci for (k = KEY_MIN; k <= KEY_MAX; k++) 15358c2ecf20Sopenharmony_ci tipc_aead_put(rcu_dereference(c->aead[k])); 15368c2ecf20Sopenharmony_ci rcu_read_unlock(); 15378c2ecf20Sopenharmony_ci pr_debug("%s: has been stopped\n", c->name); 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci /* Free this crypto statistics */ 15408c2ecf20Sopenharmony_ci free_percpu(c->stats); 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci *crypto = NULL; 15438c2ecf20Sopenharmony_ci kfree_sensitive(c); 15448c2ecf20Sopenharmony_ci} 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_civoid tipc_crypto_timeout(struct tipc_crypto *rx) 15478c2ecf20Sopenharmony_ci{ 15488c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(rx->net); 15498c2ecf20Sopenharmony_ci struct tipc_crypto *tx = tn->crypto_tx; 15508c2ecf20Sopenharmony_ci struct tipc_key key; 15518c2ecf20Sopenharmony_ci int cmd; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci /* TX pending: taking all users & stable -> active */ 15548c2ecf20Sopenharmony_ci spin_lock(&tx->lock); 15558c2ecf20Sopenharmony_ci key = tx->key; 15568c2ecf20Sopenharmony_ci if (key.active && tipc_aead_users(tx->aead[key.active]) > 0) 15578c2ecf20Sopenharmony_ci goto s1; 15588c2ecf20Sopenharmony_ci if (!key.pending || tipc_aead_users(tx->aead[key.pending]) <= 0) 15598c2ecf20Sopenharmony_ci goto s1; 15608c2ecf20Sopenharmony_ci if (time_before(jiffies, tx->timer1 + TIPC_TX_LASTING_TIME)) 15618c2ecf20Sopenharmony_ci goto s1; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci tipc_crypto_key_set_state(tx, key.passive, key.pending, 0); 15648c2ecf20Sopenharmony_ci if (key.active) 15658c2ecf20Sopenharmony_ci tipc_crypto_key_detach(tx->aead[key.active], &tx->lock); 15668c2ecf20Sopenharmony_ci this_cpu_inc(tx->stats->stat[STAT_SWITCHES]); 15678c2ecf20Sopenharmony_ci pr_info("%s: key[%d] is activated\n", tx->name, key.pending); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_cis1: 15708c2ecf20Sopenharmony_ci spin_unlock(&tx->lock); 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci /* RX pending: having user -> active */ 15738c2ecf20Sopenharmony_ci spin_lock(&rx->lock); 15748c2ecf20Sopenharmony_ci key = rx->key; 15758c2ecf20Sopenharmony_ci if (!key.pending || tipc_aead_users(rx->aead[key.pending]) <= 0) 15768c2ecf20Sopenharmony_ci goto s2; 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci if (key.active) 15798c2ecf20Sopenharmony_ci key.passive = key.active; 15808c2ecf20Sopenharmony_ci key.active = key.pending; 15818c2ecf20Sopenharmony_ci rx->timer2 = jiffies; 15828c2ecf20Sopenharmony_ci tipc_crypto_key_set_state(rx, key.passive, key.active, 0); 15838c2ecf20Sopenharmony_ci this_cpu_inc(rx->stats->stat[STAT_SWITCHES]); 15848c2ecf20Sopenharmony_ci pr_info("%s: key[%d] is activated\n", rx->name, key.pending); 15858c2ecf20Sopenharmony_ci goto s5; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_cis2: 15888c2ecf20Sopenharmony_ci /* RX pending: not working -> remove */ 15898c2ecf20Sopenharmony_ci if (!key.pending || tipc_aead_users(rx->aead[key.pending]) > -10) 15908c2ecf20Sopenharmony_ci goto s3; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci tipc_crypto_key_set_state(rx, key.passive, key.active, 0); 15938c2ecf20Sopenharmony_ci tipc_crypto_key_detach(rx->aead[key.pending], &rx->lock); 15948c2ecf20Sopenharmony_ci pr_debug("%s: key[%d] is removed\n", rx->name, key.pending); 15958c2ecf20Sopenharmony_ci goto s5; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_cis3: 15988c2ecf20Sopenharmony_ci /* RX active: timed out or no user -> pending */ 15998c2ecf20Sopenharmony_ci if (!key.active) 16008c2ecf20Sopenharmony_ci goto s4; 16018c2ecf20Sopenharmony_ci if (time_before(jiffies, rx->timer1 + TIPC_RX_ACTIVE_LIM) && 16028c2ecf20Sopenharmony_ci tipc_aead_users(rx->aead[key.active]) > 0) 16038c2ecf20Sopenharmony_ci goto s4; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci if (key.pending) 16068c2ecf20Sopenharmony_ci key.passive = key.active; 16078c2ecf20Sopenharmony_ci else 16088c2ecf20Sopenharmony_ci key.pending = key.active; 16098c2ecf20Sopenharmony_ci rx->timer2 = jiffies; 16108c2ecf20Sopenharmony_ci tipc_crypto_key_set_state(rx, key.passive, 0, key.pending); 16118c2ecf20Sopenharmony_ci tipc_aead_users_set(rx->aead[key.pending], 0); 16128c2ecf20Sopenharmony_ci pr_debug("%s: key[%d] is deactivated\n", rx->name, key.active); 16138c2ecf20Sopenharmony_ci goto s5; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_cis4: 16168c2ecf20Sopenharmony_ci /* RX passive: outdated or not working -> free */ 16178c2ecf20Sopenharmony_ci if (!key.passive) 16188c2ecf20Sopenharmony_ci goto s5; 16198c2ecf20Sopenharmony_ci if (time_before(jiffies, rx->timer2 + TIPC_RX_PASSIVE_LIM) && 16208c2ecf20Sopenharmony_ci tipc_aead_users(rx->aead[key.passive]) > -10) 16218c2ecf20Sopenharmony_ci goto s5; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci tipc_crypto_key_set_state(rx, 0, key.active, key.pending); 16248c2ecf20Sopenharmony_ci tipc_crypto_key_detach(rx->aead[key.passive], &rx->lock); 16258c2ecf20Sopenharmony_ci pr_debug("%s: key[%d] is freed\n", rx->name, key.passive); 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_cis5: 16288c2ecf20Sopenharmony_ci spin_unlock(&rx->lock); 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci /* Relax it here, the flag will be set again if it really is, but only 16318c2ecf20Sopenharmony_ci * when we are not in grace period for safety! 16328c2ecf20Sopenharmony_ci */ 16338c2ecf20Sopenharmony_ci if (time_after(jiffies, tx->timer2 + TIPC_TX_GRACE_PERIOD)) 16348c2ecf20Sopenharmony_ci tx->legacy_user = 0; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci /* Limit max_tfms & do debug commands if needed */ 16378c2ecf20Sopenharmony_ci if (likely(sysctl_tipc_max_tfms <= TIPC_MAX_TFMS_LIM)) 16388c2ecf20Sopenharmony_ci return; 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci cmd = sysctl_tipc_max_tfms; 16418c2ecf20Sopenharmony_ci sysctl_tipc_max_tfms = TIPC_MAX_TFMS_DEF; 16428c2ecf20Sopenharmony_ci tipc_crypto_do_cmd(rx->net, cmd); 16438c2ecf20Sopenharmony_ci} 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_cistatic inline void tipc_crypto_clone_msg(struct net *net, struct sk_buff *_skb, 16468c2ecf20Sopenharmony_ci struct tipc_bearer *b, 16478c2ecf20Sopenharmony_ci struct tipc_media_addr *dst, 16488c2ecf20Sopenharmony_ci struct tipc_node *__dnode, u8 type) 16498c2ecf20Sopenharmony_ci{ 16508c2ecf20Sopenharmony_ci struct sk_buff *skb; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci skb = skb_clone(_skb, GFP_ATOMIC); 16538c2ecf20Sopenharmony_ci if (skb) { 16548c2ecf20Sopenharmony_ci TIPC_SKB_CB(skb)->xmit_type = type; 16558c2ecf20Sopenharmony_ci tipc_crypto_xmit(net, &skb, b, dst, __dnode); 16568c2ecf20Sopenharmony_ci if (skb) 16578c2ecf20Sopenharmony_ci b->media->send_msg(net, skb, b, dst); 16588c2ecf20Sopenharmony_ci } 16598c2ecf20Sopenharmony_ci} 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci/** 16628c2ecf20Sopenharmony_ci * tipc_crypto_xmit - Build & encrypt TIPC message for xmit 16638c2ecf20Sopenharmony_ci * @net: struct net 16648c2ecf20Sopenharmony_ci * @skb: input/output message skb pointer 16658c2ecf20Sopenharmony_ci * @b: bearer used for xmit later 16668c2ecf20Sopenharmony_ci * @dst: destination media address 16678c2ecf20Sopenharmony_ci * @__dnode: destination node for reference if any 16688c2ecf20Sopenharmony_ci * 16698c2ecf20Sopenharmony_ci * First, build an encryption message header on the top of the message, then 16708c2ecf20Sopenharmony_ci * encrypt the original TIPC message by using the pending, master or active 16718c2ecf20Sopenharmony_ci * key with this preference order. 16728c2ecf20Sopenharmony_ci * If the encryption is successful, the encrypted skb is returned directly or 16738c2ecf20Sopenharmony_ci * via the callback. 16748c2ecf20Sopenharmony_ci * Otherwise, the skb is freed! 16758c2ecf20Sopenharmony_ci * 16768c2ecf20Sopenharmony_ci * Return: 16778c2ecf20Sopenharmony_ci * 0 : the encryption has succeeded (or no encryption) 16788c2ecf20Sopenharmony_ci * -EINPROGRESS/-EBUSY : the encryption is ongoing, a callback will be made 16798c2ecf20Sopenharmony_ci * -ENOKEK : the encryption has failed due to no key 16808c2ecf20Sopenharmony_ci * -EKEYREVOKED : the encryption has failed due to key revoked 16818c2ecf20Sopenharmony_ci * -ENOMEM : the encryption has failed due to no memory 16828c2ecf20Sopenharmony_ci * < 0 : the encryption has failed due to other reasons 16838c2ecf20Sopenharmony_ci */ 16848c2ecf20Sopenharmony_ciint tipc_crypto_xmit(struct net *net, struct sk_buff **skb, 16858c2ecf20Sopenharmony_ci struct tipc_bearer *b, struct tipc_media_addr *dst, 16868c2ecf20Sopenharmony_ci struct tipc_node *__dnode) 16878c2ecf20Sopenharmony_ci{ 16888c2ecf20Sopenharmony_ci struct tipc_crypto *__rx = tipc_node_crypto_rx(__dnode); 16898c2ecf20Sopenharmony_ci struct tipc_crypto *tx = tipc_net(net)->crypto_tx; 16908c2ecf20Sopenharmony_ci struct tipc_crypto_stats __percpu *stats = tx->stats; 16918c2ecf20Sopenharmony_ci struct tipc_msg *hdr = buf_msg(*skb); 16928c2ecf20Sopenharmony_ci struct tipc_key key = tx->key; 16938c2ecf20Sopenharmony_ci struct tipc_aead *aead = NULL; 16948c2ecf20Sopenharmony_ci u32 user = msg_user(hdr); 16958c2ecf20Sopenharmony_ci u32 type = msg_type(hdr); 16968c2ecf20Sopenharmony_ci int rc = -ENOKEY; 16978c2ecf20Sopenharmony_ci u8 tx_key = 0; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci /* No encryption? */ 17008c2ecf20Sopenharmony_ci if (!tx->working) 17018c2ecf20Sopenharmony_ci return 0; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci /* Pending key if peer has active on it or probing time */ 17048c2ecf20Sopenharmony_ci if (unlikely(key.pending)) { 17058c2ecf20Sopenharmony_ci tx_key = key.pending; 17068c2ecf20Sopenharmony_ci if (!tx->key_master && !key.active) 17078c2ecf20Sopenharmony_ci goto encrypt; 17088c2ecf20Sopenharmony_ci if (__rx && atomic_read(&__rx->peer_rx_active) == tx_key) 17098c2ecf20Sopenharmony_ci goto encrypt; 17108c2ecf20Sopenharmony_ci if (TIPC_SKB_CB(*skb)->xmit_type == SKB_PROBING) { 17118c2ecf20Sopenharmony_ci pr_debug("%s: probing for key[%d]\n", tx->name, 17128c2ecf20Sopenharmony_ci key.pending); 17138c2ecf20Sopenharmony_ci goto encrypt; 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci if (user == LINK_CONFIG || user == LINK_PROTOCOL) 17168c2ecf20Sopenharmony_ci tipc_crypto_clone_msg(net, *skb, b, dst, __dnode, 17178c2ecf20Sopenharmony_ci SKB_PROBING); 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci /* Master key if this is a *vital* message or in grace period */ 17218c2ecf20Sopenharmony_ci if (tx->key_master) { 17228c2ecf20Sopenharmony_ci tx_key = KEY_MASTER; 17238c2ecf20Sopenharmony_ci if (!key.active) 17248c2ecf20Sopenharmony_ci goto encrypt; 17258c2ecf20Sopenharmony_ci if (TIPC_SKB_CB(*skb)->xmit_type == SKB_GRACING) { 17268c2ecf20Sopenharmony_ci pr_debug("%s: gracing for msg (%d %d)\n", tx->name, 17278c2ecf20Sopenharmony_ci user, type); 17288c2ecf20Sopenharmony_ci goto encrypt; 17298c2ecf20Sopenharmony_ci } 17308c2ecf20Sopenharmony_ci if (user == LINK_CONFIG || 17318c2ecf20Sopenharmony_ci (user == LINK_PROTOCOL && type == RESET_MSG) || 17328c2ecf20Sopenharmony_ci (user == MSG_CRYPTO && type == KEY_DISTR_MSG) || 17338c2ecf20Sopenharmony_ci time_before(jiffies, tx->timer2 + TIPC_TX_GRACE_PERIOD)) { 17348c2ecf20Sopenharmony_ci if (__rx && __rx->key_master && 17358c2ecf20Sopenharmony_ci !atomic_read(&__rx->peer_rx_active)) 17368c2ecf20Sopenharmony_ci goto encrypt; 17378c2ecf20Sopenharmony_ci if (!__rx) { 17388c2ecf20Sopenharmony_ci if (likely(!tx->legacy_user)) 17398c2ecf20Sopenharmony_ci goto encrypt; 17408c2ecf20Sopenharmony_ci tipc_crypto_clone_msg(net, *skb, b, dst, 17418c2ecf20Sopenharmony_ci __dnode, SKB_GRACING); 17428c2ecf20Sopenharmony_ci } 17438c2ecf20Sopenharmony_ci } 17448c2ecf20Sopenharmony_ci } 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci /* Else, use the active key if any */ 17478c2ecf20Sopenharmony_ci if (likely(key.active)) { 17488c2ecf20Sopenharmony_ci tx_key = key.active; 17498c2ecf20Sopenharmony_ci goto encrypt; 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci goto exit; 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ciencrypt: 17558c2ecf20Sopenharmony_ci aead = tipc_aead_get(tx->aead[tx_key]); 17568c2ecf20Sopenharmony_ci if (unlikely(!aead)) 17578c2ecf20Sopenharmony_ci goto exit; 17588c2ecf20Sopenharmony_ci rc = tipc_ehdr_build(net, aead, tx_key, *skb, __rx); 17598c2ecf20Sopenharmony_ci if (likely(rc > 0)) 17608c2ecf20Sopenharmony_ci rc = tipc_aead_encrypt(aead, *skb, b, dst, __dnode); 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ciexit: 17638c2ecf20Sopenharmony_ci switch (rc) { 17648c2ecf20Sopenharmony_ci case 0: 17658c2ecf20Sopenharmony_ci this_cpu_inc(stats->stat[STAT_OK]); 17668c2ecf20Sopenharmony_ci break; 17678c2ecf20Sopenharmony_ci case -EINPROGRESS: 17688c2ecf20Sopenharmony_ci case -EBUSY: 17698c2ecf20Sopenharmony_ci this_cpu_inc(stats->stat[STAT_ASYNC]); 17708c2ecf20Sopenharmony_ci *skb = NULL; 17718c2ecf20Sopenharmony_ci return rc; 17728c2ecf20Sopenharmony_ci default: 17738c2ecf20Sopenharmony_ci this_cpu_inc(stats->stat[STAT_NOK]); 17748c2ecf20Sopenharmony_ci if (rc == -ENOKEY) 17758c2ecf20Sopenharmony_ci this_cpu_inc(stats->stat[STAT_NOKEYS]); 17768c2ecf20Sopenharmony_ci else if (rc == -EKEYREVOKED) 17778c2ecf20Sopenharmony_ci this_cpu_inc(stats->stat[STAT_BADKEYS]); 17788c2ecf20Sopenharmony_ci kfree_skb(*skb); 17798c2ecf20Sopenharmony_ci *skb = NULL; 17808c2ecf20Sopenharmony_ci break; 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci tipc_aead_put(aead); 17848c2ecf20Sopenharmony_ci return rc; 17858c2ecf20Sopenharmony_ci} 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci/** 17888c2ecf20Sopenharmony_ci * tipc_crypto_rcv - Decrypt an encrypted TIPC message from peer 17898c2ecf20Sopenharmony_ci * @net: struct net 17908c2ecf20Sopenharmony_ci * @rx: RX crypto handle 17918c2ecf20Sopenharmony_ci * @skb: input/output message skb pointer 17928c2ecf20Sopenharmony_ci * @b: bearer where the message has been received 17938c2ecf20Sopenharmony_ci * 17948c2ecf20Sopenharmony_ci * If the decryption is successful, the decrypted skb is returned directly or 17958c2ecf20Sopenharmony_ci * as the callback, the encryption header and auth tag will be trimed out 17968c2ecf20Sopenharmony_ci * before forwarding to tipc_rcv() via the tipc_crypto_rcv_complete(). 17978c2ecf20Sopenharmony_ci * Otherwise, the skb will be freed! 17988c2ecf20Sopenharmony_ci * Note: RX key(s) can be re-aligned, or in case of no key suitable, TX 17998c2ecf20Sopenharmony_ci * cluster key(s) can be taken for decryption (- recursive). 18008c2ecf20Sopenharmony_ci * 18018c2ecf20Sopenharmony_ci * Return: 18028c2ecf20Sopenharmony_ci * 0 : the decryption has successfully completed 18038c2ecf20Sopenharmony_ci * -EINPROGRESS/-EBUSY : the decryption is ongoing, a callback will be made 18048c2ecf20Sopenharmony_ci * -ENOKEY : the decryption has failed due to no key 18058c2ecf20Sopenharmony_ci * -EBADMSG : the decryption has failed due to bad message 18068c2ecf20Sopenharmony_ci * -ENOMEM : the decryption has failed due to no memory 18078c2ecf20Sopenharmony_ci * < 0 : the decryption has failed due to other reasons 18088c2ecf20Sopenharmony_ci */ 18098c2ecf20Sopenharmony_ciint tipc_crypto_rcv(struct net *net, struct tipc_crypto *rx, 18108c2ecf20Sopenharmony_ci struct sk_buff **skb, struct tipc_bearer *b) 18118c2ecf20Sopenharmony_ci{ 18128c2ecf20Sopenharmony_ci struct tipc_crypto *tx = tipc_net(net)->crypto_tx; 18138c2ecf20Sopenharmony_ci struct tipc_crypto_stats __percpu *stats; 18148c2ecf20Sopenharmony_ci struct tipc_aead *aead = NULL; 18158c2ecf20Sopenharmony_ci struct tipc_key key; 18168c2ecf20Sopenharmony_ci int rc = -ENOKEY; 18178c2ecf20Sopenharmony_ci u8 tx_key, n; 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci tx_key = ((struct tipc_ehdr *)(*skb)->data)->tx_key; 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci /* New peer? 18228c2ecf20Sopenharmony_ci * Let's try with TX key (i.e. cluster mode) & verify the skb first! 18238c2ecf20Sopenharmony_ci */ 18248c2ecf20Sopenharmony_ci if (unlikely(!rx || tx_key == KEY_MASTER)) 18258c2ecf20Sopenharmony_ci goto pick_tx; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci /* Pick RX key according to TX key if any */ 18288c2ecf20Sopenharmony_ci key = rx->key; 18298c2ecf20Sopenharmony_ci if (tx_key == key.active || tx_key == key.pending || 18308c2ecf20Sopenharmony_ci tx_key == key.passive) 18318c2ecf20Sopenharmony_ci goto decrypt; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci /* Unknown key, let's try to align RX key(s) */ 18348c2ecf20Sopenharmony_ci if (tipc_crypto_key_try_align(rx, tx_key)) 18358c2ecf20Sopenharmony_ci goto decrypt; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_cipick_tx: 18388c2ecf20Sopenharmony_ci /* No key suitable? Try to pick one from TX... */ 18398c2ecf20Sopenharmony_ci aead = tipc_crypto_key_pick_tx(tx, rx, *skb, tx_key); 18408c2ecf20Sopenharmony_ci if (aead) 18418c2ecf20Sopenharmony_ci goto decrypt; 18428c2ecf20Sopenharmony_ci goto exit; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_cidecrypt: 18458c2ecf20Sopenharmony_ci rcu_read_lock(); 18468c2ecf20Sopenharmony_ci if (!aead) 18478c2ecf20Sopenharmony_ci aead = tipc_aead_get(rx->aead[tx_key]); 18488c2ecf20Sopenharmony_ci rc = tipc_aead_decrypt(net, aead, *skb, b); 18498c2ecf20Sopenharmony_ci rcu_read_unlock(); 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ciexit: 18528c2ecf20Sopenharmony_ci stats = ((rx) ?: tx)->stats; 18538c2ecf20Sopenharmony_ci switch (rc) { 18548c2ecf20Sopenharmony_ci case 0: 18558c2ecf20Sopenharmony_ci this_cpu_inc(stats->stat[STAT_OK]); 18568c2ecf20Sopenharmony_ci break; 18578c2ecf20Sopenharmony_ci case -EINPROGRESS: 18588c2ecf20Sopenharmony_ci case -EBUSY: 18598c2ecf20Sopenharmony_ci this_cpu_inc(stats->stat[STAT_ASYNC]); 18608c2ecf20Sopenharmony_ci *skb = NULL; 18618c2ecf20Sopenharmony_ci return rc; 18628c2ecf20Sopenharmony_ci default: 18638c2ecf20Sopenharmony_ci this_cpu_inc(stats->stat[STAT_NOK]); 18648c2ecf20Sopenharmony_ci if (rc == -ENOKEY) { 18658c2ecf20Sopenharmony_ci kfree_skb(*skb); 18668c2ecf20Sopenharmony_ci *skb = NULL; 18678c2ecf20Sopenharmony_ci if (rx) { 18688c2ecf20Sopenharmony_ci /* Mark rx->nokey only if we dont have a 18698c2ecf20Sopenharmony_ci * pending received session key, nor a newer 18708c2ecf20Sopenharmony_ci * one i.e. in the next slot. 18718c2ecf20Sopenharmony_ci */ 18728c2ecf20Sopenharmony_ci n = key_next(tx_key); 18738c2ecf20Sopenharmony_ci rx->nokey = !(rx->skey || 18748c2ecf20Sopenharmony_ci rcu_access_pointer(rx->aead[n])); 18758c2ecf20Sopenharmony_ci pr_debug_ratelimited("%s: nokey %d, key %d/%x\n", 18768c2ecf20Sopenharmony_ci rx->name, rx->nokey, 18778c2ecf20Sopenharmony_ci tx_key, rx->key.keys); 18788c2ecf20Sopenharmony_ci tipc_node_put(rx->node); 18798c2ecf20Sopenharmony_ci } 18808c2ecf20Sopenharmony_ci this_cpu_inc(stats->stat[STAT_NOKEYS]); 18818c2ecf20Sopenharmony_ci return rc; 18828c2ecf20Sopenharmony_ci } else if (rc == -EBADMSG) { 18838c2ecf20Sopenharmony_ci this_cpu_inc(stats->stat[STAT_BADMSGS]); 18848c2ecf20Sopenharmony_ci } 18858c2ecf20Sopenharmony_ci break; 18868c2ecf20Sopenharmony_ci } 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci tipc_crypto_rcv_complete(net, aead, b, skb, rc); 18898c2ecf20Sopenharmony_ci return rc; 18908c2ecf20Sopenharmony_ci} 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_cistatic void tipc_crypto_rcv_complete(struct net *net, struct tipc_aead *aead, 18938c2ecf20Sopenharmony_ci struct tipc_bearer *b, 18948c2ecf20Sopenharmony_ci struct sk_buff **skb, int err) 18958c2ecf20Sopenharmony_ci{ 18968c2ecf20Sopenharmony_ci struct tipc_skb_cb *skb_cb = TIPC_SKB_CB(*skb); 18978c2ecf20Sopenharmony_ci struct tipc_crypto *rx = aead->crypto; 18988c2ecf20Sopenharmony_ci struct tipc_aead *tmp = NULL; 18998c2ecf20Sopenharmony_ci struct tipc_ehdr *ehdr; 19008c2ecf20Sopenharmony_ci struct tipc_node *n; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci /* Is this completed by TX? */ 19038c2ecf20Sopenharmony_ci if (unlikely(is_tx(aead->crypto))) { 19048c2ecf20Sopenharmony_ci rx = skb_cb->tx_clone_ctx.rx; 19058c2ecf20Sopenharmony_ci pr_debug("TX->RX(%s): err %d, aead %p, skb->next %p, flags %x\n", 19068c2ecf20Sopenharmony_ci (rx) ? tipc_node_get_id_str(rx->node) : "-", err, aead, 19078c2ecf20Sopenharmony_ci (*skb)->next, skb_cb->flags); 19088c2ecf20Sopenharmony_ci pr_debug("skb_cb [recurs %d, last %p], tx->aead [%p %p %p]\n", 19098c2ecf20Sopenharmony_ci skb_cb->tx_clone_ctx.recurs, skb_cb->tx_clone_ctx.last, 19108c2ecf20Sopenharmony_ci aead->crypto->aead[1], aead->crypto->aead[2], 19118c2ecf20Sopenharmony_ci aead->crypto->aead[3]); 19128c2ecf20Sopenharmony_ci if (unlikely(err)) { 19138c2ecf20Sopenharmony_ci if (err == -EBADMSG && (*skb)->next) 19148c2ecf20Sopenharmony_ci tipc_rcv(net, (*skb)->next, b); 19158c2ecf20Sopenharmony_ci goto free_skb; 19168c2ecf20Sopenharmony_ci } 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci if (likely((*skb)->next)) { 19198c2ecf20Sopenharmony_ci kfree_skb((*skb)->next); 19208c2ecf20Sopenharmony_ci (*skb)->next = NULL; 19218c2ecf20Sopenharmony_ci } 19228c2ecf20Sopenharmony_ci ehdr = (struct tipc_ehdr *)(*skb)->data; 19238c2ecf20Sopenharmony_ci if (!rx) { 19248c2ecf20Sopenharmony_ci WARN_ON(ehdr->user != LINK_CONFIG); 19258c2ecf20Sopenharmony_ci n = tipc_node_create(net, 0, ehdr->id, 0xffffu, 0, 19268c2ecf20Sopenharmony_ci true); 19278c2ecf20Sopenharmony_ci rx = tipc_node_crypto_rx(n); 19288c2ecf20Sopenharmony_ci if (unlikely(!rx)) 19298c2ecf20Sopenharmony_ci goto free_skb; 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci /* Ignore cloning if it was TX master key */ 19338c2ecf20Sopenharmony_ci if (ehdr->tx_key == KEY_MASTER) 19348c2ecf20Sopenharmony_ci goto rcv; 19358c2ecf20Sopenharmony_ci if (tipc_aead_clone(&tmp, aead) < 0) 19368c2ecf20Sopenharmony_ci goto rcv; 19378c2ecf20Sopenharmony_ci WARN_ON(!refcount_inc_not_zero(&tmp->refcnt)); 19388c2ecf20Sopenharmony_ci if (tipc_crypto_key_attach(rx, tmp, ehdr->tx_key, false) < 0) { 19398c2ecf20Sopenharmony_ci tipc_aead_free(&tmp->rcu); 19408c2ecf20Sopenharmony_ci goto rcv; 19418c2ecf20Sopenharmony_ci } 19428c2ecf20Sopenharmony_ci tipc_aead_put(aead); 19438c2ecf20Sopenharmony_ci aead = tmp; 19448c2ecf20Sopenharmony_ci } 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci if (unlikely(err)) { 19478c2ecf20Sopenharmony_ci tipc_aead_users_dec(aead, INT_MIN); 19488c2ecf20Sopenharmony_ci goto free_skb; 19498c2ecf20Sopenharmony_ci } 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci /* Set the RX key's user */ 19528c2ecf20Sopenharmony_ci tipc_aead_users_set(aead, 1); 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci /* Mark this point, RX works */ 19558c2ecf20Sopenharmony_ci rx->timer1 = jiffies; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_circv: 19588c2ecf20Sopenharmony_ci /* Remove ehdr & auth. tag prior to tipc_rcv() */ 19598c2ecf20Sopenharmony_ci ehdr = (struct tipc_ehdr *)(*skb)->data; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci /* Mark this point, RX passive still works */ 19628c2ecf20Sopenharmony_ci if (rx->key.passive && ehdr->tx_key == rx->key.passive) 19638c2ecf20Sopenharmony_ci rx->timer2 = jiffies; 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci skb_reset_network_header(*skb); 19668c2ecf20Sopenharmony_ci skb_pull(*skb, tipc_ehdr_size(ehdr)); 19678c2ecf20Sopenharmony_ci if (pskb_trim(*skb, (*skb)->len - aead->authsize)) 19688c2ecf20Sopenharmony_ci goto free_skb; 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci /* Validate TIPCv2 message */ 19718c2ecf20Sopenharmony_ci if (unlikely(!tipc_msg_validate(skb))) { 19728c2ecf20Sopenharmony_ci pr_err_ratelimited("Packet dropped after decryption!\n"); 19738c2ecf20Sopenharmony_ci goto free_skb; 19748c2ecf20Sopenharmony_ci } 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci /* Ok, everything's fine, try to synch own keys according to peers' */ 19778c2ecf20Sopenharmony_ci tipc_crypto_key_synch(rx, *skb); 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci /* Re-fetch skb cb as skb might be changed in tipc_msg_validate */ 19808c2ecf20Sopenharmony_ci skb_cb = TIPC_SKB_CB(*skb); 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci /* Mark skb decrypted */ 19838c2ecf20Sopenharmony_ci skb_cb->decrypted = 1; 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci /* Clear clone cxt if any */ 19868c2ecf20Sopenharmony_ci if (likely(!skb_cb->tx_clone_deferred)) 19878c2ecf20Sopenharmony_ci goto exit; 19888c2ecf20Sopenharmony_ci skb_cb->tx_clone_deferred = 0; 19898c2ecf20Sopenharmony_ci memset(&skb_cb->tx_clone_ctx, 0, sizeof(skb_cb->tx_clone_ctx)); 19908c2ecf20Sopenharmony_ci goto exit; 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_cifree_skb: 19938c2ecf20Sopenharmony_ci kfree_skb(*skb); 19948c2ecf20Sopenharmony_ci *skb = NULL; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ciexit: 19978c2ecf20Sopenharmony_ci tipc_aead_put(aead); 19988c2ecf20Sopenharmony_ci if (rx) 19998c2ecf20Sopenharmony_ci tipc_node_put(rx->node); 20008c2ecf20Sopenharmony_ci} 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_cistatic void tipc_crypto_do_cmd(struct net *net, int cmd) 20038c2ecf20Sopenharmony_ci{ 20048c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 20058c2ecf20Sopenharmony_ci struct tipc_crypto *tx = tn->crypto_tx, *rx; 20068c2ecf20Sopenharmony_ci struct list_head *p; 20078c2ecf20Sopenharmony_ci unsigned int stat; 20088c2ecf20Sopenharmony_ci int i, j, cpu; 20098c2ecf20Sopenharmony_ci char buf[200]; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci /* Currently only one command is supported */ 20128c2ecf20Sopenharmony_ci switch (cmd) { 20138c2ecf20Sopenharmony_ci case 0xfff1: 20148c2ecf20Sopenharmony_ci goto print_stats; 20158c2ecf20Sopenharmony_ci default: 20168c2ecf20Sopenharmony_ci return; 20178c2ecf20Sopenharmony_ci } 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ciprint_stats: 20208c2ecf20Sopenharmony_ci /* Print a header */ 20218c2ecf20Sopenharmony_ci pr_info("\n=============== TIPC Crypto Statistics ===============\n\n"); 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci /* Print key status */ 20248c2ecf20Sopenharmony_ci pr_info("Key status:\n"); 20258c2ecf20Sopenharmony_ci pr_info("TX(%7.7s)\n%s", tipc_own_id_string(net), 20268c2ecf20Sopenharmony_ci tipc_crypto_key_dump(tx, buf)); 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci rcu_read_lock(); 20298c2ecf20Sopenharmony_ci for (p = tn->node_list.next; p != &tn->node_list; p = p->next) { 20308c2ecf20Sopenharmony_ci rx = tipc_node_crypto_rx_by_list(p); 20318c2ecf20Sopenharmony_ci pr_info("RX(%7.7s)\n%s", tipc_node_get_id_str(rx->node), 20328c2ecf20Sopenharmony_ci tipc_crypto_key_dump(rx, buf)); 20338c2ecf20Sopenharmony_ci } 20348c2ecf20Sopenharmony_ci rcu_read_unlock(); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci /* Print crypto statistics */ 20378c2ecf20Sopenharmony_ci for (i = 0, j = 0; i < MAX_STATS; i++) 20388c2ecf20Sopenharmony_ci j += scnprintf(buf + j, 200 - j, "|%11s ", hstats[i]); 20398c2ecf20Sopenharmony_ci pr_info("Counter %s", buf); 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci memset(buf, '-', 115); 20428c2ecf20Sopenharmony_ci buf[115] = '\0'; 20438c2ecf20Sopenharmony_ci pr_info("%s\n", buf); 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci j = scnprintf(buf, 200, "TX(%7.7s) ", tipc_own_id_string(net)); 20468c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 20478c2ecf20Sopenharmony_ci for (i = 0; i < MAX_STATS; i++) { 20488c2ecf20Sopenharmony_ci stat = per_cpu_ptr(tx->stats, cpu)->stat[i]; 20498c2ecf20Sopenharmony_ci j += scnprintf(buf + j, 200 - j, "|%11d ", stat); 20508c2ecf20Sopenharmony_ci } 20518c2ecf20Sopenharmony_ci pr_info("%s", buf); 20528c2ecf20Sopenharmony_ci j = scnprintf(buf, 200, "%12s", " "); 20538c2ecf20Sopenharmony_ci } 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci rcu_read_lock(); 20568c2ecf20Sopenharmony_ci for (p = tn->node_list.next; p != &tn->node_list; p = p->next) { 20578c2ecf20Sopenharmony_ci rx = tipc_node_crypto_rx_by_list(p); 20588c2ecf20Sopenharmony_ci j = scnprintf(buf, 200, "RX(%7.7s) ", 20598c2ecf20Sopenharmony_ci tipc_node_get_id_str(rx->node)); 20608c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 20618c2ecf20Sopenharmony_ci for (i = 0; i < MAX_STATS; i++) { 20628c2ecf20Sopenharmony_ci stat = per_cpu_ptr(rx->stats, cpu)->stat[i]; 20638c2ecf20Sopenharmony_ci j += scnprintf(buf + j, 200 - j, "|%11d ", 20648c2ecf20Sopenharmony_ci stat); 20658c2ecf20Sopenharmony_ci } 20668c2ecf20Sopenharmony_ci pr_info("%s", buf); 20678c2ecf20Sopenharmony_ci j = scnprintf(buf, 200, "%12s", " "); 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci } 20708c2ecf20Sopenharmony_ci rcu_read_unlock(); 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci pr_info("\n======================== Done ========================\n"); 20738c2ecf20Sopenharmony_ci} 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_cistatic char *tipc_crypto_key_dump(struct tipc_crypto *c, char *buf) 20768c2ecf20Sopenharmony_ci{ 20778c2ecf20Sopenharmony_ci struct tipc_key key = c->key; 20788c2ecf20Sopenharmony_ci struct tipc_aead *aead; 20798c2ecf20Sopenharmony_ci int k, i = 0; 20808c2ecf20Sopenharmony_ci char *s; 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci for (k = KEY_MIN; k <= KEY_MAX; k++) { 20838c2ecf20Sopenharmony_ci if (k == KEY_MASTER) { 20848c2ecf20Sopenharmony_ci if (is_rx(c)) 20858c2ecf20Sopenharmony_ci continue; 20868c2ecf20Sopenharmony_ci if (time_before(jiffies, 20878c2ecf20Sopenharmony_ci c->timer2 + TIPC_TX_GRACE_PERIOD)) 20888c2ecf20Sopenharmony_ci s = "ACT"; 20898c2ecf20Sopenharmony_ci else 20908c2ecf20Sopenharmony_ci s = "PAS"; 20918c2ecf20Sopenharmony_ci } else { 20928c2ecf20Sopenharmony_ci if (k == key.passive) 20938c2ecf20Sopenharmony_ci s = "PAS"; 20948c2ecf20Sopenharmony_ci else if (k == key.active) 20958c2ecf20Sopenharmony_ci s = "ACT"; 20968c2ecf20Sopenharmony_ci else if (k == key.pending) 20978c2ecf20Sopenharmony_ci s = "PEN"; 20988c2ecf20Sopenharmony_ci else 20998c2ecf20Sopenharmony_ci s = "-"; 21008c2ecf20Sopenharmony_ci } 21018c2ecf20Sopenharmony_ci i += scnprintf(buf + i, 200 - i, "\tKey%d: %s", k, s); 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci rcu_read_lock(); 21048c2ecf20Sopenharmony_ci aead = rcu_dereference(c->aead[k]); 21058c2ecf20Sopenharmony_ci if (aead) 21068c2ecf20Sopenharmony_ci i += scnprintf(buf + i, 200 - i, 21078c2ecf20Sopenharmony_ci "{\"0x...%s\", \"%s\"}/%d:%d", 21088c2ecf20Sopenharmony_ci aead->hint, 21098c2ecf20Sopenharmony_ci (aead->mode == CLUSTER_KEY) ? "c" : "p", 21108c2ecf20Sopenharmony_ci atomic_read(&aead->users), 21118c2ecf20Sopenharmony_ci refcount_read(&aead->refcnt)); 21128c2ecf20Sopenharmony_ci rcu_read_unlock(); 21138c2ecf20Sopenharmony_ci i += scnprintf(buf + i, 200 - i, "\n"); 21148c2ecf20Sopenharmony_ci } 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci if (is_rx(c)) 21178c2ecf20Sopenharmony_ci i += scnprintf(buf + i, 200 - i, "\tPeer RX active: %d\n", 21188c2ecf20Sopenharmony_ci atomic_read(&c->peer_rx_active)); 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci return buf; 21218c2ecf20Sopenharmony_ci} 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_cistatic char *tipc_key_change_dump(struct tipc_key old, struct tipc_key new, 21248c2ecf20Sopenharmony_ci char *buf) 21258c2ecf20Sopenharmony_ci{ 21268c2ecf20Sopenharmony_ci struct tipc_key *key = &old; 21278c2ecf20Sopenharmony_ci int k, i = 0; 21288c2ecf20Sopenharmony_ci char *s; 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci /* Output format: "[%s %s %s] -> [%s %s %s]", max len = 32 */ 21318c2ecf20Sopenharmony_ciagain: 21328c2ecf20Sopenharmony_ci i += scnprintf(buf + i, 32 - i, "["); 21338c2ecf20Sopenharmony_ci for (k = KEY_1; k <= KEY_3; k++) { 21348c2ecf20Sopenharmony_ci if (k == key->passive) 21358c2ecf20Sopenharmony_ci s = "pas"; 21368c2ecf20Sopenharmony_ci else if (k == key->active) 21378c2ecf20Sopenharmony_ci s = "act"; 21388c2ecf20Sopenharmony_ci else if (k == key->pending) 21398c2ecf20Sopenharmony_ci s = "pen"; 21408c2ecf20Sopenharmony_ci else 21418c2ecf20Sopenharmony_ci s = "-"; 21428c2ecf20Sopenharmony_ci i += scnprintf(buf + i, 32 - i, 21438c2ecf20Sopenharmony_ci (k != KEY_3) ? "%s " : "%s", s); 21448c2ecf20Sopenharmony_ci } 21458c2ecf20Sopenharmony_ci if (key != &new) { 21468c2ecf20Sopenharmony_ci i += scnprintf(buf + i, 32 - i, "] -> "); 21478c2ecf20Sopenharmony_ci key = &new; 21488c2ecf20Sopenharmony_ci goto again; 21498c2ecf20Sopenharmony_ci } 21508c2ecf20Sopenharmony_ci i += scnprintf(buf + i, 32 - i, "]"); 21518c2ecf20Sopenharmony_ci return buf; 21528c2ecf20Sopenharmony_ci} 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci/** 21558c2ecf20Sopenharmony_ci * tipc_crypto_msg_rcv - Common 'MSG_CRYPTO' processing point 21568c2ecf20Sopenharmony_ci * @net: the struct net 21578c2ecf20Sopenharmony_ci * @skb: the receiving message buffer 21588c2ecf20Sopenharmony_ci */ 21598c2ecf20Sopenharmony_civoid tipc_crypto_msg_rcv(struct net *net, struct sk_buff *skb) 21608c2ecf20Sopenharmony_ci{ 21618c2ecf20Sopenharmony_ci struct tipc_crypto *rx; 21628c2ecf20Sopenharmony_ci struct tipc_msg *hdr; 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci if (unlikely(skb_linearize(skb))) 21658c2ecf20Sopenharmony_ci goto exit; 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci hdr = buf_msg(skb); 21688c2ecf20Sopenharmony_ci rx = tipc_node_crypto_rx_by_addr(net, msg_prevnode(hdr)); 21698c2ecf20Sopenharmony_ci if (unlikely(!rx)) 21708c2ecf20Sopenharmony_ci goto exit; 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci switch (msg_type(hdr)) { 21738c2ecf20Sopenharmony_ci case KEY_DISTR_MSG: 21748c2ecf20Sopenharmony_ci if (tipc_crypto_key_rcv(rx, hdr)) 21758c2ecf20Sopenharmony_ci goto exit; 21768c2ecf20Sopenharmony_ci break; 21778c2ecf20Sopenharmony_ci default: 21788c2ecf20Sopenharmony_ci break; 21798c2ecf20Sopenharmony_ci } 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci tipc_node_put(rx->node); 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ciexit: 21848c2ecf20Sopenharmony_ci kfree_skb(skb); 21858c2ecf20Sopenharmony_ci} 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci/** 21888c2ecf20Sopenharmony_ci * tipc_crypto_key_distr - Distribute a TX key 21898c2ecf20Sopenharmony_ci * @tx: the TX crypto 21908c2ecf20Sopenharmony_ci * @key: the key's index 21918c2ecf20Sopenharmony_ci * @dest: the destination tipc node, = NULL if distributing to all nodes 21928c2ecf20Sopenharmony_ci * 21938c2ecf20Sopenharmony_ci * Return: 0 in case of success, otherwise < 0 21948c2ecf20Sopenharmony_ci */ 21958c2ecf20Sopenharmony_ciint tipc_crypto_key_distr(struct tipc_crypto *tx, u8 key, 21968c2ecf20Sopenharmony_ci struct tipc_node *dest) 21978c2ecf20Sopenharmony_ci{ 21988c2ecf20Sopenharmony_ci struct tipc_aead *aead; 21998c2ecf20Sopenharmony_ci u32 dnode = tipc_node_get_addr(dest); 22008c2ecf20Sopenharmony_ci int rc = -ENOKEY; 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci if (!sysctl_tipc_key_exchange_enabled) 22038c2ecf20Sopenharmony_ci return 0; 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci if (key) { 22068c2ecf20Sopenharmony_ci rcu_read_lock(); 22078c2ecf20Sopenharmony_ci aead = tipc_aead_get(tx->aead[key]); 22088c2ecf20Sopenharmony_ci if (likely(aead)) { 22098c2ecf20Sopenharmony_ci rc = tipc_crypto_key_xmit(tx->net, aead->key, 22108c2ecf20Sopenharmony_ci aead->gen, aead->mode, 22118c2ecf20Sopenharmony_ci dnode); 22128c2ecf20Sopenharmony_ci tipc_aead_put(aead); 22138c2ecf20Sopenharmony_ci } 22148c2ecf20Sopenharmony_ci rcu_read_unlock(); 22158c2ecf20Sopenharmony_ci } 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci return rc; 22188c2ecf20Sopenharmony_ci} 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci/** 22218c2ecf20Sopenharmony_ci * tipc_crypto_key_xmit - Send a session key 22228c2ecf20Sopenharmony_ci * @net: the struct net 22238c2ecf20Sopenharmony_ci * @skey: the session key to be sent 22248c2ecf20Sopenharmony_ci * @gen: the key's generation 22258c2ecf20Sopenharmony_ci * @mode: the key's mode 22268c2ecf20Sopenharmony_ci * @dnode: the destination node address, = 0 if broadcasting to all nodes 22278c2ecf20Sopenharmony_ci * 22288c2ecf20Sopenharmony_ci * The session key 'skey' is packed in a TIPC v2 'MSG_CRYPTO/KEY_DISTR_MSG' 22298c2ecf20Sopenharmony_ci * as its data section, then xmit-ed through the uc/bc link. 22308c2ecf20Sopenharmony_ci * 22318c2ecf20Sopenharmony_ci * Return: 0 in case of success, otherwise < 0 22328c2ecf20Sopenharmony_ci */ 22338c2ecf20Sopenharmony_cistatic int tipc_crypto_key_xmit(struct net *net, struct tipc_aead_key *skey, 22348c2ecf20Sopenharmony_ci u16 gen, u8 mode, u32 dnode) 22358c2ecf20Sopenharmony_ci{ 22368c2ecf20Sopenharmony_ci struct sk_buff_head pkts; 22378c2ecf20Sopenharmony_ci struct tipc_msg *hdr; 22388c2ecf20Sopenharmony_ci struct sk_buff *skb; 22398c2ecf20Sopenharmony_ci u16 size, cong_link_cnt; 22408c2ecf20Sopenharmony_ci u8 *data; 22418c2ecf20Sopenharmony_ci int rc; 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci size = tipc_aead_key_size(skey); 22448c2ecf20Sopenharmony_ci skb = tipc_buf_acquire(INT_H_SIZE + size, GFP_ATOMIC); 22458c2ecf20Sopenharmony_ci if (!skb) 22468c2ecf20Sopenharmony_ci return -ENOMEM; 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci hdr = buf_msg(skb); 22498c2ecf20Sopenharmony_ci tipc_msg_init(tipc_own_addr(net), hdr, MSG_CRYPTO, KEY_DISTR_MSG, 22508c2ecf20Sopenharmony_ci INT_H_SIZE, dnode); 22518c2ecf20Sopenharmony_ci msg_set_size(hdr, INT_H_SIZE + size); 22528c2ecf20Sopenharmony_ci msg_set_key_gen(hdr, gen); 22538c2ecf20Sopenharmony_ci msg_set_key_mode(hdr, mode); 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci data = msg_data(hdr); 22568c2ecf20Sopenharmony_ci *((__be32 *)(data + TIPC_AEAD_ALG_NAME)) = htonl(skey->keylen); 22578c2ecf20Sopenharmony_ci memcpy(data, skey->alg_name, TIPC_AEAD_ALG_NAME); 22588c2ecf20Sopenharmony_ci memcpy(data + TIPC_AEAD_ALG_NAME + sizeof(__be32), skey->key, 22598c2ecf20Sopenharmony_ci skey->keylen); 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci __skb_queue_head_init(&pkts); 22628c2ecf20Sopenharmony_ci __skb_queue_tail(&pkts, skb); 22638c2ecf20Sopenharmony_ci if (dnode) 22648c2ecf20Sopenharmony_ci rc = tipc_node_xmit(net, &pkts, dnode, 0); 22658c2ecf20Sopenharmony_ci else 22668c2ecf20Sopenharmony_ci rc = tipc_bcast_xmit(net, &pkts, &cong_link_cnt); 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci return rc; 22698c2ecf20Sopenharmony_ci} 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci/** 22728c2ecf20Sopenharmony_ci * tipc_crypto_key_rcv - Receive a session key 22738c2ecf20Sopenharmony_ci * @rx: the RX crypto 22748c2ecf20Sopenharmony_ci * @hdr: the TIPC v2 message incl. the receiving session key in its data 22758c2ecf20Sopenharmony_ci * 22768c2ecf20Sopenharmony_ci * This function retrieves the session key in the message from peer, then 22778c2ecf20Sopenharmony_ci * schedules a RX work to attach the key to the corresponding RX crypto. 22788c2ecf20Sopenharmony_ci * 22798c2ecf20Sopenharmony_ci * Return: "true" if the key has been scheduled for attaching, otherwise 22808c2ecf20Sopenharmony_ci * "false". 22818c2ecf20Sopenharmony_ci */ 22828c2ecf20Sopenharmony_cistatic bool tipc_crypto_key_rcv(struct tipc_crypto *rx, struct tipc_msg *hdr) 22838c2ecf20Sopenharmony_ci{ 22848c2ecf20Sopenharmony_ci struct tipc_crypto *tx = tipc_net(rx->net)->crypto_tx; 22858c2ecf20Sopenharmony_ci struct tipc_aead_key *skey = NULL; 22868c2ecf20Sopenharmony_ci u16 key_gen = msg_key_gen(hdr); 22878c2ecf20Sopenharmony_ci u32 size = msg_data_sz(hdr); 22888c2ecf20Sopenharmony_ci u8 *data = msg_data(hdr); 22898c2ecf20Sopenharmony_ci unsigned int keylen; 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci /* Verify whether the size can exist in the packet */ 22928c2ecf20Sopenharmony_ci if (unlikely(size < sizeof(struct tipc_aead_key) + TIPC_AEAD_KEYLEN_MIN)) { 22938c2ecf20Sopenharmony_ci pr_debug("%s: message data size is too small\n", rx->name); 22948c2ecf20Sopenharmony_ci goto exit; 22958c2ecf20Sopenharmony_ci } 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci keylen = ntohl(*((__be32 *)(data + TIPC_AEAD_ALG_NAME))); 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci /* Verify the supplied size values */ 23008c2ecf20Sopenharmony_ci if (unlikely(size != keylen + sizeof(struct tipc_aead_key) || 23018c2ecf20Sopenharmony_ci keylen > TIPC_AEAD_KEY_SIZE_MAX)) { 23028c2ecf20Sopenharmony_ci pr_debug("%s: invalid MSG_CRYPTO key size\n", rx->name); 23038c2ecf20Sopenharmony_ci goto exit; 23048c2ecf20Sopenharmony_ci } 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci spin_lock(&rx->lock); 23078c2ecf20Sopenharmony_ci if (unlikely(rx->skey || (key_gen == rx->key_gen && rx->key.keys))) { 23088c2ecf20Sopenharmony_ci pr_err("%s: key existed <%p>, gen %d vs %d\n", rx->name, 23098c2ecf20Sopenharmony_ci rx->skey, key_gen, rx->key_gen); 23108c2ecf20Sopenharmony_ci goto exit_unlock; 23118c2ecf20Sopenharmony_ci } 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci /* Allocate memory for the key */ 23148c2ecf20Sopenharmony_ci skey = kmalloc(size, GFP_ATOMIC); 23158c2ecf20Sopenharmony_ci if (unlikely(!skey)) { 23168c2ecf20Sopenharmony_ci pr_err("%s: unable to allocate memory for skey\n", rx->name); 23178c2ecf20Sopenharmony_ci goto exit_unlock; 23188c2ecf20Sopenharmony_ci } 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci /* Copy key from msg data */ 23218c2ecf20Sopenharmony_ci skey->keylen = keylen; 23228c2ecf20Sopenharmony_ci memcpy(skey->alg_name, data, TIPC_AEAD_ALG_NAME); 23238c2ecf20Sopenharmony_ci memcpy(skey->key, data + TIPC_AEAD_ALG_NAME + sizeof(__be32), 23248c2ecf20Sopenharmony_ci skey->keylen); 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci rx->key_gen = key_gen; 23278c2ecf20Sopenharmony_ci rx->skey_mode = msg_key_mode(hdr); 23288c2ecf20Sopenharmony_ci rx->skey = skey; 23298c2ecf20Sopenharmony_ci rx->nokey = 0; 23308c2ecf20Sopenharmony_ci mb(); /* for nokey flag */ 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ciexit_unlock: 23338c2ecf20Sopenharmony_ci spin_unlock(&rx->lock); 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ciexit: 23368c2ecf20Sopenharmony_ci /* Schedule the key attaching on this crypto */ 23378c2ecf20Sopenharmony_ci if (likely(skey && queue_delayed_work(tx->wq, &rx->work, 0))) 23388c2ecf20Sopenharmony_ci return true; 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci return false; 23418c2ecf20Sopenharmony_ci} 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci/** 23448c2ecf20Sopenharmony_ci * tipc_crypto_work_rx - Scheduled RX works handler 23458c2ecf20Sopenharmony_ci * @work: the struct RX work 23468c2ecf20Sopenharmony_ci * 23478c2ecf20Sopenharmony_ci * The function processes the previous scheduled works i.e. distributing TX key 23488c2ecf20Sopenharmony_ci * or attaching a received session key on RX crypto. 23498c2ecf20Sopenharmony_ci */ 23508c2ecf20Sopenharmony_cistatic void tipc_crypto_work_rx(struct work_struct *work) 23518c2ecf20Sopenharmony_ci{ 23528c2ecf20Sopenharmony_ci struct delayed_work *dwork = to_delayed_work(work); 23538c2ecf20Sopenharmony_ci struct tipc_crypto *rx = container_of(dwork, struct tipc_crypto, work); 23548c2ecf20Sopenharmony_ci struct tipc_crypto *tx = tipc_net(rx->net)->crypto_tx; 23558c2ecf20Sopenharmony_ci unsigned long delay = msecs_to_jiffies(5000); 23568c2ecf20Sopenharmony_ci bool resched = false; 23578c2ecf20Sopenharmony_ci u8 key; 23588c2ecf20Sopenharmony_ci int rc; 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci /* Case 1: Distribute TX key to peer if scheduled */ 23618c2ecf20Sopenharmony_ci if (atomic_cmpxchg(&rx->key_distr, 23628c2ecf20Sopenharmony_ci KEY_DISTR_SCHED, 23638c2ecf20Sopenharmony_ci KEY_DISTR_COMPL) == KEY_DISTR_SCHED) { 23648c2ecf20Sopenharmony_ci /* Always pick the newest one for distributing */ 23658c2ecf20Sopenharmony_ci key = tx->key.pending ?: tx->key.active; 23668c2ecf20Sopenharmony_ci rc = tipc_crypto_key_distr(tx, key, rx->node); 23678c2ecf20Sopenharmony_ci if (unlikely(rc)) 23688c2ecf20Sopenharmony_ci pr_warn("%s: unable to distr key[%d] to %s, err %d\n", 23698c2ecf20Sopenharmony_ci tx->name, key, tipc_node_get_id_str(rx->node), 23708c2ecf20Sopenharmony_ci rc); 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci /* Sched for key_distr releasing */ 23738c2ecf20Sopenharmony_ci resched = true; 23748c2ecf20Sopenharmony_ci } else { 23758c2ecf20Sopenharmony_ci atomic_cmpxchg(&rx->key_distr, KEY_DISTR_COMPL, 0); 23768c2ecf20Sopenharmony_ci } 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci /* Case 2: Attach a pending received session key from peer if any */ 23798c2ecf20Sopenharmony_ci if (rx->skey) { 23808c2ecf20Sopenharmony_ci rc = tipc_crypto_key_init(rx, rx->skey, rx->skey_mode, false); 23818c2ecf20Sopenharmony_ci if (unlikely(rc < 0)) 23828c2ecf20Sopenharmony_ci pr_warn("%s: unable to attach received skey, err %d\n", 23838c2ecf20Sopenharmony_ci rx->name, rc); 23848c2ecf20Sopenharmony_ci switch (rc) { 23858c2ecf20Sopenharmony_ci case -EBUSY: 23868c2ecf20Sopenharmony_ci case -ENOMEM: 23878c2ecf20Sopenharmony_ci /* Resched the key attaching */ 23888c2ecf20Sopenharmony_ci resched = true; 23898c2ecf20Sopenharmony_ci break; 23908c2ecf20Sopenharmony_ci default: 23918c2ecf20Sopenharmony_ci synchronize_rcu(); 23928c2ecf20Sopenharmony_ci kfree(rx->skey); 23938c2ecf20Sopenharmony_ci rx->skey = NULL; 23948c2ecf20Sopenharmony_ci break; 23958c2ecf20Sopenharmony_ci } 23968c2ecf20Sopenharmony_ci } 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci if (resched && queue_delayed_work(tx->wq, &rx->work, delay)) 23998c2ecf20Sopenharmony_ci return; 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci tipc_node_put(rx->node); 24028c2ecf20Sopenharmony_ci} 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci/** 24058c2ecf20Sopenharmony_ci * tipc_crypto_rekeying_sched - (Re)schedule rekeying w/o new interval 24068c2ecf20Sopenharmony_ci * @tx: TX crypto 24078c2ecf20Sopenharmony_ci * @changed: if the rekeying needs to be rescheduled with new interval 24088c2ecf20Sopenharmony_ci * @new_intv: new rekeying interval (when "changed" = true) 24098c2ecf20Sopenharmony_ci */ 24108c2ecf20Sopenharmony_civoid tipc_crypto_rekeying_sched(struct tipc_crypto *tx, bool changed, 24118c2ecf20Sopenharmony_ci u32 new_intv) 24128c2ecf20Sopenharmony_ci{ 24138c2ecf20Sopenharmony_ci unsigned long delay; 24148c2ecf20Sopenharmony_ci bool now = false; 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci if (changed) { 24178c2ecf20Sopenharmony_ci if (new_intv == TIPC_REKEYING_NOW) 24188c2ecf20Sopenharmony_ci now = true; 24198c2ecf20Sopenharmony_ci else 24208c2ecf20Sopenharmony_ci tx->rekeying_intv = new_intv; 24218c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&tx->work); 24228c2ecf20Sopenharmony_ci } 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci if (tx->rekeying_intv || now) { 24258c2ecf20Sopenharmony_ci delay = (now) ? 0 : tx->rekeying_intv * 60 * 1000; 24268c2ecf20Sopenharmony_ci queue_delayed_work(tx->wq, &tx->work, msecs_to_jiffies(delay)); 24278c2ecf20Sopenharmony_ci } 24288c2ecf20Sopenharmony_ci} 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci/** 24318c2ecf20Sopenharmony_ci * tipc_crypto_work_tx - Scheduled TX works handler 24328c2ecf20Sopenharmony_ci * @work: the struct TX work 24338c2ecf20Sopenharmony_ci * 24348c2ecf20Sopenharmony_ci * The function processes the previous scheduled work, i.e. key rekeying, by 24358c2ecf20Sopenharmony_ci * generating a new session key based on current one, then attaching it to the 24368c2ecf20Sopenharmony_ci * TX crypto and finally distributing it to peers. It also re-schedules the 24378c2ecf20Sopenharmony_ci * rekeying if needed. 24388c2ecf20Sopenharmony_ci */ 24398c2ecf20Sopenharmony_cistatic void tipc_crypto_work_tx(struct work_struct *work) 24408c2ecf20Sopenharmony_ci{ 24418c2ecf20Sopenharmony_ci struct delayed_work *dwork = to_delayed_work(work); 24428c2ecf20Sopenharmony_ci struct tipc_crypto *tx = container_of(dwork, struct tipc_crypto, work); 24438c2ecf20Sopenharmony_ci struct tipc_aead_key *skey = NULL; 24448c2ecf20Sopenharmony_ci struct tipc_key key = tx->key; 24458c2ecf20Sopenharmony_ci struct tipc_aead *aead; 24468c2ecf20Sopenharmony_ci int rc = -ENOMEM; 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci if (unlikely(key.pending)) 24498c2ecf20Sopenharmony_ci goto resched; 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci /* Take current key as a template */ 24528c2ecf20Sopenharmony_ci rcu_read_lock(); 24538c2ecf20Sopenharmony_ci aead = rcu_dereference(tx->aead[key.active ?: KEY_MASTER]); 24548c2ecf20Sopenharmony_ci if (unlikely(!aead)) { 24558c2ecf20Sopenharmony_ci rcu_read_unlock(); 24568c2ecf20Sopenharmony_ci /* At least one key should exist for securing */ 24578c2ecf20Sopenharmony_ci return; 24588c2ecf20Sopenharmony_ci } 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci /* Lets duplicate it first */ 24618c2ecf20Sopenharmony_ci skey = kmemdup(aead->key, tipc_aead_key_size(aead->key), GFP_ATOMIC); 24628c2ecf20Sopenharmony_ci rcu_read_unlock(); 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci /* Now, generate new key, initiate & distribute it */ 24658c2ecf20Sopenharmony_ci if (likely(skey)) { 24668c2ecf20Sopenharmony_ci rc = tipc_aead_key_generate(skey) ?: 24678c2ecf20Sopenharmony_ci tipc_crypto_key_init(tx, skey, PER_NODE_KEY, false); 24688c2ecf20Sopenharmony_ci if (likely(rc > 0)) 24698c2ecf20Sopenharmony_ci rc = tipc_crypto_key_distr(tx, rc, NULL); 24708c2ecf20Sopenharmony_ci kfree_sensitive(skey); 24718c2ecf20Sopenharmony_ci } 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci if (unlikely(rc)) 24748c2ecf20Sopenharmony_ci pr_warn_ratelimited("%s: rekeying returns %d\n", tx->name, rc); 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ciresched: 24778c2ecf20Sopenharmony_ci /* Re-schedule rekeying if any */ 24788c2ecf20Sopenharmony_ci tipc_crypto_rekeying_sched(tx, false, 0); 24798c2ecf20Sopenharmony_ci} 2480