2484 lines · 65.9 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * net/tipc/crypto.c: TIPC crypto for key handling & packet en/decryption * * Copyright (c) 2019, Ericsson AB * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the names of the copyright holders nor the names of its *    contributors may be used to endorse or promote products derived from *    this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include <crypto/aead.h>#include <crypto/aes.h>#include <crypto/rng.h>#include "crypto.h"#include "msg.h"#include "bcast.h" #define TIPC_TX_GRACE_PERIOD	msecs_to_jiffies(5000) /* 5s */#define TIPC_TX_LASTING_TIME	msecs_to_jiffies(10000) /* 10s */#define TIPC_RX_ACTIVE_LIM	msecs_to_jiffies(3000) /* 3s */#define TIPC_RX_PASSIVE_LIM	msecs_to_jiffies(15000) /* 15s */ #define TIPC_MAX_TFMS_DEF	10#define TIPC_MAX_TFMS_LIM	1000 #define TIPC_REKEYING_INTV_DEF	(60 * 24) /* default: 1 day */ /* * TIPC Key ids */enum {	KEY_MASTER = 0,	KEY_MIN = KEY_MASTER,	KEY_1 = 1,	KEY_2,	KEY_3,	KEY_MAX = KEY_3,}; /* * TIPC Crypto statistics */enum {	STAT_OK,	STAT_NOK,	STAT_ASYNC,	STAT_ASYNC_OK,	STAT_ASYNC_NOK,	STAT_BADKEYS, /* tx only */	STAT_BADMSGS = STAT_BADKEYS, /* rx only */	STAT_NOKEYS,	STAT_SWITCHES, 	MAX_STATS,}; /* TIPC crypto statistics' header */static const char *hstats[MAX_STATS] = {"ok", "nok", "async", "async_ok",					"async_nok", "badmsgs", "nokeys",					"switches"}; /* Max TFMs number per key */int sysctl_tipc_max_tfms __read_mostly = TIPC_MAX_TFMS_DEF;/* Key exchange switch, default: on */int sysctl_tipc_key_exchange_enabled __read_mostly = 1; /* * struct tipc_key - TIPC keys' status indicator * *         7     6     5     4     3     2     1     0 *      +-----+-----+-----+-----+-----+-----+-----+-----+ * key: | (reserved)|passive idx| active idx|pending idx| *      +-----+-----+-----+-----+-----+-----+-----+-----+ */struct tipc_key {#define KEY_BITS (2)#define KEY_MASK ((1 << KEY_BITS) - 1)	union {		struct {#if defined(__LITTLE_ENDIAN_BITFIELD)			u8 pending:2,			   active:2,			   passive:2, /* rx only */			   reserved:2;#elif defined(__BIG_ENDIAN_BITFIELD)			u8 reserved:2,			   passive:2, /* rx only */			   active:2,			   pending:2;#else#error  "Please fix <asm/byteorder.h>"#endif		} __packed;		u8 keys;	};}; /** * struct tipc_tfm - TIPC TFM structure to form a list of TFMs * @tfm: cipher handle/key * @list: linked list of TFMs */struct tipc_tfm {	struct crypto_aead *tfm;	struct list_head list;}; /** * struct tipc_aead - TIPC AEAD key structure * @tfm_entry: per-cpu pointer to one entry in TFM list * @crypto: TIPC crypto owns this key * @cloned: reference to the source key in case cloning * @users: the number of the key users (TX/RX) * @salt: the key's SALT value * @authsize: authentication tag size (max = 16) * @mode: crypto mode is applied to the key * @hint: a hint for user key * @rcu: struct rcu_head * @key: the aead key * @gen: the key's generation * @seqno: the key seqno (cluster scope) * @refcnt: the key reference counter */struct tipc_aead {#define TIPC_AEAD_HINT_LEN (5)	struct tipc_tfm * __percpu *tfm_entry;	struct tipc_crypto *crypto;	struct tipc_aead *cloned;	atomic_t users;	u32 salt;	u8 authsize;	u8 mode;	char hint[2 * TIPC_AEAD_HINT_LEN + 1];	struct rcu_head rcu;	struct tipc_aead_key *key;	u16 gen; 	atomic64_t seqno ____cacheline_aligned;	refcount_t refcnt ____cacheline_aligned; } ____cacheline_aligned; /** * struct tipc_crypto_stats - TIPC Crypto statistics * @stat: array of crypto statistics */struct tipc_crypto_stats {	unsigned int stat[MAX_STATS];}; /** * struct tipc_crypto - TIPC TX/RX crypto structure * @net: struct net * @node: TIPC node (RX) * @aead: array of pointers to AEAD keys for encryption/decryption * @peer_rx_active: replicated peer RX active key index * @key_gen: TX/RX key generation * @key: the key states * @skey_mode: session key's mode * @skey: received session key * @wq: common workqueue on TX crypto * @work: delayed work sched for TX/RX * @key_distr: key distributing state * @rekeying_intv: rekeying interval (in minutes) * @stats: the crypto statistics * @name: the crypto name * @sndnxt: the per-peer sndnxt (TX) * @timer1: general timer 1 (jiffies) * @timer2: general timer 2 (jiffies) * @working: the crypto is working or not * @key_master: flag indicates if master key exists * @legacy_user: flag indicates if a peer joins w/o master key (for bwd comp.) * @nokey: no key indication * @flags: combined flags field * @lock: tipc_key lock */struct tipc_crypto {	struct net *net;	struct tipc_node *node;	struct tipc_aead __rcu *aead[KEY_MAX + 1];	atomic_t peer_rx_active;	u16 key_gen;	struct tipc_key key;	u8 skey_mode;	struct tipc_aead_key *skey;	struct workqueue_struct *wq;	struct delayed_work work;#define KEY_DISTR_SCHED		1#define KEY_DISTR_COMPL		2	atomic_t key_distr;	u32 rekeying_intv; 	struct tipc_crypto_stats __percpu *stats;	char name[48]; 	atomic64_t sndnxt ____cacheline_aligned;	unsigned long timer1;	unsigned long timer2;	union {		struct {			u8 working:1;			u8 key_master:1;			u8 legacy_user:1;			u8 nokey: 1;		};		u8 flags;	};	spinlock_t lock; /* crypto lock */ } ____cacheline_aligned; /* struct tipc_crypto_tx_ctx - TX context for callbacks */struct tipc_crypto_tx_ctx {	struct tipc_aead *aead;	struct tipc_bearer *bearer;	struct tipc_media_addr dst;}; /* struct tipc_crypto_rx_ctx - RX context for callbacks */struct tipc_crypto_rx_ctx {	struct tipc_aead *aead;	struct tipc_bearer *bearer;}; static struct tipc_aead *tipc_aead_get(struct tipc_aead __rcu *aead);static inline void tipc_aead_put(struct tipc_aead *aead);static void tipc_aead_free(struct rcu_head *rp);static int tipc_aead_users(struct tipc_aead __rcu *aead);static void tipc_aead_users_inc(struct tipc_aead __rcu *aead, int lim);static void tipc_aead_users_dec(struct tipc_aead __rcu *aead, int lim);static void tipc_aead_users_set(struct tipc_aead __rcu *aead, int val);static struct crypto_aead *tipc_aead_tfm_next(struct tipc_aead *aead);static int tipc_aead_init(struct tipc_aead **aead, struct tipc_aead_key *ukey,			  u8 mode);static int tipc_aead_clone(struct tipc_aead **dst, struct tipc_aead *src);static void *tipc_aead_mem_alloc(struct crypto_aead *tfm,				 unsigned int crypto_ctx_size,				 u8 **iv, struct aead_request **req,				 struct scatterlist **sg, int nsg);static int tipc_aead_encrypt(struct tipc_aead *aead, struct sk_buff *skb,			     struct tipc_bearer *b,			     struct tipc_media_addr *dst,			     struct tipc_node *__dnode);static void tipc_aead_encrypt_done(void *data, int err);static int tipc_aead_decrypt(struct net *net, struct tipc_aead *aead,			     struct sk_buff *skb, struct tipc_bearer *b);static void tipc_aead_decrypt_done(void *data, int err);static inline int tipc_ehdr_size(struct tipc_ehdr *ehdr);static int tipc_ehdr_build(struct net *net, struct tipc_aead *aead,			   u8 tx_key, struct sk_buff *skb,			   struct tipc_crypto *__rx);static inline void tipc_crypto_key_set_state(struct tipc_crypto *c,					     u8 new_passive,					     u8 new_active,					     u8 new_pending);static int tipc_crypto_key_attach(struct tipc_crypto *c,				  struct tipc_aead *aead, u8 pos,				  bool master_key);static bool tipc_crypto_key_try_align(struct tipc_crypto *rx, u8 new_pending);static struct tipc_aead *tipc_crypto_key_pick_tx(struct tipc_crypto *tx,						 struct tipc_crypto *rx,						 struct sk_buff *skb,						 u8 tx_key);static void tipc_crypto_key_synch(struct tipc_crypto *rx, struct sk_buff *skb);static int tipc_crypto_key_revoke(struct net *net, u8 tx_key);static inline void tipc_crypto_clone_msg(struct net *net, struct sk_buff *_skb,					 struct tipc_bearer *b,					 struct tipc_media_addr *dst,					 struct tipc_node *__dnode, u8 type);static void tipc_crypto_rcv_complete(struct net *net, struct tipc_aead *aead,				     struct tipc_bearer *b,				     struct sk_buff **skb, int err);static void tipc_crypto_do_cmd(struct net *net, int cmd);static char *tipc_crypto_key_dump(struct tipc_crypto *c, char *buf);static char *tipc_key_change_dump(struct tipc_key old, struct tipc_key new,				  char *buf);static int tipc_crypto_key_xmit(struct net *net, struct tipc_aead_key *skey,				u16 gen, u8 mode, u32 dnode);static bool tipc_crypto_key_rcv(struct tipc_crypto *rx, struct tipc_msg *hdr);static void tipc_crypto_work_tx(struct work_struct *work);static void tipc_crypto_work_rx(struct work_struct *work);static int tipc_aead_key_generate(struct tipc_aead_key *skey); #define is_tx(crypto) (!(crypto)->node)#define is_rx(crypto) (!is_tx(crypto)) #define key_next(cur) ((cur) % KEY_MAX + 1) #define tipc_aead_rcu_ptr(rcu_ptr, lock)				\	rcu_dereference_protected((rcu_ptr), lockdep_is_held(lock)) #define tipc_aead_rcu_replace(rcu_ptr, ptr, lock)			\do {									\	struct tipc_aead *__tmp = rcu_dereference_protected((rcu_ptr),	\						lockdep_is_held(lock));	\	rcu_assign_pointer((rcu_ptr), (ptr));				\	tipc_aead_put(__tmp);						\} while (0) #define tipc_crypto_key_detach(rcu_ptr, lock)				\	tipc_aead_rcu_replace((rcu_ptr), NULL, lock) /** * tipc_aead_key_validate - Validate a AEAD user key * @ukey: pointer to user key data * @info: netlink info pointer */int tipc_aead_key_validate(struct tipc_aead_key *ukey, struct genl_info *info){	int keylen; 	/* Check if algorithm exists */	if (unlikely(!crypto_has_alg(ukey->alg_name, 0, 0))) {		GENL_SET_ERR_MSG(info, "unable to load the algorithm (module existed?)");		return -ENODEV;	} 	/* Currently, we only support the "gcm(aes)" cipher algorithm */	if (strcmp(ukey->alg_name, "gcm(aes)")) {		GENL_SET_ERR_MSG(info, "not supported yet the algorithm");		return -ENOTSUPP;	} 	/* Check if key size is correct */	keylen = ukey->keylen - TIPC_AES_GCM_SALT_SIZE;	if (unlikely(keylen != TIPC_AES_GCM_KEY_SIZE_128 &&		     keylen != TIPC_AES_GCM_KEY_SIZE_192 &&		     keylen != TIPC_AES_GCM_KEY_SIZE_256)) {		GENL_SET_ERR_MSG(info, "incorrect key length (20, 28 or 36 octets?)");		return -EKEYREJECTED;	} 	return 0;} /** * tipc_aead_key_generate - Generate new session key * @skey: input/output key with new content * * Return: 0 in case of success, otherwise < 0 */static int tipc_aead_key_generate(struct tipc_aead_key *skey){	/* Fill the key's content with a random value via stdrng */	return crypto_stdrng_get_bytes(skey->key, skey->keylen);} static struct tipc_aead *tipc_aead_get(struct tipc_aead __rcu *aead){	struct tipc_aead *tmp; 	rcu_read_lock();	tmp = rcu_dereference(aead);	if (unlikely(!tmp || !refcount_inc_not_zero(&tmp->refcnt)))		tmp = NULL;	rcu_read_unlock(); 	return tmp;} static inline void tipc_aead_put(struct tipc_aead *aead){	if (aead && refcount_dec_and_test(&aead->refcnt))		call_rcu(&aead->rcu, tipc_aead_free);} /** * tipc_aead_free - Release AEAD key incl. all the TFMs in the list * @rp: rcu head pointer */static void tipc_aead_free(struct rcu_head *rp){	struct tipc_aead *aead = container_of(rp, struct tipc_aead, rcu);	struct tipc_tfm *tfm_entry, *head, *tmp; 	if (aead->cloned) {		tipc_aead_put(aead->cloned);	} else {		head = *get_cpu_ptr(aead->tfm_entry);		put_cpu_ptr(aead->tfm_entry);		list_for_each_entry_safe(tfm_entry, tmp, &head->list, list) {			crypto_free_aead(tfm_entry->tfm);			list_del(&tfm_entry->list);			kfree(tfm_entry);		}		/* Free the head */		crypto_free_aead(head->tfm);		list_del(&head->list);		kfree(head);	}	free_percpu(aead->tfm_entry);	kfree_sensitive(aead->key);	kfree_sensitive(aead);} static int tipc_aead_users(struct tipc_aead __rcu *aead){	struct tipc_aead *tmp;	int users = 0; 	rcu_read_lock();	tmp = rcu_dereference(aead);	if (tmp)		users = atomic_read(&tmp->users);	rcu_read_unlock(); 	return users;} static void tipc_aead_users_inc(struct tipc_aead __rcu *aead, int lim){	struct tipc_aead *tmp; 	rcu_read_lock();	tmp = rcu_dereference(aead);	if (tmp)		atomic_add_unless(&tmp->users, 1, lim);	rcu_read_unlock();} static void tipc_aead_users_dec(struct tipc_aead __rcu *aead, int lim){	struct tipc_aead *tmp; 	rcu_read_lock();	tmp = rcu_dereference(aead);	if (tmp)		atomic_add_unless(&tmp->users, -1, lim);	rcu_read_unlock();} static void tipc_aead_users_set(struct tipc_aead __rcu *aead, int val){	struct tipc_aead *tmp;	int cur; 	rcu_read_lock();	tmp = rcu_dereference(aead);	if (tmp) {		do {			cur = atomic_read(&tmp->users);			if (cur == val)				break;		} while (atomic_cmpxchg(&tmp->users, cur, val) != cur);	}	rcu_read_unlock();} /** * tipc_aead_tfm_next - Move TFM entry to the next one in list and return it * @aead: the AEAD key pointer */static struct crypto_aead *tipc_aead_tfm_next(struct tipc_aead *aead){	struct tipc_tfm **tfm_entry;	struct crypto_aead *tfm; 	tfm_entry = get_cpu_ptr(aead->tfm_entry);	*tfm_entry = list_next_entry(*tfm_entry, list);	tfm = (*tfm_entry)->tfm;	put_cpu_ptr(tfm_entry); 	return tfm;} /** * tipc_aead_init - Initiate TIPC AEAD * @aead: returned new TIPC AEAD key handle pointer * @ukey: pointer to user key data * @mode: the key mode * * Allocate a (list of) new cipher transformation (TFM) with the specific user * key data if valid. The number of the allocated TFMs can be set via the sysfs * "net/tipc/max_tfms" first.

Lines 1–500 of 2484.