tipc: add support for AEAD key setting via netlink

This commit adds two netlink commands to TIPC in order for user to be
able to set or remove AEAD keys:
- TIPC_NL_KEY_SET
- TIPC_NL_KEY_FLUSH

When the 'KEY_SET' is given along with the key data, the key will be
initiated and attached to TIPC crypto. On the other hand, the
'KEY_FLUSH' command will remove all existing keys if any.

Acked-by: Ying Xue <ying.xue@windreiver.com>
Acked-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: Tuong Lien <tuong.t.lien@dektech.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Tuong Lien
2019-11-08 12:05:12 +07:00
committed by David S. Miller
parent fc1b6d6de2
commit e1f32190cf
4 changed files with 160 additions and 1 deletions

View File

@@ -2760,6 +2760,141 @@ int tipc_nl_node_dump_monitor_peer(struct sk_buff *skb,
return skb->len;
}
#ifdef CONFIG_TIPC_CRYPTO
static int tipc_nl_retrieve_key(struct nlattr **attrs,
struct tipc_aead_key **key)
{
struct nlattr *attr = attrs[TIPC_NLA_NODE_KEY];
if (!attr)
return -ENODATA;
*key = (struct tipc_aead_key *)nla_data(attr);
if (nla_len(attr) < tipc_aead_key_size(*key))
return -EINVAL;
return 0;
}
static int tipc_nl_retrieve_nodeid(struct nlattr **attrs, u8 **node_id)
{
struct nlattr *attr = attrs[TIPC_NLA_NODE_ID];
if (!attr)
return -ENODATA;
if (nla_len(attr) < TIPC_NODEID_LEN)
return -EINVAL;
*node_id = (u8 *)nla_data(attr);
return 0;
}
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_node *n = NULL;
struct tipc_aead_key *ukey;
struct tipc_crypto *c;
u8 *id, *own_id;
int rc = 0;
if (!info->attrs[TIPC_NLA_NODE])
return -EINVAL;
rc = nla_parse_nested(attrs, TIPC_NLA_NODE_MAX,
info->attrs[TIPC_NLA_NODE],
tipc_nl_node_policy, info->extack);
if (rc)
goto exit;
own_id = tipc_own_id(net);
if (!own_id) {
rc = -EPERM;
goto exit;
}
rc = tipc_nl_retrieve_key(attrs, &ukey);
if (rc)
goto exit;
rc = tipc_aead_key_validate(ukey);
if (rc)
goto exit;
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);
break;
case 0:
/* Per-node key mode */
if (!memcmp(id, own_id, NODE_ID_LEN)) {
c = tn->crypto_tx;
} else {
n = tipc_node_find_by_id(net, id) ?:
tipc_node_create(net, 0, id, 0xffffu, 0, true);
if (unlikely(!n)) {
rc = -ENOMEM;
break;
}
c = n->crypto_rx;
}
rc = tipc_crypto_key_init(c, ukey, PER_NODE_KEY);
if (n)
tipc_node_put(n);
break;
default:
break;
}
exit:
return (rc < 0) ? rc : 0;
}
int tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info)
{
int err;
rtnl_lock();
err = __tipc_nl_node_set_key(skb, info);
rtnl_unlock();
return err;
}
int __tipc_nl_node_flush_key(struct sk_buff *skb, struct genl_info *info)
{
struct net *net = sock_net(skb->sk);
struct tipc_net *tn = tipc_net(net);
struct tipc_node *n;
tipc_crypto_key_flush(tn->crypto_tx);
rcu_read_lock();
list_for_each_entry_rcu(n, &tn->node_list, list)
tipc_crypto_key_flush(n->crypto_rx);
rcu_read_unlock();
pr_info("All keys are flushed!\n");
return 0;
}
int tipc_nl_node_flush_key(struct sk_buff *skb, struct genl_info *info)
{
int err;
rtnl_lock();
err = __tipc_nl_node_flush_key(skb, info);
rtnl_unlock();
return err;
}
#endif
/**
* tipc_node_dump - dump TIPC node data
* @n: tipc node to be dumped