Two new commands are added as part of 'tipc node' command:

 $tipc node set key KEY [algname ALGNAME] [nodeid NODEID]
 $tipc node flush key

which enable user to set and remove AEAD keys in kernel TIPC.

For the 'set key' command, the given 'nodeid' parameter decides the
mode to be applied to the key, particularly:

- If NODEID is empty, the key is a 'cluster' key which will be used for
all message encryption/decryption from/to the node (i.e. both TX & RX).
The same key needs to be set in the other nodes i.e. the 'cluster key'
mode.

- If NODEID is own node, the key is used for message encryption (TX)
from the node. Whereas, if NODEID is a peer node, the key is for
message decryption (RX) from that peer node.
This is the 'per-node-key' mode that each nodes in the cluster has its
specific (TX) key.

Signed-off-by: Tuong Lien <tuong.t.l...@dektech.com.au>
---
 include/uapi/linux/tipc.h         |  21 ++++++
 include/uapi/linux/tipc_netlink.h |   4 ++
 tipc/misc.c                       |  38 +++++++++++
 tipc/misc.h                       |   1 +
 tipc/node.c                       | 133 +++++++++++++++++++++++++++++++++++++-
 5 files changed, 195 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/tipc.h b/include/uapi/linux/tipc.h
index e16cb4e2..b118ce9b 100644
--- a/include/uapi/linux/tipc.h
+++ b/include/uapi/linux/tipc.h
@@ -232,6 +232,27 @@ struct tipc_sioc_nodeid_req {
        char node_id[TIPC_NODEID_LEN];
 };
 
+/*
+ * TIPC Crypto, AEAD mode
+ */
+#define TIPC_AEAD_MAX_ALG_NAME (32)
+#define TIPC_AEAD_MIN_KEYLEN   (16 + 4)
+#define TIPC_AEAD_MAX_KEYLEN   (32 + 4)
+
+struct tipc_aead_key {
+       char alg_name[TIPC_AEAD_MAX_ALG_NAME];
+       unsigned int keylen;    /* in bytes */
+       char key[];
+};
+
+#define TIPC_AEAD_KEY_MAX_SIZE (sizeof(struct tipc_aead_key) + \
+                                               TIPC_AEAD_MAX_KEYLEN)
+
+static inline int tipc_aead_key_size(struct tipc_aead_key *key)
+{
+       return sizeof(*key) + key->keylen;
+}
+
 /* The macros and functions below are deprecated:
  */
 
diff --git a/include/uapi/linux/tipc_netlink.h 
b/include/uapi/linux/tipc_netlink.h
index efb958fd..6c2194ab 100644
--- a/include/uapi/linux/tipc_netlink.h
+++ b/include/uapi/linux/tipc_netlink.h
@@ -63,6 +63,8 @@ enum {
        TIPC_NL_PEER_REMOVE,
        TIPC_NL_BEARER_ADD,
        TIPC_NL_UDP_GET_REMOTEIP,
+       TIPC_NL_KEY_SET,
+       TIPC_NL_KEY_FLUSH,
 
        __TIPC_NL_CMD_MAX,
        TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1
@@ -160,6 +162,8 @@ enum {
        TIPC_NLA_NODE_UNSPEC,
        TIPC_NLA_NODE_ADDR,             /* u32 */
        TIPC_NLA_NODE_UP,               /* flag */
+       TIPC_NLA_NODE_ID,               /* data */
+       TIPC_NLA_NODE_KEY,              /* data */
 
        __TIPC_NLA_NODE_MAX,
        TIPC_NLA_NODE_MAX = __TIPC_NLA_NODE_MAX - 1
diff --git a/tipc/misc.c b/tipc/misc.c
index e4b1cd0c..1daf3072 100644
--- a/tipc/misc.c
+++ b/tipc/misc.c
@@ -98,6 +98,44 @@ int str2nodeid(char *str, uint8_t *id)
        return 0;
 }
 
+int str2key(char *str, struct tipc_aead_key *key)
+{
+       int len = strlen(str);
+       int ishex = 0;
+       int i;
+
+       /* Check if the input is a hex string (i.e. 0x...) */
+       if (len > 2 && strncmp(str, "0x", 2) == 0) {
+           ishex = is_hex(str + 2, len - 2 - 1);
+           if (ishex) {
+               len -= 2;
+               str += 2;
+           }
+       }
+
+       /* Obtain key: */
+       if (!ishex) {
+               key->keylen = len;
+               memcpy(key->key, str, len);
+       } else {
+               /* Convert hex string to key */
+               key->keylen = (len + 1) / 2;
+               for (i = 0; i < key->keylen; i++) {
+                       if (i == 0 && len % 2 != 0) {
+                               if (sscanf(str, "%1hhx", &key->key[0]) != 1)
+                                       return -1;
+                               str += 1;
+                               continue;
+                       }
+                       if (sscanf(str, "%2hhx", &key->key[i]) != 1)
+                               return -1;
+                       str += 2;
+               }
+       }
+
+       return 0;
+}
+
 void nodeid2str(uint8_t *id, char *str)
 {
        int i;
diff --git a/tipc/misc.h b/tipc/misc.h
index ff2f31f1..59309f68 100644
--- a/tipc/misc.h
+++ b/tipc/misc.h
@@ -18,5 +18,6 @@ uint32_t str2addr(char *str);
 int str2nodeid(char *str, uint8_t *id);
 void nodeid2str(uint8_t *id, char *str);
 void hash2nodestr(uint32_t hash, char *str);
+int str2key(char *str, struct tipc_aead_key *key);
 
 #endif
diff --git a/tipc/node.c b/tipc/node.c
index 2fec6753..fc81bd30 100644
--- a/tipc/node.c
+++ b/tipc/node.c
@@ -157,6 +157,111 @@ static int cmd_node_set_nodeid(struct nlmsghdr *nlh, 
const struct cmd *cmd,
        return msg_doit(nlh, NULL, NULL);
 }
 
+static void cmd_node_set_key_help(struct cmdl *cmdl)
+{
+       fprintf(stderr,
+               "Usage: %s node set key KEY [algname ALGNAME] [nodeid 
NODEID]\n\n"
+               "PROPERTIES\n"
+               " KEY                   - Symmetric KEY & SALT as a normal or 
hex string\n"
+               "                         that consists of two parts:\n"
+               "                         [KEY: 16, 24 or 32 octets][SALT: 4 
octets]\n\n"
+               " algname ALGNAME       - Default: \"gcm(aes)\"\n\n"
+               " nodeid NODEID         - Own or peer node identity to which 
the key will\n"
+               "                         be attached. If not present, the key 
is a cluster\n"
+               "                         key!\n\n"
+               "EXAMPLES\n"
+               "  %s node set key this_is_a_key16_salt algname \"gcm(aes)\" 
nodeid node1\n"
+               "  %s node set key 0x746869735F69735F615F6B657931365F73616C74 
nodeid node2\n\n",
+               cmdl->argv[0], cmdl->argv[0], cmdl->argv[0]);
+}
+
+static int cmd_node_set_key(struct nlmsghdr *nlh, const struct cmd *cmd,
+                           struct cmdl *cmdl, void *data)
+{
+       struct {
+               struct tipc_aead_key key;
+               char mem[TIPC_AEAD_MAX_KEYLEN + 1];
+       } input = {};
+       struct opt opts[] = {
+               { "algname",    OPT_KEYVAL,     NULL },
+               { "nodeid",     OPT_KEYVAL,     NULL },
+               { NULL }
+       };
+       struct nlattr *nest;
+       struct opt *opt_algname, *opt_nodeid;
+       char buf[MNL_SOCKET_BUFFER_SIZE];
+       uint8_t id[TIPC_NODEID_LEN] = {0,};
+       int keysize;
+       char *str;
+
+       if (help_flag) {
+               (cmd->help)(cmdl);
+               return -EINVAL;
+       }
+
+       if (cmdl->optind >= cmdl->argc) {
+               fprintf(stderr, "error, missing key\n");
+               return -EINVAL;
+       }
+
+       /* Get user key */
+       str = shift_cmdl(cmdl);
+       if (str2key(str, &input.key)) {
+               fprintf(stderr, "error, invalid key input\n");
+               return -EINVAL;
+       }
+
+       if (parse_opts(opts, cmdl) < 0)
+               return -EINVAL;
+
+       /* Get algorithm name, default: "gcm(aes)" */
+       opt_algname = get_opt(opts, "algname");
+       if (!opt_algname)
+               strcpy(input.key.alg_name, "gcm(aes)");
+       else
+               strcpy(input.key.alg_name, opt_algname->val);
+
+       /* Get node identity */
+       opt_nodeid = get_opt(opts, "nodeid");
+       if (opt_nodeid && str2nodeid(opt_nodeid->val, id)) {
+               fprintf(stderr, "error, invalid node identity\n");
+               return -EINVAL;
+       }
+
+       /* Init & do the command */
+       nlh = msg_init(buf, TIPC_NL_KEY_SET);
+       if (!nlh) {
+               fprintf(stderr, "error, message initialisation failed\n");
+               return -1;
+       }
+       nest = mnl_attr_nest_start(nlh, TIPC_NLA_NODE);
+       keysize = tipc_aead_key_size(&input.key);
+       mnl_attr_put(nlh, TIPC_NLA_NODE_KEY, keysize, &input.key);
+       if (opt_nodeid)
+               mnl_attr_put(nlh, TIPC_NLA_NODE_ID, TIPC_NODEID_LEN, id);
+       mnl_attr_nest_end(nlh, nest);
+       return msg_doit(nlh, NULL, NULL);
+}
+
+static int cmd_node_flush_key(struct nlmsghdr *nlh, const struct cmd *cmd,
+                             struct cmdl *cmdl, void *data)
+{
+       char buf[MNL_SOCKET_BUFFER_SIZE];
+
+       if (help_flag) {
+               (cmd->help)(cmdl);
+               return -EINVAL;
+       }
+
+       /* Init & do the command */
+       nlh = msg_init(buf, TIPC_NL_KEY_FLUSH);
+       if (!nlh) {
+               fprintf(stderr, "error, message initialisation failed\n");
+               return -1;
+       }
+       return msg_doit(nlh, NULL, NULL);
+}
+
 static int nodeid_get_cb(const struct nlmsghdr *nlh, void *data)
 {
        struct nlattr *info[TIPC_NLA_MAX + 1] = {};
@@ -270,13 +375,34 @@ static int cmd_node_set_netid(struct nlmsghdr *nlh, const 
struct cmd *cmd,
        return msg_doit(nlh, NULL, NULL);
 }
 
+static void cmd_node_flush_help(struct cmdl *cmdl)
+{
+       fprintf(stderr,
+               "Usage: %s node flush PROPERTY\n\n"
+               "PROPERTIES\n"
+               " key                   - Flush all symmetric-keys\n",
+               cmdl->argv[0]);
+}
+
+static int cmd_node_flush(struct nlmsghdr *nlh, const struct cmd *cmd,
+                         struct cmdl *cmdl, void *data)
+{
+       const struct cmd cmds[] = {
+               { "key",        cmd_node_flush_key,     NULL },
+               { NULL }
+       };
+
+       return run_cmd(nlh, cmd, cmds, cmdl, NULL);
+}
+
 static void cmd_node_set_help(struct cmdl *cmdl)
 {
        fprintf(stderr,
                "Usage: %s node set PROPERTY\n\n"
                "PROPERTIES\n"
                " identity NODEID       - Set node identity\n"
-               " clusterid CLUSTERID   - Set local cluster id\n",
+               " clusterid CLUSTERID   - Set local cluster id\n"
+               " key PROPERTY          - Set symmetric-key\n",
                cmdl->argv[0]);
 }
 
@@ -288,6 +414,7 @@ static int cmd_node_set(struct nlmsghdr *nlh, const struct 
cmd *cmd,
                { "identity",   cmd_node_set_nodeid,    NULL },
                { "netid",      cmd_node_set_netid,     NULL },
                { "clusterid",  cmd_node_set_netid,     NULL },
+               { "key",        cmd_node_set_key,       cmd_node_set_key_help },
                { NULL }
        };
 
@@ -325,7 +452,8 @@ void cmd_node_help(struct cmdl *cmdl)
                "COMMANDS\n"
                " list                  - List remote nodes\n"
                " get                   - Get local node parameters\n"
-               " set                   - Set local node parameters\n",
+               " set                   - Set local node parameters\n"
+               " flush                 - Flush local node parameters\n",
                cmdl->argv[0]);
 }
 
@@ -336,6 +464,7 @@ int cmd_node(struct nlmsghdr *nlh, const struct cmd *cmd, 
struct cmdl *cmdl,
                { "list",       cmd_node_list,  NULL },
                { "get",        cmd_node_get,   cmd_node_get_help },
                { "set",        cmd_node_set,   cmd_node_set_help },
+               { "flush",      cmd_node_flush, cmd_node_flush_help},
                { NULL }
        };
 
-- 
2.13.7



_______________________________________________
tipc-discussion mailing list
tipc-discussion@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tipc-discussion

Reply via email to