linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH BlueZ v6 0/2] mesh: node dir Restructure, and keyring
@ 2019-05-09 21:33 Brian Gix
  2019-05-09 21:33 ` [PATCH BlueZ v6 1/2] mesh: Reconfigure node storage tree Brian Gix
  2019-05-09 21:33 ` [PATCH BlueZ v6 2/2] mesh: Add key storage Brian Gix
  0 siblings, 2 replies; 4+ messages in thread
From: Brian Gix @ 2019-05-09 21:33 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, brian.gix, michal.lowas-rzechonek

This version 6 allows the legal file descriptor == 0, and uses lseek()
to streamline checking network bindings when updating application keys.


Brian Gix (2):
  mesh: Reconfigure node storage tree
  mesh: Add key storage

 Makefile.mesh  |   1 +
 mesh/README    |  34 ++++++-
 mesh/keyring.c | 298 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 mesh/keyring.h |  49 ++++++++++
 mesh/node.c    |  16 ++--
 mesh/node.h    |   4 +-
 mesh/storage.c | 144 +++++++++++++++++-----------
 7 files changed, 479 insertions(+), 67 deletions(-)
 create mode 100644 mesh/keyring.c
 create mode 100644 mesh/keyring.h

-- 
2.14.5


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH BlueZ v6 1/2] mesh: Reconfigure node storage tree
  2019-05-09 21:33 [PATCH BlueZ v6 0/2] mesh: node dir Restructure, and keyring Brian Gix
@ 2019-05-09 21:33 ` Brian Gix
  2019-05-13 19:32   ` Gix, Brian
  2019-05-09 21:33 ` [PATCH BlueZ v6 2/2] mesh: Add key storage Brian Gix
  1 sibling, 1 reply; 4+ messages in thread
From: Brian Gix @ 2019-05-09 21:33 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, brian.gix, michal.lowas-rzechonek

Add a tree structure to a nodes data storage, in order to safely handle
Replay Protection list, Refactor local Sequence Numbers, and add Key
storage for Config Client nodes.
---
 mesh/README    |  34 +++++++++++++-
 mesh/node.c    |  16 ++++---
 mesh/node.h    |   4 +-
 mesh/storage.c | 144 ++++++++++++++++++++++++++++++++++-----------------------
 4 files changed, 131 insertions(+), 67 deletions(-)

diff --git a/mesh/README b/mesh/README
index ca223a6d8..82fd5a017 100644
--- a/mesh/README
+++ b/mesh/README
@@ -36,8 +36,40 @@ Each subdirectory contains the following files:
 		provisioner/configuration client
 	- node.json.bak:
 		a backup that the last known good node configuration.
+	- seq_num:
+		File containing next sequence number to use
+	- seq_num.bak:
+		Backup of the sequence number. This may be larger than the
+		actual sequence number being used at runtime, to prevent re-use
+		of sequence numbers in the event of an unexpected restart.
+	- ./rpl/:
+		Directory to store the sequence numbers of remote nodes, as
+		required by Replay Protection List (RPL) parameters.
+		- xxxx:
+			Files named for remote Unicast addresses, and contain
+			last received iv_index + seq_num from each SRC address.
+	- ./dev_keys/:
+		Directory to store remote Device keys. This is only created/used
+		by Configuration Client (Network administration) nodes.
+		- xxxx:
+			Files named for remote Unicast addresses, and contains
+			16 octet key.
+	- ./net_keys/:
+		Directory to store network subnet keys. This is only
+		created/used by Configuration Client (Network administration)
+		nodes.
+		- xxx:
+			Files named for subnet index, and contains key refresh
+			phase, and old/new versions of the key.
+	- ./app_keys/:
+		Directory to store application keys. This is only created/used
+		by Configuration Client (Network administration) nodes.
+		- xxx:
+			Files named for application index, and contains bound
+			subnet index, and old/new versions of the key.
 
-The files are in JSON format.
+The node.json and node.json.bak are in JSON format. All other files are stored
+in little endian binary format.
 
 Information
 ===========
diff --git a/mesh/node.c b/mesh/node.c
index 5904b116c..6f95c8d1c 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -79,7 +79,7 @@ struct mesh_node {
 	char *owner;
 	char *path;
 	void *jconfig;
-	char *cfg_file;
+	char *node_path;
 	uint32_t disc_watch;
 	time_t upd_sec;
 	uint32_t seq_number;
@@ -236,6 +236,7 @@ static void free_node_resources(void *data)
 	l_free(node->comp);
 	l_free(node->app_path);
 	l_free(node->owner);
+	l_free(node->node_path);
 
 	if (node->disc_watch)
 		l_dbus_remove_watch(dbus_get_bus(), node->disc_watch);
@@ -259,7 +260,7 @@ void node_remove(struct mesh_node *node)
 
 	l_queue_remove(nodes, node);
 
-	if (node->cfg_file)
+	if (node->node_path)
 		storage_remove_node_config(node);
 
 	free_node_resources(node);
@@ -395,7 +396,7 @@ static void cleanup_node(void *data)
 	struct mesh_net *net = node->net;
 
 	/* Save local node configuration */
-	if (node->cfg_file) {
+	if (node->node_path) {
 
 		/* Preserve the last sequence number */
 		storage_write_sequence_number(net, mesh_net_get_seq_num(net));
@@ -1859,14 +1860,15 @@ void *node_jconfig_get(struct mesh_node *node)
 	return node->jconfig;
 }
 
-void node_cfg_file_set(struct mesh_node *node, char *cfg)
+void node_path_set(struct mesh_node *node, char *path)
 {
-	node->cfg_file = cfg;
+	l_free(node->node_path);
+	node->node_path = l_strdup(path);
 }
 
-char *node_cfg_file_get(struct mesh_node *node)
+char *node_path_get(struct mesh_node *node)
 {
-	return node->cfg_file;
+	return node->node_path;
 }
 
 struct mesh_net *node_get_net(struct mesh_node *node)
diff --git a/mesh/node.h b/mesh/node.h
index 1be4de1da..1194ff837 100644
--- a/mesh/node.h
+++ b/mesh/node.h
@@ -95,5 +95,5 @@ bool node_dbus_init(struct l_dbus *bus);
 void node_cleanup_all(void);
 void node_jconfig_set(struct mesh_node *node, void *jconfig);
 void *node_jconfig_get(struct mesh_node *node);
-void node_cfg_file_set(struct mesh_node *node, char *cfg);
-char *node_cfg_file_get(struct mesh_node *node);
+void node_path_set(struct mesh_node *node, char *path);
+char *node_path_get(struct mesh_node *node);
diff --git a/mesh/storage.c b/mesh/storage.c
index 2580cbe7f..f4e23bf49 100644
--- a/mesh/storage.c
+++ b/mesh/storage.c
@@ -28,6 +28,7 @@
 #include <unistd.h>
 #include <dirent.h>
 #include <libgen.h>
+#include <ftw.h>
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -49,13 +50,30 @@
 
 struct write_info {
 	json_object *jnode;
-	const char *config_name;
+	const char *node_path;
 	void *user_data;
 	mesh_status_func_t cb;
 };
 
+static const char *cfg_name = "/node.json";
+static const char *bak_ext = ".bak";
+static const char *tmp_ext = ".tmp";
 static const char *storage_dir;
 
+/* This is a thread-safe always malloced version of dirname which will work
+ * regardless of which underlying dirname() implementation is used.
+ */
+static char *alloc_dirname(const char *path)
+{
+	char *tmp = l_strdup(path);
+	char *dir;
+
+	dir = dirname(tmp);
+	strncpy(tmp, dir, strlen(path) + 1);
+
+	return tmp;
+}
+
 static bool read_node_cb(struct mesh_db_node *db_node, void *user_data)
 {
 	struct mesh_node *node = user_data;
@@ -166,7 +184,7 @@ static bool parse_node(struct mesh_node *node, json_object *jnode)
 	return true;
 }
 
-static bool parse_config(char *in_file, char *out_file, const uint8_t uuid[16])
+static bool parse_config(char *in_file, char *out_dir, const uint8_t uuid[16])
 {
 	int fd;
 	char *str;
@@ -213,7 +231,7 @@ static bool parse_config(char *in_file, char *out_file, const uint8_t uuid[16])
 	}
 
 	node_jconfig_set(node, jnode);
-	node_cfg_file_set(node, out_file);
+	node_path_set(node, out_dir);
 
 done:
 	close(fd);
@@ -430,15 +448,12 @@ static bool save_config(json_object *jnode, const char *config_name)
 static void idle_save_config(void *user_data)
 {
 	struct write_info *info = user_data;
-	size_t len = strlen(info->config_name) + 5;
-	char *tmp = l_malloc(len);
-	char *bak = l_malloc(len);
+	char *tmp, *bak, *cfg;
 	bool result = false;
 
-	strncpy(tmp, info->config_name, len);
-	strncpy(bak, info->config_name, len);
-	tmp = strncat(tmp, ".tmp", 5);
-	bak = strncat(bak, ".bak", 5);
+	cfg = l_strdup_printf("%s%s", info->node_path, cfg_name);
+	tmp = l_strdup_printf("%s%s", cfg, tmp_ext);
+	bak = l_strdup_printf("%s%s", cfg, bak_ext);
 	remove(tmp);
 
 	l_debug("Storage-Wrote");
@@ -446,13 +461,14 @@ static void idle_save_config(void *user_data)
 
 	if (result) {
 		remove(bak);
-		rename(info->config_name, bak);
-		rename(tmp, info->config_name);
+		rename(cfg, bak);
+		rename(tmp, cfg);
 	}
 
 	remove(tmp);
 	l_free(tmp);
 	l_free(bak);
+	l_free(cfg);
 
 	if (info->cb)
 		info->cb(info->user_data, result);
@@ -467,7 +483,7 @@ void storage_save_config(struct mesh_node *node, bool no_wait,
 
 	info = l_new(struct write_info, 1);
 	info->jnode = node_jconfig_get(node);
-	info->config_name = node_cfg_file_get(node);
+	info->node_path = node_path_get(node);
 	info->cb = cb;
 	info->user_data = user_data;
 
@@ -517,6 +533,7 @@ bool storage_load_nodes(const char *dir_name)
 {
 	DIR *dir;
 	struct dirent *entry;
+	size_t path_len = strlen(dir_name) + strlen(cfg_name) + strlen(bak_ext);
 
 	create_dir(dir_name);
 	dir = opendir(dir_name);
@@ -529,33 +546,37 @@ bool storage_load_nodes(const char *dir_name)
 	storage_dir = dir_name;
 
 	while ((entry = readdir(dir)) != NULL) {
-		char *cfg;
-		char *bak;
+		char *dir, *cfg, *bak;
 		uint8_t uuid[16];
+		size_t node_len;
 
 		if (entry->d_type != DT_DIR)
 			continue;
 
-		if (!str2hex(entry->d_name, strlen(entry->d_name), uuid, sizeof(uuid)))
+		/* Check path length */
+		node_len = strlen(entry->d_name);
+		if (path_len + node_len + 1 >= PATH_MAX)
 			continue;
 
-		cfg = l_strdup_printf("%s/%s/node.json", dir_name, entry->d_name);
-
-		if (parse_config(cfg, cfg, uuid))
+		if (!str2hex(entry->d_name, node_len, uuid, sizeof(uuid)))
 			continue;
 
-		/* Fall-back to Backup version */
-		bak = l_strdup_printf("%s/%s/node.json.bak", dir_name, entry->d_name);
+		dir = l_strdup_printf("%s/%s", dir_name, entry->d_name);
+		cfg = l_strdup_printf("%s%s", dir, cfg_name);
 
-		if (parse_config(bak, cfg, uuid)) {
-			remove(cfg);
-			rename(bak, cfg);
-			l_free(cfg);
-			continue;
-		}
+		if (!parse_config(cfg, dir, uuid)) {
 
+			/* Fall-back to Backup version */
+			bak = l_strdup_printf("%s%s", cfg, bak_ext);
+
+			if (parse_config(bak, dir, uuid)) {
+				remove(cfg);
+				rename(bak, cfg);
+			}
+			l_free(bak);
+		}
 		l_free(cfg);
-		l_free(bak);
+		l_free(dir);
 	}
 
 	return true;
@@ -566,8 +587,8 @@ bool storage_create_node_config(struct mesh_node *node, void *data)
 	struct mesh_db_node *db_node = data;
 	char uuid[33];
 	char name_buf[PATH_MAX];
-	char *filename;
 	json_object *jnode;
+	size_t max_len = strlen(cfg_name) + strlen(bak_ext);
 
 	if (!storage_dir)
 		return false;
@@ -578,25 +599,26 @@ bool storage_create_node_config(struct mesh_node *node, void *data)
 		return false;
 
 	if (!hex2str(node_uuid_get(node), 16, uuid, sizeof(uuid)))
-		return false;
+		goto fail;
 
 	snprintf(name_buf, PATH_MAX, "%s/%s", storage_dir, uuid);
 
+	if (strlen(name_buf) + max_len >= PATH_MAX)
+		goto fail;
+
 	/* Create a new directory and node.json file */
 	if (mkdir(name_buf, 0755) != 0)
 		goto fail;
 
-	filename = l_strdup_printf("%s/node.json", name_buf);
+	node_path_set(node, name_buf);
 
-	l_debug("New node config %s", filename);
+	snprintf(name_buf, PATH_MAX, "%s/%s%s", storage_dir, uuid, cfg_name);
+	l_debug("New node config %s", name_buf);
 
-	if (!save_config(jnode, filename)) {
-		l_free(filename);
+	if (!save_config(jnode, name_buf))
 		goto fail;
-	}
 
 	node_jconfig_set(node, jnode);
-	node_cfg_file_set(node, filename);
 
 	return true;
 fail:
@@ -604,13 +626,29 @@ fail:
 	return false;
 }
 
+static int del_fobject(const char *fpath, const struct stat *sb, int typeflag,
+						struct FTW *ftwbuf)
+{
+	switch (typeflag) {
+	case FTW_DP:
+		rmdir(fpath);
+		l_debug("RMDIR %s", fpath);
+		break;
+
+	case FTW_SL:
+	default:
+		remove(fpath);
+		l_debug("RM %s", fpath);
+		break;
+	}
+	return 0;
+}
+
 /* Permanently remove node configuration */
 void storage_remove_node_config(struct mesh_node *node)
 {
-	char *cfg;
+	char *node_path, *mesh_path, *mesh_name;
 	struct json_object *jnode;
-	const char *dir_name;
-	char *bak;
 
 	if (!node)
 		return;
@@ -621,25 +659,17 @@ void storage_remove_node_config(struct mesh_node *node)
 		json_object_put(jnode);
 	node_jconfig_set(node, NULL);
 
-	/* Delete node configuration file */
-	cfg = node_cfg_file_get(node);
-	if (!cfg)
-		return;
-
-	l_debug("Delete node config file %s", cfg);
-	remove(cfg);
-
-	/* Delete the backup file */
-	bak = l_strdup_printf("%s.bak", cfg);
-	remove(bak);
-	l_free(bak);
+	node_path = node_path_get(node);
+	l_debug("Delete node config %s", node_path);
 
-	/* Delete the node directory */
-	dir_name = dirname(cfg);
+	/* Make sure path name of node follows expected guidelines */
+	mesh_path = alloc_dirname(node_path);
+	mesh_name = basename(mesh_path);
+	if (strcmp(mesh_name, "mesh"))
+		goto done;
 
-	l_debug("Delete directory %s", dir_name);
-	rmdir(dir_name);
+	nftw(node_path, del_fobject, 5, FTW_DEPTH | FTW_PHYS);
 
-	l_free(cfg);
-	node_cfg_file_set(node, NULL);
+done:
+	l_free(mesh_path);
 }
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH BlueZ v6 2/2] mesh: Add key storage
  2019-05-09 21:33 [PATCH BlueZ v6 0/2] mesh: node dir Restructure, and keyring Brian Gix
  2019-05-09 21:33 ` [PATCH BlueZ v6 1/2] mesh: Reconfigure node storage tree Brian Gix
@ 2019-05-09 21:33 ` Brian Gix
  1 sibling, 0 replies; 4+ messages in thread
From: Brian Gix @ 2019-05-09 21:33 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: inga.stotland, brian.gix, michal.lowas-rzechonek

This implements internal key storage add/delete/fetch for the three
basic key types managed in Mesh: Network, Application and Device.

This key storage is separate from keys assigned to nodes within the
mesh, and are used to support Configuration Client functionality.
---
 Makefile.mesh  |   1 +
 mesh/keyring.c | 298 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 mesh/keyring.h |  49 ++++++++++
 3 files changed, 348 insertions(+)
 create mode 100644 mesh/keyring.c
 create mode 100644 mesh/keyring.h

diff --git a/Makefile.mesh b/Makefile.mesh
index 76e424b92..bccd4d946 100644
--- a/Makefile.mesh
+++ b/Makefile.mesh
@@ -25,6 +25,7 @@ mesh_sources = mesh/mesh.h mesh/mesh.c \
 				mesh/agent.h mesh/agent.c \
 				mesh/prov-acceptor.c mesh/prov-initiator.c \
 				mesh/pb-adv.h mesh/pb-adv.c \
+				mesh/keyring.h mesh/keyring.c \
 				mesh/mesh-defs.h
 libexec_PROGRAMS += mesh/bluetooth-meshd
 
diff --git a/mesh/keyring.c b/mesh/keyring.c
new file mode 100644
index 000000000..59aa1eaf4
--- /dev/null
+++ b/mesh/keyring.c
@@ -0,0 +1,298 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2019  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <libgen.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ell/ell.h>
+
+#include "mesh/mesh-defs.h"
+
+#include "mesh/net.h"
+#include "mesh/keyring.h"
+#include "mesh/mesh.h"
+#include "mesh/node.h"
+
+const char *dev_key_dir = "/dev_keys";
+const char *app_key_dir = "/app_keys";
+const char *net_key_dir = "/net_keys";
+
+bool keyring_put_net_key(struct mesh_node *node, uint16_t net_idx,
+						struct keyring_net_key *key)
+{
+	char *node_path;
+	char key_file[PATH_MAX];
+	bool result = false;
+	int fd;
+
+	if (!node || !key)
+		return false;
+
+	node_path = node_path_get(node);
+
+	if (strlen(node_path) + strlen(net_key_dir) + 1 + 3 >= PATH_MAX)
+		return false;
+
+	snprintf(key_file, PATH_MAX, "%s%s", node_path, net_key_dir);
+	mkdir(key_file, 0755);
+	snprintf(key_file, PATH_MAX, "%s%s/%3.3x", node_path, net_key_dir,
+								net_idx);
+	l_debug("Put Net Key %s", key_file);
+
+	fd = open(key_file, O_WRONLY | O_CREAT | O_TRUNC);
+	if (fd >= 0) {
+		if (write(fd, key, sizeof(*key)) == sizeof(*key))
+			result = true;
+
+		close(fd);
+	}
+
+	return result;
+}
+
+bool keyring_put_app_key(struct mesh_node *node, uint16_t app_idx,
+				uint16_t net_idx, struct keyring_app_key *key)
+{
+	char *node_path;
+	char key_file[PATH_MAX];
+	bool result = false;
+	int fd;
+
+	if (!node || !key)
+		return false;
+
+	node_path = node_path_get(node);
+
+	if (strlen(node_path) + strlen(app_key_dir) + 1 + 3 >= PATH_MAX)
+		return false;
+
+	snprintf(key_file, PATH_MAX, "%s%s", node_path, app_key_dir);
+	mkdir(key_file, 0755);
+	snprintf(key_file, PATH_MAX, "%s%s/%3.3x", node_path, app_key_dir,
+								app_idx);
+	l_debug("Put App Key %s", key_file);
+
+	fd = open(key_file, O_RDWR);
+	if (fd >= 0) {
+		struct keyring_app_key old_key;
+
+		if (read(fd, &old_key, sizeof(old_key)) == sizeof(old_key)) {
+			if (old_key.net_idx != net_idx) {
+				close(fd);
+				return false;
+			}
+		}
+		lseek(fd, 0, SEEK_SET);
+	} else
+		fd = open(key_file, O_WRONLY | O_CREAT | O_TRUNC);
+
+	if (fd >= 0) {
+		if (write(fd, key, sizeof(*key)) == sizeof(*key))
+			result = true;
+
+		close(fd);
+	}
+
+	return result;
+}
+
+bool keyring_put_remote_dev_key(struct mesh_node *node, uint16_t unicast,
+					uint8_t count, uint8_t dev_key[16])
+{
+	char *node_path;
+	char key_file[PATH_MAX];
+	bool result = true;
+	int fd, i;
+
+	if (!node)
+		return false;
+
+	node_path = node_path_get(node);
+
+	if (strlen(node_path) + strlen(dev_key_dir) + 1 + 4 >= PATH_MAX)
+		return false;
+
+	snprintf(key_file, PATH_MAX, "%s%s", node_path, dev_key_dir);
+	mkdir(key_file, 0755);
+
+	for (i = 0; i < count; i++) {
+		snprintf(key_file, PATH_MAX, "%s%s/%4.4x", node_path,
+						dev_key_dir, unicast + i);
+		l_debug("Put Dev Key %s", key_file);
+
+		fd = open(key_file, O_WRONLY | O_CREAT | O_TRUNC);
+		if (fd >= 0) {
+			if (write(fd, dev_key, 16) != 16)
+				result = false;
+
+			close(fd);
+		} else
+			result = false;
+	}
+
+	return result;
+}
+
+bool keyring_get_net_key(struct mesh_node *node, uint16_t net_idx,
+						struct keyring_net_key *key)
+{
+	char *node_path;
+	char key_file[PATH_MAX];
+	bool result = false;
+	int fd;
+
+	if (!node || !key)
+		return false;
+
+	node_path = node_path_get(node);
+	snprintf(key_file, PATH_MAX, "%s%s/%3.3x", node_path, net_key_dir,
+								net_idx);
+
+	fd = open(key_file, O_RDONLY);
+	if (fd >= 0) {
+		if (read(fd, key, sizeof(*key)) == sizeof(*key))
+			result = true;
+
+		close(fd);
+	}
+
+	return result;
+}
+
+bool keyring_get_app_key(struct mesh_node *node, uint16_t app_idx,
+						struct keyring_app_key *key)
+{
+	char *node_path;
+	char key_file[PATH_MAX];
+	bool result = false;
+	int fd;
+
+	if (!node || !key)
+		return false;
+
+	node_path = node_path_get(node);
+	snprintf(key_file, PATH_MAX, "%s%s/%3.3x", node_path, app_key_dir,
+								app_idx);
+
+	fd = open(key_file, O_RDONLY);
+	if (fd >= 0) {
+		if (read(fd, key, sizeof(*key)) == sizeof(*key))
+			result = true;
+
+		close(fd);
+	}
+
+	return result;
+}
+
+bool keyring_get_remote_dev_key(struct mesh_node *node, uint16_t unicast,
+							uint8_t dev_key[16])
+{
+	char *node_path;
+	char key_file[PATH_MAX];
+	bool result = false;
+	int fd;
+
+	if (!node)
+		return false;
+
+	node_path = node_path_get(node);
+	snprintf(key_file, PATH_MAX, "%s%s/%4.4x", node_path, dev_key_dir,
+								unicast);
+
+	fd = open(key_file, O_RDONLY);
+	if (fd >= 0) {
+		if (read(fd, dev_key, 16) == 16)
+			result = true;
+
+		close(fd);
+	}
+
+	return result;
+}
+
+bool keyring_del_net_key(struct mesh_node *node, uint16_t net_idx)
+{
+	char *node_path;
+	char key_file[PATH_MAX];
+
+	if (!node)
+		return false;
+
+	node_path = node_path_get(node);
+	snprintf(key_file, PATH_MAX, "%s%s/%3.3x", node_path, net_key_dir,
+								net_idx);
+	l_debug("RM Net Key %s", key_file);
+	remove(key_file);
+
+	/* TODO: See if it is easiest to delete all bound App keys here */
+	/* TODO: see nftw() */
+
+	return true;
+}
+
+bool keyring_del_app_key(struct mesh_node *node, uint16_t app_idx)
+{
+	char *node_path;
+	char key_file[PATH_MAX];
+
+	if (!node)
+		return false;
+
+	node_path = node_path_get(node);
+	snprintf(key_file, PATH_MAX, "%s%s/%3.3x", node_path, app_key_dir,
+								app_idx);
+	l_debug("RM App Key %s", key_file);
+	remove(key_file);
+
+	return true;
+}
+
+bool keyring_del_remote_dev_key(struct mesh_node *node, uint16_t unicast,
+								uint8_t count)
+{
+	char *node_path;
+	char key_file[PATH_MAX];
+	int i;
+
+	if (!node)
+		return false;
+
+	node_path = node_path_get(node);
+	for (i = 0; i < count; i++) {
+		snprintf(key_file, PATH_MAX, "%s%s/%4.4x", node_path,
+						dev_key_dir, unicast + i);
+		l_debug("RM Dev Key %s", key_file);
+		remove(key_file);
+	}
+
+	return true;
+}
diff --git a/mesh/keyring.h b/mesh/keyring.h
new file mode 100644
index 000000000..167191013
--- /dev/null
+++ b/mesh/keyring.h
@@ -0,0 +1,49 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2019  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ */
+
+struct keyring_net_key {
+	uint16_t net_idx;
+	uint8_t phase;
+	uint8_t old_key[16];
+	uint8_t new_key[16];
+};
+
+struct keyring_app_key {
+	uint16_t app_idx;
+	uint16_t net_idx;
+	uint8_t old_key[16];
+	uint8_t new_key[16];
+};
+
+bool keyring_put_net_key(struct mesh_node *node, uint16_t net_idx,
+						struct keyring_net_key *key);
+bool keyring_get_net_key(struct mesh_node *node, uint16_t net_idx,
+						struct keyring_net_key *key);
+bool keyring_del_net_key(struct mesh_node *node, uint16_t net_idx);
+bool keyring_put_app_key(struct mesh_node *node, uint16_t app_idx,
+				uint16_t net_idx, struct keyring_app_key *key);
+bool keyring_get_app_key(struct mesh_node *node, uint16_t app_idx,
+						struct keyring_app_key *key);
+bool keyring_del_app_key(struct mesh_node *node, uint16_t app_idx);
+bool keyring_get_remote_dev_key(struct mesh_node *node, uint16_t unicast,
+							uint8_t dev_key[16]);
+bool keyring_put_remote_dev_key(struct mesh_node *node, uint16_t unicast,
+					uint8_t count, uint8_t dev_key[16]);
+bool keyring_del_remote_dev_key(struct mesh_node *node, uint16_t unicast,
+								uint8_t count);
-- 
2.14.5


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH BlueZ v6 1/2] mesh: Reconfigure node storage tree
  2019-05-09 21:33 ` [PATCH BlueZ v6 1/2] mesh: Reconfigure node storage tree Brian Gix
@ 2019-05-13 19:32   ` Gix, Brian
  0 siblings, 0 replies; 4+ messages in thread
From: Gix, Brian @ 2019-05-13 19:32 UTC (permalink / raw)
  To: linux-bluetooth@vger.kernel.org
  Cc: michal.lowas-rzechonek@silvair.com, Stotland, Inga

Patch-set applied


On Thu, 2019-05-09 at 14:33 -0700, Brian Gix wrote:
> Add a tree structure to a nodes data storage, in order to safely handle
> Replay Protection list, Refactor local Sequence Numbers, and add Key
> storage for Config Client nodes.
> ---
>  mesh/README    |  34 +++++++++++++-
>  mesh/node.c    |  16 ++++---
>  mesh/node.h    |   4 +-
>  mesh/storage.c | 144 ++++++++++++++++++++++++++++++++++-----------------------
>  4 files changed, 131 insertions(+), 67 deletions(-)
> 
> diff --git a/mesh/README b/mesh/README
> index ca223a6d8..82fd5a017 100644
> --- a/mesh/README
> +++ b/mesh/README
> @@ -36,8 +36,40 @@ Each subdirectory contains the following files:
>  		provisioner/configuration client
>  	- node.json.bak:
>  		a backup that the last known good node configuration.
> +	- seq_num:
> +		File containing next sequence number to use
> +	- seq_num.bak:
> +		Backup of the sequence number. This may be larger than the
> +		actual sequence number being used at runtime, to prevent re-use
> +		of sequence numbers in the event of an unexpected restart.
> +	- ./rpl/:
> +		Directory to store the sequence numbers of remote nodes, as
> +		required by Replay Protection List (RPL) parameters.
> +		- xxxx:
> +			Files named for remote Unicast addresses, and contain
> +			last received iv_index + seq_num from each SRC address.
> +	- ./dev_keys/:
> +		Directory to store remote Device keys. This is only created/used
> +		by Configuration Client (Network administration) nodes.
> +		- xxxx:
> +			Files named for remote Unicast addresses, and contains
> +			16 octet key.
> +	- ./net_keys/:
> +		Directory to store network subnet keys. This is only
> +		created/used by Configuration Client (Network administration)
> +		nodes.
> +		- xxx:
> +			Files named for subnet index, and contains key refresh
> +			phase, and old/new versions of the key.
> +	- ./app_keys/:
> +		Directory to store application keys. This is only created/used
> +		by Configuration Client (Network administration) nodes.
> +		- xxx:
> +			Files named for application index, and contains bound
> +			subnet index, and old/new versions of the key.
>  
> -The files are in JSON format.
> +The node.json and node.json.bak are in JSON format. All other files are stored
> +in little endian binary format.
>  
>  Information
>  ===========
> diff --git a/mesh/node.c b/mesh/node.c
> index 5904b116c..6f95c8d1c 100644
> --- a/mesh/node.c
> +++ b/mesh/node.c
> @@ -79,7 +79,7 @@ struct mesh_node {
>  	char *owner;
>  	char *path;
>  	void *jconfig;
> -	char *cfg_file;
> +	char *node_path;
>  	uint32_t disc_watch;
>  	time_t upd_sec;
>  	uint32_t seq_number;
> @@ -236,6 +236,7 @@ static void free_node_resources(void *data)
>  	l_free(node->comp);
>  	l_free(node->app_path);
>  	l_free(node->owner);
> +	l_free(node->node_path);
>  
>  	if (node->disc_watch)
>  		l_dbus_remove_watch(dbus_get_bus(), node->disc_watch);
> @@ -259,7 +260,7 @@ void node_remove(struct mesh_node *node)
>  
>  	l_queue_remove(nodes, node);
>  
> -	if (node->cfg_file)
> +	if (node->node_path)
>  		storage_remove_node_config(node);
>  
>  	free_node_resources(node);
> @@ -395,7 +396,7 @@ static void cleanup_node(void *data)
>  	struct mesh_net *net = node->net;
>  
>  	/* Save local node configuration */
> -	if (node->cfg_file) {
> +	if (node->node_path) {
>  
>  		/* Preserve the last sequence number */
>  		storage_write_sequence_number(net, mesh_net_get_seq_num(net));
> @@ -1859,14 +1860,15 @@ void *node_jconfig_get(struct mesh_node *node)
>  	return node->jconfig;
>  }
>  
> -void node_cfg_file_set(struct mesh_node *node, char *cfg)
> +void node_path_set(struct mesh_node *node, char *path)
>  {
> -	node->cfg_file = cfg;
> +	l_free(node->node_path);
> +	node->node_path = l_strdup(path);
>  }
>  
> -char *node_cfg_file_get(struct mesh_node *node)
> +char *node_path_get(struct mesh_node *node)
>  {
> -	return node->cfg_file;
> +	return node->node_path;
>  }
>  
>  struct mesh_net *node_get_net(struct mesh_node *node)
> diff --git a/mesh/node.h b/mesh/node.h
> index 1be4de1da..1194ff837 100644
> --- a/mesh/node.h
> +++ b/mesh/node.h
> @@ -95,5 +95,5 @@ bool node_dbus_init(struct l_dbus *bus);
>  void node_cleanup_all(void);
>  void node_jconfig_set(struct mesh_node *node, void *jconfig);
>  void *node_jconfig_get(struct mesh_node *node);
> -void node_cfg_file_set(struct mesh_node *node, char *cfg);
> -char *node_cfg_file_get(struct mesh_node *node);
> +void node_path_set(struct mesh_node *node, char *path);
> +char *node_path_get(struct mesh_node *node);
> diff --git a/mesh/storage.c b/mesh/storage.c
> index 2580cbe7f..f4e23bf49 100644
> --- a/mesh/storage.c
> +++ b/mesh/storage.c
> @@ -28,6 +28,7 @@
>  #include <unistd.h>
>  #include <dirent.h>
>  #include <libgen.h>
> +#include <ftw.h>
>  
>  #include <sys/types.h>
>  #include <sys/stat.h>
> @@ -49,13 +50,30 @@
>  
>  struct write_info {
>  	json_object *jnode;
> -	const char *config_name;
> +	const char *node_path;
>  	void *user_data;
>  	mesh_status_func_t cb;
>  };
>  
> +static const char *cfg_name = "/node.json";
> +static const char *bak_ext = ".bak";
> +static const char *tmp_ext = ".tmp";
>  static const char *storage_dir;
>  
> +/* This is a thread-safe always malloced version of dirname which will work
> + * regardless of which underlying dirname() implementation is used.
> + */
> +static char *alloc_dirname(const char *path)
> +{
> +	char *tmp = l_strdup(path);
> +	char *dir;
> +
> +	dir = dirname(tmp);
> +	strncpy(tmp, dir, strlen(path) + 1);
> +
> +	return tmp;
> +}
> +
>  static bool read_node_cb(struct mesh_db_node *db_node, void *user_data)
>  {
>  	struct mesh_node *node = user_data;
> @@ -166,7 +184,7 @@ static bool parse_node(struct mesh_node *node, json_object *jnode)
>  	return true;
>  }
>  
> -static bool parse_config(char *in_file, char *out_file, const uint8_t uuid[16])
> +static bool parse_config(char *in_file, char *out_dir, const uint8_t uuid[16])
>  {
>  	int fd;
>  	char *str;
> @@ -213,7 +231,7 @@ static bool parse_config(char *in_file, char *out_file, const uint8_t uuid[16])
>  	}
>  
>  	node_jconfig_set(node, jnode);
> -	node_cfg_file_set(node, out_file);
> +	node_path_set(node, out_dir);
>  
>  done:
>  	close(fd);
> @@ -430,15 +448,12 @@ static bool save_config(json_object *jnode, const char *config_name)
>  static void idle_save_config(void *user_data)
>  {
>  	struct write_info *info = user_data;
> -	size_t len = strlen(info->config_name) + 5;
> -	char *tmp = l_malloc(len);
> -	char *bak = l_malloc(len);
> +	char *tmp, *bak, *cfg;
>  	bool result = false;
>  
> -	strncpy(tmp, info->config_name, len);
> -	strncpy(bak, info->config_name, len);
> -	tmp = strncat(tmp, ".tmp", 5);
> -	bak = strncat(bak, ".bak", 5);
> +	cfg = l_strdup_printf("%s%s", info->node_path, cfg_name);
> +	tmp = l_strdup_printf("%s%s", cfg, tmp_ext);
> +	bak = l_strdup_printf("%s%s", cfg, bak_ext);
>  	remove(tmp);
>  
>  	l_debug("Storage-Wrote");
> @@ -446,13 +461,14 @@ static void idle_save_config(void *user_data)
>  
>  	if (result) {
>  		remove(bak);
> -		rename(info->config_name, bak);
> -		rename(tmp, info->config_name);
> +		rename(cfg, bak);
> +		rename(tmp, cfg);
>  	}
>  
>  	remove(tmp);
>  	l_free(tmp);
>  	l_free(bak);
> +	l_free(cfg);
>  
>  	if (info->cb)
>  		info->cb(info->user_data, result);
> @@ -467,7 +483,7 @@ void storage_save_config(struct mesh_node *node, bool no_wait,
>  
>  	info = l_new(struct write_info, 1);
>  	info->jnode = node_jconfig_get(node);
> -	info->config_name = node_cfg_file_get(node);
> +	info->node_path = node_path_get(node);
>  	info->cb = cb;
>  	info->user_data = user_data;
>  
> @@ -517,6 +533,7 @@ bool storage_load_nodes(const char *dir_name)
>  {
>  	DIR *dir;
>  	struct dirent *entry;
> +	size_t path_len = strlen(dir_name) + strlen(cfg_name) + strlen(bak_ext);
>  
>  	create_dir(dir_name);
>  	dir = opendir(dir_name);
> @@ -529,33 +546,37 @@ bool storage_load_nodes(const char *dir_name)
>  	storage_dir = dir_name;
>  
>  	while ((entry = readdir(dir)) != NULL) {
> -		char *cfg;
> -		char *bak;
> +		char *dir, *cfg, *bak;
>  		uint8_t uuid[16];
> +		size_t node_len;
>  
>  		if (entry->d_type != DT_DIR)
>  			continue;
>  
> -		if (!str2hex(entry->d_name, strlen(entry->d_name), uuid, sizeof(uuid)))
> +		/* Check path length */
> +		node_len = strlen(entry->d_name);
> +		if (path_len + node_len + 1 >= PATH_MAX)
>  			continue;
>  
> -		cfg = l_strdup_printf("%s/%s/node.json", dir_name, entry->d_name);
> -
> -		if (parse_config(cfg, cfg, uuid))
> +		if (!str2hex(entry->d_name, node_len, uuid, sizeof(uuid)))
>  			continue;
>  
> -		/* Fall-back to Backup version */
> -		bak = l_strdup_printf("%s/%s/node.json.bak", dir_name, entry->d_name);
> +		dir = l_strdup_printf("%s/%s", dir_name, entry->d_name);
> +		cfg = l_strdup_printf("%s%s", dir, cfg_name);
>  
> -		if (parse_config(bak, cfg, uuid)) {
> -			remove(cfg);
> -			rename(bak, cfg);
> -			l_free(cfg);
> -			continue;
> -		}
> +		if (!parse_config(cfg, dir, uuid)) {
>  
> +			/* Fall-back to Backup version */
> +			bak = l_strdup_printf("%s%s", cfg, bak_ext);
> +
> +			if (parse_config(bak, dir, uuid)) {
> +				remove(cfg);
> +				rename(bak, cfg);
> +			}
> +			l_free(bak);
> +		}
>  		l_free(cfg);
> -		l_free(bak);
> +		l_free(dir);
>  	}
>  
>  	return true;
> @@ -566,8 +587,8 @@ bool storage_create_node_config(struct mesh_node *node, void *data)
>  	struct mesh_db_node *db_node = data;
>  	char uuid[33];
>  	char name_buf[PATH_MAX];
> -	char *filename;
>  	json_object *jnode;
> +	size_t max_len = strlen(cfg_name) + strlen(bak_ext);
>  
>  	if (!storage_dir)
>  		return false;
> @@ -578,25 +599,26 @@ bool storage_create_node_config(struct mesh_node *node, void *data)
>  		return false;
>  
>  	if (!hex2str(node_uuid_get(node), 16, uuid, sizeof(uuid)))
> -		return false;
> +		goto fail;
>  
>  	snprintf(name_buf, PATH_MAX, "%s/%s", storage_dir, uuid);
>  
> +	if (strlen(name_buf) + max_len >= PATH_MAX)
> +		goto fail;
> +
>  	/* Create a new directory and node.json file */
>  	if (mkdir(name_buf, 0755) != 0)
>  		goto fail;
>  
> -	filename = l_strdup_printf("%s/node.json", name_buf);
> +	node_path_set(node, name_buf);
>  
> -	l_debug("New node config %s", filename);
> +	snprintf(name_buf, PATH_MAX, "%s/%s%s", storage_dir, uuid, cfg_name);
> +	l_debug("New node config %s", name_buf);
>  
> -	if (!save_config(jnode, filename)) {
> -		l_free(filename);
> +	if (!save_config(jnode, name_buf))
>  		goto fail;
> -	}
>  
>  	node_jconfig_set(node, jnode);
> -	node_cfg_file_set(node, filename);
>  
>  	return true;
>  fail:
> @@ -604,13 +626,29 @@ fail:
>  	return false;
>  }
>  
> +static int del_fobject(const char *fpath, const struct stat *sb, int typeflag,
> +						struct FTW *ftwbuf)
> +{
> +	switch (typeflag) {
> +	case FTW_DP:
> +		rmdir(fpath);
> +		l_debug("RMDIR %s", fpath);
> +		break;
> +
> +	case FTW_SL:
> +	default:
> +		remove(fpath);
> +		l_debug("RM %s", fpath);
> +		break;
> +	}
> +	return 0;
> +}
> +
>  /* Permanently remove node configuration */
>  void storage_remove_node_config(struct mesh_node *node)
>  {
> -	char *cfg;
> +	char *node_path, *mesh_path, *mesh_name;
>  	struct json_object *jnode;
> -	const char *dir_name;
> -	char *bak;
>  
>  	if (!node)
>  		return;
> @@ -621,25 +659,17 @@ void storage_remove_node_config(struct mesh_node *node)
>  		json_object_put(jnode);
>  	node_jconfig_set(node, NULL);
>  
> -	/* Delete node configuration file */
> -	cfg = node_cfg_file_get(node);
> -	if (!cfg)
> -		return;
> -
> -	l_debug("Delete node config file %s", cfg);
> -	remove(cfg);
> -
> -	/* Delete the backup file */
> -	bak = l_strdup_printf("%s.bak", cfg);
> -	remove(bak);
> -	l_free(bak);
> +	node_path = node_path_get(node);
> +	l_debug("Delete node config %s", node_path);
>  
> -	/* Delete the node directory */
> -	dir_name = dirname(cfg);
> +	/* Make sure path name of node follows expected guidelines */
> +	mesh_path = alloc_dirname(node_path);
> +	mesh_name = basename(mesh_path);
> +	if (strcmp(mesh_name, "mesh"))
> +		goto done;
>  
> -	l_debug("Delete directory %s", dir_name);
> -	rmdir(dir_name);
> +	nftw(node_path, del_fobject, 5, FTW_DEPTH | FTW_PHYS);
>  
> -	l_free(cfg);
> -	node_cfg_file_set(node, NULL);
> +done:
> +	l_free(mesh_path);
>  }

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2019-05-13 19:32 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-05-09 21:33 [PATCH BlueZ v6 0/2] mesh: node dir Restructure, and keyring Brian Gix
2019-05-09 21:33 ` [PATCH BlueZ v6 1/2] mesh: Reconfigure node storage tree Brian Gix
2019-05-13 19:32   ` Gix, Brian
2019-05-09 21:33 ` [PATCH BlueZ v6 2/2] mesh: Add key storage Brian Gix

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).