Commit 5d7d28e5 authored by David S. Miller's avatar David S. Miller

Merge branch 'tipc-add-more-features-to-TIPC-encryption'

Tuong Lien says:

====================
tipc: add more features to TIPC encryption

This series adds some new features to TIPC encryption:

- Patch 1 ("tipc: optimize key switching time and logic") optimizes the
code and logic in preparation for the following commits.

- Patch 2 ("tipc: introduce encryption master key") introduces support
of 'master key' for authentication of new nodes and key exchange. A
master key can be set/changed by user via netlink (eg. using the same
'tipc node set key' command in iproute2/tipc).

- Patch 3 ("tipc: add automatic session key exchange") allows a session
key to be securely exchanged between nodes as needed.

- Patch 4 ("tipc: add automatic rekeying for encryption key") adds
automatic 'rekeying' of session keys a specific interval. The new key
will be distributed automatically to peer nodes, so become active then.
The rekeying interval is configurable via netlink as well.

v2: update the "tipc: add automatic session key exchange" patch to fix
"implicit declaration" issue when built without "CONFIG_TIPC_CRYPTO".

v3: update the patches according to David comments by using the
"genl_info->extack" for messages in response to netlink user config
requests.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents cb589a55 23700da2
......@@ -254,6 +254,8 @@ static inline int tipc_aead_key_size(struct tipc_aead_key *key)
return sizeof(*key) + key->keylen;
}
#define TIPC_REKEYING_NOW (~0U)
/* The macros and functions below are deprecated:
*/
......
......@@ -165,6 +165,8 @@ enum {
TIPC_NLA_NODE_UP, /* flag */
TIPC_NLA_NODE_ID, /* data */
TIPC_NLA_NODE_KEY, /* data */
TIPC_NLA_NODE_KEY_MASTER, /* flag */
TIPC_NLA_NODE_REKEYING, /* u32 */
__TIPC_NLA_NODE_MAX,
TIPC_NLA_NODE_MAX = __TIPC_NLA_NODE_MAX - 1
......
This diff is collapsed.
......@@ -67,6 +67,7 @@ enum {
};
extern int sysctl_tipc_max_tfms __read_mostly;
extern int sysctl_tipc_key_exchange_enabled __read_mostly;
/**
* TIPC encryption message format:
......@@ -74,7 +75,7 @@ extern int sysctl_tipc_max_tfms __read_mostly;
* 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
* 1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* w0:|Ver=7| User |D|TX |RX |K| Rsvd |
* w0:|Ver=7| User |D|TX |RX |K|M|N| Rsvd |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* w1:| Seqno |
* w2:| (8 octets) |
......@@ -101,6 +102,9 @@ extern int sysctl_tipc_max_tfms __read_mostly;
* RX : Currently RX active key corresponding to the destination
* node's TX key (when the "D" bit is set)
* K : Keep-alive bit (for RPS, LINK_PROTOCOL/STATE_MSG only)
* M : Bit indicates if sender has master key
* N : Bit indicates if sender has no RX keys corresponding to the
* receiver's TX (when the "D" bit is set)
* Rsvd : Reserved bit, field
* Word1-2:
* Seqno : The 64-bit sequence number of the encrypted message, also
......@@ -117,7 +121,9 @@ struct tipc_ehdr {
__u8 destined:1,
user:4,
version:3;
__u8 reserved_1:3,
__u8 reserved_1:1,
rx_nokey:1,
master_key:1,
keepalive:1,
rx_key_active:2,
tx_key:2;
......@@ -128,7 +134,9 @@ struct tipc_ehdr {
__u8 tx_key:2,
rx_key_active:2,
keepalive:1,
reserved_1:3;
master_key:1,
rx_nokey:1,
reserved_1:1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
......@@ -158,10 +166,35 @@ int tipc_crypto_xmit(struct net *net, struct sk_buff **skb,
int tipc_crypto_rcv(struct net *net, struct tipc_crypto *rx,
struct sk_buff **skb, struct tipc_bearer *b);
int tipc_crypto_key_init(struct tipc_crypto *c, struct tipc_aead_key *ukey,
u8 mode);
u8 mode, bool master_key);
void tipc_crypto_key_flush(struct tipc_crypto *c);
int tipc_aead_key_validate(struct tipc_aead_key *ukey);
int tipc_crypto_key_distr(struct tipc_crypto *tx, u8 key,
struct tipc_node *dest);
void tipc_crypto_msg_rcv(struct net *net, struct sk_buff *skb);
void tipc_crypto_rekeying_sched(struct tipc_crypto *tx, bool changed,
u32 new_intv);
int tipc_aead_key_validate(struct tipc_aead_key *ukey, struct genl_info *info);
bool tipc_ehdr_validate(struct sk_buff *skb);
static inline u32 msg_key_gen(struct tipc_msg *m)
{
return msg_bits(m, 4, 16, 0xffff);
}
static inline void msg_set_key_gen(struct tipc_msg *m, u32 gen)
{
msg_set_bits(m, 4, 16, 0xffff, gen);
}
static inline u32 msg_key_mode(struct tipc_msg *m)
{
return msg_bits(m, 4, 0, 0xf);
}
static inline void msg_set_key_mode(struct tipc_msg *m, u32 mode)
{
msg_set_bits(m, 4, 0, 0xf, mode);
}
#endif /* _TIPC_CRYPTO_H */
#endif
......@@ -1250,6 +1250,11 @@ static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb,
case MSG_FRAGMENTER:
case BCAST_PROTOCOL:
return false;
#ifdef CONFIG_TIPC_CRYPTO
case MSG_CRYPTO:
tipc_crypto_msg_rcv(l->net, skb);
return true;
#endif
default:
pr_warn("Dropping received illegal msg type\n");
kfree_skb(skb);
......
......@@ -82,6 +82,7 @@ struct plist;
#define NAME_DISTRIBUTOR 11
#define MSG_FRAGMENTER 12
#define LINK_CONFIG 13
#define MSG_CRYPTO 14
#define SOCK_WAKEUP 14 /* pseudo user */
#define TOP_SRV 15 /* pseudo user */
......@@ -127,7 +128,9 @@ struct tipc_skb_cb {
#ifdef CONFIG_TIPC_CRYPTO
u8 encrypted:1;
u8 decrypted:1;
u8 probe:1;
#define SKB_PROBING 1
#define SKB_GRACING 2
u8 xmit_type:2;
u8 tx_clone_deferred:1;
#endif
};
......@@ -747,6 +750,9 @@ static inline void msg_set_nameupper(struct tipc_msg *m, u32 n)
#define GRP_RECLAIM_MSG 4
#define GRP_REMIT_MSG 5
/* Crypto message types */
#define KEY_DISTR_MSG 0
/*
* Word 1
*/
......
......@@ -108,6 +108,8 @@ const struct nla_policy tipc_nl_node_policy[TIPC_NLA_NODE_MAX + 1] = {
.len = TIPC_NODEID_LEN},
[TIPC_NLA_NODE_KEY] = { .type = NLA_BINARY,
.len = TIPC_AEAD_KEY_SIZE_MAX},
[TIPC_NLA_NODE_KEY_MASTER] = { .type = NLA_FLAG },
[TIPC_NLA_NODE_REKEYING] = { .type = NLA_U32 },
};
/* Properties valid for media, bearer and link */
......
......@@ -278,6 +278,14 @@ struct tipc_crypto *tipc_node_crypto_rx_by_list(struct list_head *pos)
{
return container_of(pos, struct tipc_node, list)->crypto_rx;
}
struct tipc_crypto *tipc_node_crypto_rx_by_addr(struct net *net, u32 addr)
{
struct tipc_node *n;
n = tipc_node_find(net, addr);
return (n) ? n->crypto_rx : NULL;
}
#endif
static void tipc_node_free(struct rcu_head *rp)
......@@ -303,7 +311,7 @@ void tipc_node_put(struct tipc_node *node)
kref_put(&node->kref, tipc_node_kref_release);
}
static void tipc_node_get(struct tipc_node *node)
void tipc_node_get(struct tipc_node *node)
{
kref_get(&node->kref);
}
......@@ -584,6 +592,9 @@ static void tipc_node_calculate_timer(struct tipc_node *n, struct tipc_link *l)
static void tipc_node_delete_from_list(struct tipc_node *node)
{
#ifdef CONFIG_TIPC_CRYPTO
tipc_crypto_key_flush(node->crypto_rx);
#endif
list_del_rcu(&node->list);
hlist_del_rcu(&node->hash);
tipc_node_put(node);
......@@ -2868,15 +2879,27 @@ static int tipc_nl_retrieve_nodeid(struct nlattr **attrs, u8 **node_id)
return 0;
}
static int tipc_nl_retrieve_rekeying(struct nlattr **attrs, u32 *intv)
{
struct nlattr *attr = attrs[TIPC_NLA_NODE_REKEYING];
if (!attr)
return -ENODATA;
*intv = nla_get_u32(attr);
return 0;
}
static int __tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *attrs[TIPC_NLA_NODE_MAX + 1];
struct net *net = sock_net(skb->sk);
struct tipc_net *tn = tipc_net(net);
struct tipc_crypto *tx = tipc_net(net)->crypto_tx, *c = tx;
struct tipc_node *n = NULL;
struct tipc_aead_key *ukey;
struct tipc_crypto *c;
u8 *id, *own_id;
bool rekeying = true, master_key = false;
u8 *id, *own_id, mode;
u32 intv = 0;
int rc = 0;
if (!info->attrs[TIPC_NLA_NODE])
......@@ -2886,52 +2909,66 @@ static int __tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info)
info->attrs[TIPC_NLA_NODE],
tipc_nl_node_policy, info->extack);
if (rc)
goto exit;
return rc;
own_id = tipc_own_id(net);
if (!own_id) {
rc = -EPERM;
goto exit;
GENL_SET_ERR_MSG(info, "not found own node identity (set id?)");
return -EPERM;
}
rc = tipc_nl_retrieve_rekeying(attrs, &intv);
if (rc == -ENODATA)
rekeying = false;
rc = tipc_nl_retrieve_key(attrs, &ukey);
if (rc)
goto exit;
if (rc == -ENODATA && rekeying)
goto rekeying;
else if (rc)
return rc;
rc = tipc_aead_key_validate(ukey);
rc = tipc_aead_key_validate(ukey, info);
if (rc)
goto exit;
return rc;
rc = tipc_nl_retrieve_nodeid(attrs, &id);
switch (rc) {
case -ENODATA:
/* Cluster key mode */
rc = tipc_crypto_key_init(tn->crypto_tx, ukey, CLUSTER_KEY);
mode = CLUSTER_KEY;
master_key = !!(attrs[TIPC_NLA_NODE_KEY_MASTER]);
break;
case 0:
/* Per-node key mode */
if (!memcmp(id, own_id, NODE_ID_LEN)) {
c = tn->crypto_tx;
} else {
mode = PER_NODE_KEY;
if (memcmp(id, own_id, NODE_ID_LEN)) {
n = tipc_node_find_by_id(net, id) ?:
tipc_node_create(net, 0, id, 0xffffu, 0, true);
if (unlikely(!n)) {
rc = -ENOMEM;
break;
}
if (unlikely(!n))
return -ENOMEM;
c = n->crypto_rx;
}
rc = tipc_crypto_key_init(c, ukey, PER_NODE_KEY);
if (n)
tipc_node_put(n);
break;
default:
break;
return rc;
}
exit:
return (rc < 0) ? rc : 0;
/* Initiate the TX/RX key */
rc = tipc_crypto_key_init(c, ukey, mode, master_key);
if (n)
tipc_node_put(n);
if (unlikely(rc < 0)) {
GENL_SET_ERR_MSG(info, "unable to initiate or attach new key");
return rc;
} else if (c == tx) {
/* Distribute TX key but not master one */
if (!master_key && tipc_crypto_key_distr(tx, rc, NULL))
GENL_SET_ERR_MSG(info, "failed to replicate new key");
rekeying:
/* Schedule TX rekeying if needed */
tipc_crypto_rekeying_sched(tx, rekeying, intv);
}
return 0;
}
int tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info)
......@@ -2958,7 +2995,6 @@ static int __tipc_nl_node_flush_key(struct sk_buff *skb,
tipc_crypto_key_flush(n->crypto_rx);
rcu_read_unlock();
pr_info("All keys are flushed!\n");
return 0;
}
......
......@@ -79,12 +79,14 @@ bool tipc_node_get_id(struct net *net, u32 addr, u8 *id);
u32 tipc_node_get_addr(struct tipc_node *node);
char *tipc_node_get_id_str(struct tipc_node *node);
void tipc_node_put(struct tipc_node *node);
void tipc_node_get(struct tipc_node *node);
struct tipc_node *tipc_node_create(struct net *net, u32 addr, u8 *peer_id,
u16 capabilities, u32 hash_mixes,
bool preliminary);
#ifdef CONFIG_TIPC_CRYPTO
struct tipc_crypto *tipc_node_crypto_rx(struct tipc_node *__n);
struct tipc_crypto *tipc_node_crypto_rx_by_list(struct list_head *pos);
struct tipc_crypto *tipc_node_crypto_rx_by_addr(struct net *net, u32 addr);
#endif
u32 tipc_node_try_addr(struct net *net, u8 *id, u32 addr);
void tipc_node_check_dest(struct net *net, u32 onode, u8 *peer_id128,
......
......@@ -74,6 +74,15 @@ static struct ctl_table tipc_table[] = {
.proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ONE,
},
{
.procname = "key_exchange_enabled",
.data = &sysctl_tipc_key_exchange_enabled,
.maxlen = sizeof(sysctl_tipc_key_exchange_enabled),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_ONE,
},
#endif
{
.procname = "bc_retruni",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment