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) ...@@ -254,6 +254,8 @@ static inline int tipc_aead_key_size(struct tipc_aead_key *key)
return sizeof(*key) + key->keylen; return sizeof(*key) + key->keylen;
} }
#define TIPC_REKEYING_NOW (~0U)
/* The macros and functions below are deprecated: /* The macros and functions below are deprecated:
*/ */
......
...@@ -165,6 +165,8 @@ enum { ...@@ -165,6 +165,8 @@ enum {
TIPC_NLA_NODE_UP, /* flag */ TIPC_NLA_NODE_UP, /* flag */
TIPC_NLA_NODE_ID, /* data */ TIPC_NLA_NODE_ID, /* data */
TIPC_NLA_NODE_KEY, /* 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 = __TIPC_NLA_NODE_MAX - 1 TIPC_NLA_NODE_MAX = __TIPC_NLA_NODE_MAX - 1
......
This diff is collapsed.
...@@ -67,6 +67,7 @@ enum { ...@@ -67,6 +67,7 @@ enum {
}; };
extern int sysctl_tipc_max_tfms __read_mostly; extern int sysctl_tipc_max_tfms __read_mostly;
extern int sysctl_tipc_key_exchange_enabled __read_mostly;
/** /**
* TIPC encryption message format: * TIPC encryption message format:
...@@ -74,7 +75,7 @@ extern int sysctl_tipc_max_tfms __read_mostly; ...@@ -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 * 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 * 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 | * w1:| Seqno |
* w2:| (8 octets) | * w2:| (8 octets) |
...@@ -101,6 +102,9 @@ extern int sysctl_tipc_max_tfms __read_mostly; ...@@ -101,6 +102,9 @@ extern int sysctl_tipc_max_tfms __read_mostly;
* RX : Currently RX active key corresponding to the destination * RX : Currently RX active key corresponding to the destination
* node's TX key (when the "D" bit is set) * node's TX key (when the "D" bit is set)
* K : Keep-alive bit (for RPS, LINK_PROTOCOL/STATE_MSG only) * 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 * Rsvd : Reserved bit, field
* Word1-2: * Word1-2:
* Seqno : The 64-bit sequence number of the encrypted message, also * Seqno : The 64-bit sequence number of the encrypted message, also
...@@ -117,7 +121,9 @@ struct tipc_ehdr { ...@@ -117,7 +121,9 @@ struct tipc_ehdr {
__u8 destined:1, __u8 destined:1,
user:4, user:4,
version:3; version:3;
__u8 reserved_1:3, __u8 reserved_1:1,
rx_nokey:1,
master_key:1,
keepalive:1, keepalive:1,
rx_key_active:2, rx_key_active:2,
tx_key:2; tx_key:2;
...@@ -128,7 +134,9 @@ struct tipc_ehdr { ...@@ -128,7 +134,9 @@ struct tipc_ehdr {
__u8 tx_key:2, __u8 tx_key:2,
rx_key_active:2, rx_key_active:2,
keepalive:1, keepalive:1,
reserved_1:3; master_key:1,
rx_nokey:1,
reserved_1:1;
#else #else
#error "Please fix <asm/byteorder.h>" #error "Please fix <asm/byteorder.h>"
#endif #endif
...@@ -158,10 +166,35 @@ int tipc_crypto_xmit(struct net *net, struct sk_buff **skb, ...@@ -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, int tipc_crypto_rcv(struct net *net, struct tipc_crypto *rx,
struct sk_buff **skb, struct tipc_bearer *b); struct sk_buff **skb, struct tipc_bearer *b);
int tipc_crypto_key_init(struct tipc_crypto *c, struct tipc_aead_key *ukey, 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); 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); 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 /* _TIPC_CRYPTO_H */
#endif #endif
...@@ -1250,6 +1250,11 @@ static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb, ...@@ -1250,6 +1250,11 @@ static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb,
case MSG_FRAGMENTER: case MSG_FRAGMENTER:
case BCAST_PROTOCOL: case BCAST_PROTOCOL:
return false; return false;
#ifdef CONFIG_TIPC_CRYPTO
case MSG_CRYPTO:
tipc_crypto_msg_rcv(l->net, skb);
return true;
#endif
default: default:
pr_warn("Dropping received illegal msg type\n"); pr_warn("Dropping received illegal msg type\n");
kfree_skb(skb); kfree_skb(skb);
......
...@@ -82,6 +82,7 @@ struct plist; ...@@ -82,6 +82,7 @@ struct plist;
#define NAME_DISTRIBUTOR 11 #define NAME_DISTRIBUTOR 11
#define MSG_FRAGMENTER 12 #define MSG_FRAGMENTER 12
#define LINK_CONFIG 13 #define LINK_CONFIG 13
#define MSG_CRYPTO 14
#define SOCK_WAKEUP 14 /* pseudo user */ #define SOCK_WAKEUP 14 /* pseudo user */
#define TOP_SRV 15 /* pseudo user */ #define TOP_SRV 15 /* pseudo user */
...@@ -127,7 +128,9 @@ struct tipc_skb_cb { ...@@ -127,7 +128,9 @@ struct tipc_skb_cb {
#ifdef CONFIG_TIPC_CRYPTO #ifdef CONFIG_TIPC_CRYPTO
u8 encrypted:1; u8 encrypted:1;
u8 decrypted:1; u8 decrypted:1;
u8 probe:1; #define SKB_PROBING 1
#define SKB_GRACING 2
u8 xmit_type:2;
u8 tx_clone_deferred:1; u8 tx_clone_deferred:1;
#endif #endif
}; };
...@@ -747,6 +750,9 @@ static inline void msg_set_nameupper(struct tipc_msg *m, u32 n) ...@@ -747,6 +750,9 @@ static inline void msg_set_nameupper(struct tipc_msg *m, u32 n)
#define GRP_RECLAIM_MSG 4 #define GRP_RECLAIM_MSG 4
#define GRP_REMIT_MSG 5 #define GRP_REMIT_MSG 5
/* Crypto message types */
#define KEY_DISTR_MSG 0
/* /*
* Word 1 * Word 1
*/ */
......
...@@ -108,6 +108,8 @@ const struct nla_policy tipc_nl_node_policy[TIPC_NLA_NODE_MAX + 1] = { ...@@ -108,6 +108,8 @@ const struct nla_policy tipc_nl_node_policy[TIPC_NLA_NODE_MAX + 1] = {
.len = TIPC_NODEID_LEN}, .len = TIPC_NODEID_LEN},
[TIPC_NLA_NODE_KEY] = { .type = NLA_BINARY, [TIPC_NLA_NODE_KEY] = { .type = NLA_BINARY,
.len = TIPC_AEAD_KEY_SIZE_MAX}, .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 */ /* Properties valid for media, bearer and link */
......
...@@ -278,6 +278,14 @@ struct tipc_crypto *tipc_node_crypto_rx_by_list(struct list_head *pos) ...@@ -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; 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 #endif
static void tipc_node_free(struct rcu_head *rp) static void tipc_node_free(struct rcu_head *rp)
...@@ -303,7 +311,7 @@ void tipc_node_put(struct tipc_node *node) ...@@ -303,7 +311,7 @@ void tipc_node_put(struct tipc_node *node)
kref_put(&node->kref, tipc_node_kref_release); 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); kref_get(&node->kref);
} }
...@@ -584,6 +592,9 @@ static void tipc_node_calculate_timer(struct tipc_node *n, struct tipc_link *l) ...@@ -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) 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); list_del_rcu(&node->list);
hlist_del_rcu(&node->hash); hlist_del_rcu(&node->hash);
tipc_node_put(node); tipc_node_put(node);
...@@ -2868,15 +2879,27 @@ static int tipc_nl_retrieve_nodeid(struct nlattr **attrs, u8 **node_id) ...@@ -2868,15 +2879,27 @@ static int tipc_nl_retrieve_nodeid(struct nlattr **attrs, u8 **node_id)
return 0; 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) static int __tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info)
{ {
struct nlattr *attrs[TIPC_NLA_NODE_MAX + 1]; struct nlattr *attrs[TIPC_NLA_NODE_MAX + 1];
struct net *net = sock_net(skb->sk); 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_node *n = NULL;
struct tipc_aead_key *ukey; struct tipc_aead_key *ukey;
struct tipc_crypto *c; bool rekeying = true, master_key = false;
u8 *id, *own_id; u8 *id, *own_id, mode;
u32 intv = 0;
int rc = 0; int rc = 0;
if (!info->attrs[TIPC_NLA_NODE]) 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) ...@@ -2886,52 +2909,66 @@ static int __tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info)
info->attrs[TIPC_NLA_NODE], info->attrs[TIPC_NLA_NODE],
tipc_nl_node_policy, info->extack); tipc_nl_node_policy, info->extack);
if (rc) if (rc)
goto exit; return rc;
own_id = tipc_own_id(net); own_id = tipc_own_id(net);
if (!own_id) { if (!own_id) {
rc = -EPERM; GENL_SET_ERR_MSG(info, "not found own node identity (set id?)");
goto exit; return -EPERM;
} }
rc = tipc_nl_retrieve_rekeying(attrs, &intv);
if (rc == -ENODATA)
rekeying = false;
rc = tipc_nl_retrieve_key(attrs, &ukey); rc = tipc_nl_retrieve_key(attrs, &ukey);
if (rc) if (rc == -ENODATA && rekeying)
goto exit; goto rekeying;
else if (rc)
return rc;
rc = tipc_aead_key_validate(ukey); rc = tipc_aead_key_validate(ukey, info);
if (rc) if (rc)
goto exit; return rc;
rc = tipc_nl_retrieve_nodeid(attrs, &id); rc = tipc_nl_retrieve_nodeid(attrs, &id);
switch (rc) { switch (rc) {
case -ENODATA: case -ENODATA:
/* Cluster key mode */ mode = CLUSTER_KEY;
rc = tipc_crypto_key_init(tn->crypto_tx, ukey, CLUSTER_KEY); master_key = !!(attrs[TIPC_NLA_NODE_KEY_MASTER]);
break; break;
case 0: case 0:
/* Per-node key mode */ mode = PER_NODE_KEY;
if (!memcmp(id, own_id, NODE_ID_LEN)) { if (memcmp(id, own_id, NODE_ID_LEN)) {
c = tn->crypto_tx;
} else {
n = tipc_node_find_by_id(net, id) ?: n = tipc_node_find_by_id(net, id) ?:
tipc_node_create(net, 0, id, 0xffffu, 0, true); tipc_node_create(net, 0, id, 0xffffu, 0, true);
if (unlikely(!n)) { if (unlikely(!n))
rc = -ENOMEM; return -ENOMEM;
break;
}
c = n->crypto_rx; c = n->crypto_rx;
} }
break;
default:
return rc;
}
rc = tipc_crypto_key_init(c, ukey, PER_NODE_KEY); /* Initiate the TX/RX key */
rc = tipc_crypto_key_init(c, ukey, mode, master_key);
if (n) if (n)
tipc_node_put(n); tipc_node_put(n);
break;
default: if (unlikely(rc < 0)) {
break; 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);
} }
exit: return 0;
return (rc < 0) ? rc : 0;
} }
int tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info) 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, ...@@ -2958,7 +2995,6 @@ static int __tipc_nl_node_flush_key(struct sk_buff *skb,
tipc_crypto_key_flush(n->crypto_rx); tipc_crypto_key_flush(n->crypto_rx);
rcu_read_unlock(); rcu_read_unlock();
pr_info("All keys are flushed!\n");
return 0; return 0;
} }
......
...@@ -79,12 +79,14 @@ bool tipc_node_get_id(struct net *net, u32 addr, u8 *id); ...@@ -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); u32 tipc_node_get_addr(struct tipc_node *node);
char *tipc_node_get_id_str(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_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, struct tipc_node *tipc_node_create(struct net *net, u32 addr, u8 *peer_id,
u16 capabilities, u32 hash_mixes, u16 capabilities, u32 hash_mixes,
bool preliminary); bool preliminary);
#ifdef CONFIG_TIPC_CRYPTO #ifdef CONFIG_TIPC_CRYPTO
struct tipc_crypto *tipc_node_crypto_rx(struct tipc_node *__n); 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_list(struct list_head *pos);
struct tipc_crypto *tipc_node_crypto_rx_by_addr(struct net *net, u32 addr);
#endif #endif
u32 tipc_node_try_addr(struct net *net, u8 *id, u32 addr); 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, void tipc_node_check_dest(struct net *net, u32 onode, u8 *peer_id128,
......
...@@ -74,6 +74,15 @@ static struct ctl_table tipc_table[] = { ...@@ -74,6 +74,15 @@ static struct ctl_table tipc_table[] = {
.proc_handler = proc_dointvec_minmax, .proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ONE, .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 #endif
{ {
.procname = "bc_retruni", .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