linux/net/tipc/crypto.c

// 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
#define TIPC_TX_LASTING_TIME
#define TIPC_RX_ACTIVE_LIM
#define TIPC_RX_PASSIVE_LIM

#define TIPC_MAX_TFMS_DEF
#define TIPC_MAX_TFMS_LIM

#define TIPC_REKEYING_INTV_DEF

/*
 * TIPC Key ids
 */
enum {};

/*
 * TIPC Crypto statistics
 */
enum {};

/* TIPC crypto statistics' header */
static const char *hstats[MAX_STATS] =;

/* Max TFMs number per key */
int sysctl_tipc_max_tfms __read_mostly =;
/* Key exchange switch, default: on */
int sysctl_tipc_key_exchange_enabled __read_mostly =;

/*
 * 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 {};

/**
 * 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 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 {} ____cacheline_aligned;

/**
 * struct tipc_crypto_stats - TIPC Crypto statistics
 * @stat: array of crypto statistics
 */
struct tipc_crypto_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 {} ____cacheline_aligned;

/* struct tipc_crypto_tx_ctx - TX context for callbacks */
struct tipc_crypto_tx_ctx {};

/* struct tipc_crypto_rx_ctx - RX context for callbacks */
struct tipc_crypto_rx_ctx {};

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)
#define is_rx(crypto)

#define key_next(cur)

#define tipc_aead_rcu_ptr(rcu_ptr, lock)

#define tipc_aead_rcu_replace(rcu_ptr, ptr, lock)

#define tipc_crypto_key_detach(rcu_ptr, 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)
{}

/**
 * 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)
{}

static struct tipc_aead *tipc_aead_get(struct tipc_aead __rcu *aead)
{}

static inline void tipc_aead_put(struct tipc_aead *aead)
{}

/**
 * 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)
{}

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)
{}

/**
 * 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)
{}

/**
 * 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.
 * Also, all the other AEAD data are also initialized.
 *
 * Return: 0 if the initiation is successful, otherwise: < 0
 */
static int tipc_aead_init(struct tipc_aead **aead, struct tipc_aead_key *ukey,
			  u8 mode)
{}

/**
 * tipc_aead_clone - Clone a TIPC AEAD key
 * @dst: dest key for the cloning
 * @src: source key to clone from
 *
 * Make a "copy" of the source AEAD key data to the dest, the TFMs list is
 * common for the keys.
 * A reference to the source is hold in the "cloned" pointer for the later
 * freeing purposes.
 *
 * Note: this must be done in cluster-key mode only!
 * Return: 0 in case of success, otherwise < 0
 */
static int tipc_aead_clone(struct tipc_aead **dst, struct tipc_aead *src)
{}

/**
 * tipc_aead_mem_alloc - Allocate memory for AEAD request operations
 * @tfm: cipher handle to be registered with the request
 * @crypto_ctx_size: size of crypto context for callback
 * @iv: returned pointer to IV data
 * @req: returned pointer to AEAD request data
 * @sg: returned pointer to SG lists
 * @nsg: number of SG lists to be allocated
 *
 * Allocate memory to store the crypto context data, AEAD request, IV and SG
 * lists, the memory layout is as follows:
 * crypto_ctx || iv || aead_req || sg[]
 *
 * Return: the pointer to the memory areas in case of success, otherwise NULL
 */
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)
{}

/**
 * tipc_aead_encrypt - Encrypt a message
 * @aead: TIPC AEAD key for the message encryption
 * @skb: the input/output skb
 * @b: TIPC bearer where the message will be delivered after the encryption
 * @dst: the destination media address
 * @__dnode: TIPC dest node if "known"
 *
 * Return:
 * * 0                   : if the encryption has completed
 * * -EINPROGRESS/-EBUSY : if a callback will be performed
 * * < 0                 : the encryption has failed
 */
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)
{}

/**
 * tipc_aead_decrypt - Decrypt an encrypted message
 * @net: struct net
 * @aead: TIPC AEAD for the message decryption
 * @skb: the input/output skb
 * @b: TIPC bearer where the message has been received
 *
 * Return:
 * * 0                   : if the decryption has completed
 * * -EINPROGRESS/-EBUSY : if a callback will be performed
 * * < 0                 : the decryption has failed
 */
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)
{}

/**
 * tipc_ehdr_validate - Validate an encryption message
 * @skb: the message buffer
 *
 * Return: "true" if this is a valid encryption message, otherwise "false"
 */
bool tipc_ehdr_validate(struct sk_buff *skb)
{}

/**
 * tipc_ehdr_build - Build TIPC encryption message header
 * @net: struct net
 * @aead: TX AEAD key to be used for the message encryption
 * @tx_key: key id used for the message encryption
 * @skb: input/output message skb
 * @__rx: RX crypto handle if dest is "known"
 *
 * Return: the header size if the building is successful, otherwise < 0
 */
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)
{}

/**
 * tipc_crypto_key_init - Initiate a new user / AEAD key
 * @c: TIPC crypto to which new key is attached
 * @ukey: the user key
 * @mode: the key mode (CLUSTER_KEY or PER_NODE_KEY)
 * @master_key: specify this is a cluster master key
 *
 * A new TIPC AEAD key will be allocated and initiated with the specified user
 * key, then attached to the TIPC crypto.
 *
 * Return: new key id in case of success, otherwise: < 0
 */
int tipc_crypto_key_init(struct tipc_crypto *c, struct tipc_aead_key *ukey,
			 u8 mode, bool master_key)
{}

/**
 * tipc_crypto_key_attach - Attach a new AEAD key to TIPC crypto
 * @c: TIPC crypto to which the new AEAD key is attached
 * @aead: the new AEAD key pointer
 * @pos: desired slot in the crypto key array, = 0 if any!
 * @master_key: specify this is a cluster master key
 *
 * Return: new key id in case of success, otherwise: -EBUSY
 */
static int tipc_crypto_key_attach(struct tipc_crypto *c,
				  struct tipc_aead *aead, u8 pos,
				  bool master_key)
{}

void tipc_crypto_key_flush(struct tipc_crypto *c)
{}

/**
 * tipc_crypto_key_try_align - Align RX keys if possible
 * @rx: RX crypto handle
 * @new_pending: new pending slot if aligned (= TX key from peer)
 *
 * Peer has used an unknown key slot, this only happens when peer has left and
 * rejoned, or we are newcomer.
 * That means, there must be no active key but a pending key at unaligned slot.
 * If so, we try to move the pending key to the new slot.
 * Note: A potential passive key can exist, it will be shifted correspondingly!
 *
 * Return: "true" if key is successfully aligned, otherwise "false"
 */
static bool tipc_crypto_key_try_align(struct tipc_crypto *rx, u8 new_pending)
{}

/**
 * tipc_crypto_key_pick_tx - Pick one TX key for message decryption
 * @tx: TX crypto handle
 * @rx: RX crypto handle (can be NULL)
 * @skb: the message skb which will be decrypted later
 * @tx_key: peer TX key id
 *
 * This function looks up the existing TX keys and pick one which is suitable
 * for the message decryption, that must be a cluster key and not used before
 * on the same message (i.e. recursive).
 *
 * Return: the TX AEAD key handle in case of success, otherwise NULL
 */
static struct tipc_aead *tipc_crypto_key_pick_tx(struct tipc_crypto *tx,
						 struct tipc_crypto *rx,
						 struct sk_buff *skb,
						 u8 tx_key)
{}

/**
 * tipc_crypto_key_synch: Synch own key data according to peer key status
 * @rx: RX crypto handle
 * @skb: TIPCv2 message buffer (incl. the ehdr from peer)
 *
 * This function updates the peer node related data as the peer RX active key
 * has changed, so the number of TX keys' users on this node are increased and
 * decreased correspondingly.
 *
 * It also considers if peer has no key, then we need to make own master key
 * (if any) taking over i.e. starting grace period and also trigger key
 * distributing process.
 *
 * The "per-peer" sndnxt is also reset when the peer key has switched.
 */
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)
{}

int tipc_crypto_start(struct tipc_crypto **crypto, struct net *net,
		      struct tipc_node *node)
{}

void tipc_crypto_stop(struct tipc_crypto **crypto)
{}

void tipc_crypto_timeout(struct tipc_crypto *rx)
{}

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)
{}

/**
 * tipc_crypto_xmit - Build & encrypt TIPC message for xmit
 * @net: struct net
 * @skb: input/output message skb pointer
 * @b: bearer used for xmit later
 * @dst: destination media address
 * @__dnode: destination node for reference if any
 *
 * First, build an encryption message header on the top of the message, then
 * encrypt the original TIPC message by using the pending, master or active
 * key with this preference order.
 * If the encryption is successful, the encrypted skb is returned directly or
 * via the callback.
 * Otherwise, the skb is freed!
 *
 * Return:
 * * 0                   : the encryption has succeeded (or no encryption)
 * * -EINPROGRESS/-EBUSY : the encryption is ongoing, a callback will be made
 * * -ENOKEK             : the encryption has failed due to no key
 * * -EKEYREVOKED        : the encryption has failed due to key revoked
 * * -ENOMEM             : the encryption has failed due to no memory
 * * < 0                 : the encryption has failed due to other reasons
 */
int tipc_crypto_xmit(struct net *net, struct sk_buff **skb,
		     struct tipc_bearer *b, struct tipc_media_addr *dst,
		     struct tipc_node *__dnode)
{}

/**
 * tipc_crypto_rcv - Decrypt an encrypted TIPC message from peer
 * @net: struct net
 * @rx: RX crypto handle
 * @skb: input/output message skb pointer
 * @b: bearer where the message has been received
 *
 * If the decryption is successful, the decrypted skb is returned directly or
 * as the callback, the encryption header and auth tag will be trimed out
 * before forwarding to tipc_rcv() via the tipc_crypto_rcv_complete().
 * Otherwise, the skb will be freed!
 * Note: RX key(s) can be re-aligned, or in case of no key suitable, TX
 * cluster key(s) can be taken for decryption (- recursive).
 *
 * Return:
 * * 0                   : the decryption has successfully completed
 * * -EINPROGRESS/-EBUSY : the decryption is ongoing, a callback will be made
 * * -ENOKEY             : the decryption has failed due to no key
 * * -EBADMSG            : the decryption has failed due to bad message
 * * -ENOMEM             : the decryption has failed due to no memory
 * * < 0                 : the decryption has failed due to other reasons
 */
int tipc_crypto_rcv(struct net *net, struct tipc_crypto *rx,
		    struct sk_buff **skb, struct tipc_bearer *b)
{}

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)
{}

/**
 * tipc_crypto_msg_rcv - Common 'MSG_CRYPTO' processing point
 * @net: the struct net
 * @skb: the receiving message buffer
 */
void tipc_crypto_msg_rcv(struct net *net, struct sk_buff *skb)
{}

/**
 * tipc_crypto_key_distr - Distribute a TX key
 * @tx: the TX crypto
 * @key: the key's index
 * @dest: the destination tipc node, = NULL if distributing to all nodes
 *
 * Return: 0 in case of success, otherwise < 0
 */
int tipc_crypto_key_distr(struct tipc_crypto *tx, u8 key,
			  struct tipc_node *dest)
{}

/**
 * tipc_crypto_key_xmit - Send a session key
 * @net: the struct net
 * @skey: the session key to be sent
 * @gen: the key's generation
 * @mode: the key's mode
 * @dnode: the destination node address, = 0 if broadcasting to all nodes
 *
 * The session key 'skey' is packed in a TIPC v2 'MSG_CRYPTO/KEY_DISTR_MSG'
 * as its data section, then xmit-ed through the uc/bc link.
 *
 * Return: 0 in case of success, otherwise < 0
 */
static int tipc_crypto_key_xmit(struct net *net, struct tipc_aead_key *skey,
				u16 gen, u8 mode, u32 dnode)
{}

/**
 * tipc_crypto_key_rcv - Receive a session key
 * @rx: the RX crypto
 * @hdr: the TIPC v2 message incl. the receiving session key in its data
 *
 * This function retrieves the session key in the message from peer, then
 * schedules a RX work to attach the key to the corresponding RX crypto.
 *
 * Return: "true" if the key has been scheduled for attaching, otherwise
 * "false".
 */
static bool tipc_crypto_key_rcv(struct tipc_crypto *rx, struct tipc_msg *hdr)
{}

/**
 * tipc_crypto_work_rx - Scheduled RX works handler
 * @work: the struct RX work
 *
 * The function processes the previous scheduled works i.e. distributing TX key
 * or attaching a received session key on RX crypto.
 */
static void tipc_crypto_work_rx(struct work_struct *work)
{}

/**
 * tipc_crypto_rekeying_sched - (Re)schedule rekeying w/o new interval
 * @tx: TX crypto
 * @changed: if the rekeying needs to be rescheduled with new interval
 * @new_intv: new rekeying interval (when "changed" = true)
 */
void tipc_crypto_rekeying_sched(struct tipc_crypto *tx, bool changed,
				u32 new_intv)
{}

/**
 * tipc_crypto_work_tx - Scheduled TX works handler
 * @work: the struct TX work
 *
 * The function processes the previous scheduled work, i.e. key rekeying, by
 * generating a new session key based on current one, then attaching it to the
 * TX crypto and finally distributing it to peers. It also re-schedules the
 * rekeying if needed.
 */
static void tipc_crypto_work_tx(struct work_struct *work)
{}