summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDimitri Staessens <dimitri@ouroboros.rocks>2025-08-13 09:03:20 +0200
committerDimitri Staessens <dimitri@ouroboros.rocks>2025-08-18 20:57:23 +0200
commite35302ca0ab64edd21b9d8e40d3aa74a3a4f4f7e (patch)
tree348711a66a585f982b19979f083e601fc85ed605 /src
parentf1fcec220c8454cb461bd1ac22621a1b64609051 (diff)
downloadouroboros-e35302ca0ab64edd21b9d8e40d3aa74a3a4f4f7e.tar.gz
ouroboros-e35302ca0ab64edd21b9d8e40d3aa74a3a4f4f7e.zip
irmd: Add flow authentication
This adds initial implementation of peer authentication as part of flow allocation. If credentials are not provided, this will be accepted and logged as info that the flow is not authenticated. Certificates and keys are passed as .pem files. The key file should not be encrypted, else the IRMd will open a prompt for the password. The default location for these .pem files is in /etc/ouroboros/security. It is strongly recommended to make this directory only accessible to root. ├── security │ ├── cacert │ │ └── ca.root.o7s.crt.pem │ ├── client │ │ ├── <name> │ │ | ├── crt.pem │ │ | └── key.pem │ │ └── <name> | | ├──... | | │ ├── server │ │ ├── <name> │ │ | ├── crt.pem │ │ | └── key.pem │ │ └── <name> | | ├── ... | | │ └── untrusted │ └── sign.root.o7s.crt.pem Trusted root CA certificates go in the /cacert directory, untrusted certificates for signature verification go in the /untrusted directory. The IRMd will load these certificates at boot. The IRMd will look for certificates in the /client and /server directories. For each name a subdirectory can be added and the credentials in that directory are used to sign the OAP header for flows at flow_alloc() on the client side and flow_accept() on the server side. These defaults can be changed at build time using the following variables (in alphabetical order): OUROBOROS_CA_CRT_DIR /etc/ouroboros/security/cacert OUROBOROS_CLI_CRT_DIR /etc/ouroboros/security/client OUROBOROS_SECURITY_DIR /etc/ouroboros/security OUROBOROS_SRV_CRT_DIR /etc/ouroboros/security/server OUROBOROS_UNTRUSTED_DIR /etc/ouroboros/security/untrusted The directories for the names can also be configured at IRMd boot using the configuraton file and at runtime when a name is created using the "irm name create" CLI tool. The user needs to have permissions to access the keyfile and certificate when specifying the paths with the "irm name create" CLI tool. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks>
Diffstat (limited to 'src')
-rw-r--r--src/ipcpd/common/enroll.c7
-rw-r--r--src/ipcpd/unicast/fa.c1
-rw-r--r--src/irmd/CMakeLists.txt18
-rw-r--r--src/irmd/config.h.in7
-rw-r--r--src/irmd/configfile.c115
-rw-r--r--src/irmd/irmd.h2
-rw-r--r--src/irmd/main.c648
-rw-r--r--src/irmd/reg/flow.h3
-rw-r--r--src/irmd/reg/name.c74
-rw-r--r--src/irmd/reg/name.h28
-rw-r--r--src/irmd/reg/reg.c98
-rw-r--r--src/irmd/reg/reg.h6
-rw-r--r--src/irmd/reg/tests/name_test.c51
-rw-r--r--src/irmd/reg/tests/reg_test.c7
-rw-r--r--src/irmd/tests/oap_test.c10
-rw-r--r--src/lib/crypt.c2
-rw-r--r--src/lib/crypt/openssl.c4
-rw-r--r--src/lib/irm.c26
-rw-r--r--src/lib/pb/irm.proto25
-rw-r--r--src/lib/pb/model.proto8
-rw-r--r--src/lib/protobuf.c60
-rw-r--r--src/lib/tests/auth_test.c75
-rw-r--r--src/tools/irm/irm_name_create.c124
-rw-r--r--src/tools/irm/irm_name_reg.c37
24 files changed, 1144 insertions, 292 deletions
diff --git a/src/ipcpd/common/enroll.c b/src/ipcpd/common/enroll.c
index 4b437b27..ade6db70 100644
--- a/src/ipcpd/common/enroll.c
+++ b/src/ipcpd/common/enroll.c
@@ -64,13 +64,6 @@ struct {
pthread_t listener;
} enroll;
-#ifdef DEBUG_PROTO_OEP
-
-
-#endif
-
-
-
static void * enroll_handle(void * o)
{
struct enroll_req req;
diff --git a/src/ipcpd/unicast/fa.c b/src/ipcpd/unicast/fa.c
index 23676c23..69a9bbe6 100644
--- a/src/ipcpd/unicast/fa.c
+++ b/src/ipcpd/unicast/fa.c
@@ -673,7 +673,6 @@ int fa_init(void)
fail_mtx:
pthread_rwlock_destroy(&fa.flows_lock);
fail_rwlock:
-
return -1;
}
diff --git a/src/irmd/CMakeLists.txt b/src/irmd/CMakeLists.txt
index 965c4b3d..46d49391 100644
--- a/src/irmd/CMakeLists.txt
+++ b/src/irmd/CMakeLists.txt
@@ -4,13 +4,14 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/include)
+set(OUROBOROS_CONFIG_DIR /etc/ouroboros CACHE STRING
+ "Configuration directory")
+
find_library(LIBTOML_LIBRARIES toml QUIET)
if (LIBTOML_LIBRARIES)
set(DISABLE_CONFIGFILE FALSE CACHE BOOL
"Disable configuration file support")
if (NOT DISABLE_CONFIGFILE)
- set(OUROBOROS_CONFIG_DIR /etc/ouroboros/ CACHE STRING
- "Configuration directory")
set(OUROBOROS_CONFIG_FILE irmd.conf CACHE STRING
"Name of the IRMd configuration file")
set(HAVE_TOML TRUE)
@@ -28,7 +29,6 @@ if (LIBTOML_LIBRARIES)
else ()
message(STATUS "Configuration file support disabled by user")
unset(OUROBOROS_CONFIG_FILE CACHE)
- unset(OUROBOROS_CONFIG_DIR CACHE)
set(HAVE_TOML FALSE)
endif ()
else ()
@@ -39,9 +39,19 @@ else ()
unset(HAVE_TOML)
endif ()
+set(OUROBOROS_SECURITY_DIR "${OUROBOROS_CONFIG_DIR}/security" CACHE STRING
+ "Security directory holding authentication information")
+set(OUROBOROS_CA_CRT_DIR "${OUROBOROS_SECURITY_DIR}/cacert" CACHE STRING
+ "Directory holding trusted CA certificates")
+set(OUROBOROS_SRV_CRT_DIR "${OUROBOROS_SECURITY_DIR}/server" CACHE STRING
+ "Directory holding trusted CA certificates")
+set(OUROBOROS_CLI_CRT_DIR "${OUROBOROS_SECURITY_DIR}/client" CACHE STRING
+ "Directory holding trusted CA certificates")
+set(OUROBOROS_UNTRUSTED_DIR "${OUROBOROS_SECURITY_DIR}/untrusted" CACHE STRING
+ "Directory holding untrusted intermediate certificates")
+
set(IRMD_REQ_ARR_TIMEOUT 1000 CACHE STRING
"Timeout for an application to respond to a new flow (ms)")
-
set(BOOTSTRAP_TIMEOUT 5000 CACHE STRING
"Timeout for an IPCP to bootstrap (ms)")
set(ENROLL_TIMEOUT 20000 CACHE STRING
diff --git a/src/irmd/config.h.in b/src/irmd/config.h.in
index 6bf3817b..c829cfb7 100644
--- a/src/irmd/config.h.in
+++ b/src/irmd/config.h.in
@@ -50,7 +50,6 @@
#define IRMD_MIN_THREADS @IRMD_MIN_THREADS@
#define IRMD_ADD_THREADS @IRMD_ADD_THREADS@
-
#cmakedefine HAVE_FUSE
#ifdef HAVE_FUSE
#define FUSE_PREFIX "@FUSE_PREFIX@"
@@ -62,6 +61,12 @@
#define OUROBOROS_CONFIG_FILE "@OUROBOROS_CONFIG_FILE@"
#endif
+#define OUROBOROS_SECURITY_DIR "@OUROBOROS_SECURITY_DIR@"
+#define OUROBOROS_CA_CRT_DIR "@OUROBOROS_CA_CRT_DIR@"
+#define OUROBOROS_SRV_CRT_DIR "@OUROBOROS_SRV_CRT_DIR@"
+#define OUROBOROS_CLI_CRT_DIR "@OUROBOROS_CLI_CRT_DIR@"
+#define OUROBOROS_CHAIN_DIR "@OUROBOROS_UNTRUSTED_DIR@"
+
#define IRMD_PKILL_TIMEOUT @IRMD_PKILL_TIMEOUT@
#cmakedefine IRMD_KILL_ALL_PROCESSES
diff --git a/src/irmd/configfile.c b/src/irmd/configfile.c
index 14b03d53..229a3fd3 100644
--- a/src/irmd/configfile.c
+++ b/src/irmd/configfile.c
@@ -258,7 +258,7 @@ static int toml_dir(toml_table_t * table,
if (!BETWEEN(alpha.u.i,
DHT_ALPHA_MIN, DHT_ALPHA_MAX)) {
log_err("Invalid alpha value: %ld",
- alpha.u.i);
+ (long) alpha.u.i);
return -EINVAL;
}
DHT(conf, alpha) = alpha.u.i;
@@ -268,7 +268,7 @@ static int toml_dir(toml_table_t * table,
if (!BETWEEN(t_expire.u.i,
DHT_T_EXPIRE_MIN, DHT_T_EXPIRE_MAX)) {
log_err("Invalid expire time: %ld",
- t_expire.u.i);
+ (long) t_expire.u.i);
return -EINVAL;
}
DHT(conf, t_expire) = t_expire.u.i;
@@ -278,7 +278,7 @@ static int toml_dir(toml_table_t * table,
if (!BETWEEN(t_refresh.u.i,
DHT_T_REFRESH_MIN, DHT_T_REFRESH_MAX)) {
log_err("Invalid refresh time: %ld",
- t_refresh.u.i);
+ (long) t_refresh.u.i);
return -EINVAL;
}
DHT(conf, t_refresh) = t_refresh.u.i;
@@ -288,7 +288,7 @@ static int toml_dir(toml_table_t * table,
if (!BETWEEN(t_replicate.u.i,
DHT_T_REPLICATE_MIN, DHT_T_REPLICATE_MAX)) {
log_err("Invalid replication time: %ld",
- t_replicate.u.i);
+ (long) t_replicate.u.i);
return -EINVAL;
}
DHT(conf, t_replicate) = t_replicate.u.i;
@@ -297,7 +297,7 @@ static int toml_dir(toml_table_t * table,
if (k.ok) {
if (!BETWEEN(k.u.i, DHT_K_MIN, DHT_K_MAX)) {
log_err("Invalid replication factor: %ld",
- k.u.i);
+ (long) k.u.i);
return -EINVAL;
}
DHT(conf, k) = k.u.i;
@@ -344,7 +344,7 @@ static int toml_routing(toml_table_t * table,
if (t_recalc.ok) {
if (t_recalc.u.i < 1) {
log_err("Invalid ls_t_recalc value: %ld",
- t_recalc.u.i);
+ (long) t_recalc.u.i);
return -EINVAL;
}
conf->routing.ls.t_recalc = t_recalc.u.i;
@@ -353,7 +353,7 @@ static int toml_routing(toml_table_t * table,
if (t_update.ok) {
if (t_update.u.i < 1) {
log_err("Invalid ls_t_update value: %ld",
- t_update.u.i);
+ (long) t_update.u.i);
return -EINVAL;
}
conf->routing.ls.t_update = t_update.u.i;
@@ -362,7 +362,7 @@ static int toml_routing(toml_table_t * table,
if (t_timeo.ok) {
if (t_timeo.u.i < 1) {
log_err("Invalid ls_t_timeo value: %ld",
- t_timeo.u.i);
+ (long) t_timeo.u.i);
return -EINVAL;
}
conf->routing.ls.t_timeo = t_timeo.u.i;
@@ -833,15 +833,27 @@ static int toml_prog_list(toml_array_t * progs,
static int toml_name(toml_table_t * table,
const char * name)
{
- toml_array_t * progs;
- toml_array_t * args;
- toml_datum_t lb;
+ toml_array_t * progs;
+ toml_array_t * args;
+ toml_datum_t lb;
+ toml_datum_t scrt;
+ toml_datum_t skey;
+ toml_datum_t ccrt;
+ toml_datum_t ckey;
+
struct name_info info = {
.pol_lb = LB_SPILL
};
log_dbg("Found service name %s in configuration file.", name);
+ if (strlen(name) > NAME_SIZE) {
+ log_err("Name too long: %s", name);
+ return -1;
+ }
+
+ strcpy(info.name, name);
+
lb = toml_string_in(table, "lb");
if (lb.ok) {
if (strcmp(lb.u.s, "spill") == 0)
@@ -858,7 +870,83 @@ static int toml_name(toml_table_t * table,
return -1;
}
- strcpy(info.name, name);
+ scrt = toml_string_in(table, "server_crt_file");
+ if (scrt.ok) {
+ char * scrt_path = realpath(scrt.u.s, NULL);
+ if (scrt_path == NULL) {
+ log_err("Failed to check path for %s: %s.",
+ scrt.u.s, strerror(errno));
+ free(scrt.u.s);
+ return -1;
+ }
+ if (strlen(scrt.u.s) > NAME_PATH_SIZE) {
+ log_err("Server certificate file path too long: %s",
+ scrt_path);
+ free(scrt.u.s);
+ return -1;
+ }
+ strcpy(info.s.crt, scrt_path);
+ free(scrt_path);
+ free(scrt.u.s);
+ }
+
+ skey = toml_string_in(table, "server_key_file");
+ if (skey.ok) {
+ char * skey_path = realpath(skey.u.s, NULL);
+ if (skey_path == NULL) {
+ log_err("Failed to check path for %s: %s.",
+ skey.u.s, strerror(errno));
+ free(skey.u.s);
+ return -1;
+ }
+ if (strlen(skey.u.s) > NAME_PATH_SIZE) {
+ log_err("Server key file path too long: %s", skey_path);
+ free(skey.u.s);
+ return -1;
+ }
+ strcpy(info.s.key, skey_path);
+ free(skey_path);
+ free(skey.u.s);
+ }
+
+ ccrt = toml_string_in(table, "client_crt_file");
+ if (ccrt.ok) {
+ char * ccrt_path = realpath(ccrt.u.s, NULL);
+ if (ccrt_path == NULL) {
+ log_err("Failed to check path for %s: %s.",
+ ccrt.u.s, strerror(errno));
+ free(ccrt.u.s);
+ return -1;
+ }
+ if (strlen(ccrt.u.s) > NAME_PATH_SIZE) {
+ log_err("Client certificate file path too long: %s",
+ ccrt_path);
+ free(ccrt.u.s);
+ return -1;
+ }
+ strcpy(info.c.crt, ccrt_path);
+ free(ccrt_path);
+ free(ccrt.u.s);
+ }
+
+ ckey = toml_string_in(table, "client_key_file");
+ if (ckey.ok) {
+ char * ckey_path = realpath(ckey.u.s, NULL);
+ if (ckey_path == NULL) {
+ log_err("Failed to check path for %s: %s.",
+ ckey.u.s, strerror(errno));
+ free(ckey.u.s);
+ return -1;
+ }
+ if (strlen(ckey.u.s) > NAME_PATH_SIZE) {
+ log_err("Client key file path too long: %s", ckey_path);
+ free(ckey.u.s);
+ return -1;
+ }
+ strcpy(info.c.key, ckey_path);
+ free(ckey_path);
+ free(ckey.u.s);
+ }
if (name_create(&info) < 0) {
log_err("Failed to create name %s.", name);
@@ -976,7 +1064,8 @@ int irm_configure(const char * path)
rp = realpath(path, NULL);
if (rp == NULL) {
- log_err("Failed to resolve path for %s", path);
+ log_err("Failed to check path for %s: %s.",
+ path, strerror(errno));
goto fail_resolve;
}
diff --git a/src/irmd/irmd.h b/src/irmd/irmd.h
index cf8f6953..3e54904a 100644
--- a/src/irmd/irmd.h
+++ b/src/irmd/irmd.h
@@ -39,7 +39,7 @@ int connect_ipcp(pid_t pid,
const char * component,
qosspec_t qs);
-int name_create(const struct name_info * info);
+int name_create(struct name_info * info);
int name_reg(const char * name,
pid_t pid);
diff --git a/src/irmd/main.c b/src/irmd/main.c
index 4acd0ef3..e799666f 100644
--- a/src/irmd/main.c
+++ b/src/irmd/main.c
@@ -55,6 +55,7 @@
#include "reg/reg.h"
#include "configfile.h"
+#include <dirent.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
@@ -74,6 +75,7 @@
#define IPCP_HASH_LEN(p) hash_len((p)->dir_hash_algo)
#define BIND_TIMEOUT 10 /* ms */
#define TIMESYNC_SLACK 100 /* ms */
+#define OAP_SEEN_TIMER 20 /* s */
#define DEALLOC_TIME 300 /* s */
enum irm_state {
@@ -82,6 +84,13 @@ enum irm_state {
IRMD_SHUTDOWN
};
+struct oaph {
+ struct list_head next;
+
+ uint64_t stamp;
+ uint8_t id[OAP_ID_SIZE];
+};
+
struct cmd {
struct list_head next;
@@ -95,6 +104,12 @@ struct {
#ifdef HAVE_TOML
char * cfg_file; /* configuration file path */
#endif
+ struct {
+ struct auth_ctx * ctx; /* default authentication ctx */
+ struct list_head list; /* OAP headers seen before */
+ pthread_mutex_t mtx; /* mutex for OAP headers */
+ } auth;
+
struct lockfile * lf; /* single irmd per system */
struct shm_rdrbuff * rdrb; /* rdrbuff for packets */
@@ -427,6 +442,65 @@ static int disconnect_ipcp(pid_t pid,
return 0;
}
+static void name_update_sec_paths(struct name_info * info)
+{
+ char * srv_dir = OUROBOROS_SRV_CRT_DIR;
+ char * cli_dir = OUROBOROS_CLI_CRT_DIR;
+
+ assert(info != NULL);
+
+ if (strlen(info->s.crt) == 0)
+ sprintf(info->s.crt, "%s/%s/crt.pem", srv_dir, info->name);
+
+ if (strlen(info->s.key) == 0)
+ sprintf(info->s.key, "%s/%s/key.pem", srv_dir, info->name);
+
+ if (strlen(info->c.crt) == 0)
+ sprintf(info->c.crt, "%s/%s/crt.pem", cli_dir, info->name);
+
+ if (strlen(info->c.key) == 0)
+ sprintf(info->c.key, "%s/%s/key.pem", cli_dir, info->name);
+}
+
+int name_create(struct name_info * info)
+{
+ int ret;
+
+ assert(info != NULL);
+
+ name_update_sec_paths(info);
+
+ ret = reg_create_name(info);
+ if (ret == -EEXIST) {
+ log_info("Name %s already exists.", info->name);
+ return 0;
+ }
+
+ if (ret < 0) {
+ log_err("Failed to create name %s.", info->name);
+ return -1;
+ }
+
+ log_info("Created new name: %s.", info->name);
+
+ return 0;
+}
+
+static int name_destroy(const char * name)
+{
+
+ assert(name != NULL);
+
+ if (reg_destroy_name(name) < 0) {
+ log_err("Failed to destroy name %s.", name);
+ return -1;
+ }
+
+ log_info("Destroyed name: %s.", name);
+
+ return 0;
+}
+
int bind_program(char ** exec,
const char * name,
uint8_t flags)
@@ -450,10 +524,8 @@ int bind_program(char ** exec,
if (!reg_has_name(name)) {
ni.pol_lb = LB_SPILL;
strcpy(ni.name, name);
- if (reg_create_name(&ni) < 0) {
- log_err("Failed to create name %s.", name);
+ if (name_create(&ni) < 0)
goto fail_name;
- }
}
if (reg_bind_prog(name, exec, flags) < 0) {
@@ -499,10 +571,8 @@ int bind_process(pid_t pid,
if (!reg_has_name(name)) {
ni.pol_lb = LB_SPILL;
strcpy(ni.name, name);
- if (reg_create_name(&ni) < 0) {
- log_err("Failed to create name %s.", name);
+ if (name_create(&ni) < 0)
goto fail;
- }
}
if (reg_bind_proc(name, pid) < 0) {
@@ -583,43 +653,6 @@ static int list_ipcps(ipcp_list_msg_t *** ipcps,
return -1;
}
-int name_create(const struct name_info * info)
-{
- int ret;
-
- assert(info != NULL);
-
- ret = reg_create_name(info);
- if (ret == -EEXIST) {
- log_info("Name %s already exists.", info->name);
- return 0;
- }
-
- if (ret < 0) {
- log_err("Failed to create name %s.", info->name);
- return -1;
- }
-
- log_info("Created new name: %s.", info->name);
-
- return 0;
-}
-
-static int name_destroy(const char * name)
-{
-
- assert(name != NULL);
-
- if (reg_destroy_name(name) < 0) {
- log_err("Failed to destroy name %s.", name);
- return -1;
- }
-
- log_info("Destroyed name: %s.", name);
-
- return 0;
-}
-
static int list_names(name_info_msg_t *** names,
size_t * n_names)
{
@@ -762,22 +795,244 @@ static void __cleanup_flow(void * flow)
reg_destroy_flow(((struct flow_info *) flow)->id);
}
+static bool file_exists(const char * path)
+{
+ struct stat s;
+
+ if (stat(path, &s) < 0 && errno == ENOENT) {
+ log_dbg("File %s does not exist.", path);
+ return false;
+ }
+
+ return true;
+}
+
+static int load_credentials(const char * name,
+ const struct name_sec_paths * paths,
+ void ** pkp,
+ void ** crt)
+{
+ assert(paths != NULL);
+ assert(pkp != NULL);
+ assert(crt != NULL);
+
+ *pkp = NULL;
+ *crt = NULL;
+
+ if (!file_exists(paths->crt) || !file_exists(paths->key)) {
+ log_info("No security info for %s.", name);
+ return 0;
+ }
+
+ if (crypt_load_crt_file(paths->crt, crt) < 0) {
+ log_err("Failed to load %s for %s.", paths->crt, name);
+ goto fail_crt;
+ }
+
+ if (crypt_load_privkey_file(paths->key, pkp) < 0) {
+ log_err("Failed to load %s for %s.", paths->key, name);
+ goto fail_key;
+ }
+
+ log_info("Loaded security keys for %s.", name);
+
+ return 0;
+
+ fail_key:
+ crypt_free_crt(*crt);
+ *crt = NULL;
+ fail_crt:
+ return -EAUTH;
+}
+
+static int load_srv_credentials(const char * name,
+ void ** pkp,
+ void ** crt)
+{
+ struct name_info info;
+
+ assert(name != NULL);
+ assert(pkp != NULL);
+ assert(crt != NULL);
+
+ if (reg_get_name_info(name, &info) < 0) {
+ log_err("Failed to get name info for %s.", name);
+ return -ENAME;
+ }
+
+ return load_credentials(name, &info.s, pkp, crt);
+}
+
+static int load_cli_credentials(const char * name,
+ void ** pkp,
+ void ** crt)
+{
+ struct name_info info;
+
+ assert(name != NULL);
+ assert(pkp != NULL);
+ assert(crt != NULL);
+
+ if (reg_get_name_info(name, &info) < 0) {
+ log_err("Failed to get name info for %s.", name);
+ return -ENAME;
+ }
+
+ return load_credentials(name, &info.c, pkp, crt);
+}
+
+#define ID_IS_EQUAL(id1, id2) (memcmp(id1, id2, OAP_ID_SIZE) == 0)
+static int irm_check_oap_hdr(const struct oap_hdr * oap_hdr,
+ time_t mpl)
+{
+ struct list_head * p;
+ struct list_head * h;
+ struct timespec now;
+ struct oaph * new;
+ uint64_t stamp;
+ uint64_t cur;
+ uint8_t * id;
+ ssize_t delta;
+
+ assert(oap_hdr != NULL);
+
+ stamp = oap_hdr->timestamp;
+ id = oap_hdr->id.data;
+
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ cur = TS_TO_UINT64(now);
+
+ delta = (ssize_t)(cur - stamp) / MILLION;
+ if (delta > mpl)
+ log_warn("Transit time exceeds MPL by %zd ms.", delta);
+ if (delta < -TIMESYNC_SLACK)
+ log_warn("OAP header sent %zd ms from the future.", -delta);
+
+ new = malloc(sizeof(*new));
+ if (new == NULL) {
+ log_err("Failed to allocate memory for OAP element.");
+ return -ENOMEM;
+ }
+
+ pthread_mutex_lock(&irmd.auth.mtx);
+
+ list_for_each_safe(p, h, &irmd.auth.list) {
+ struct oaph * oaph = list_entry(p, struct oaph, next);
+ if (cur > oaph->stamp + OAP_SEEN_TIMER * BILLION) {
+ list_del(&oaph->next);
+ free(oaph);
+ continue;
+ }
+
+ if (oaph->stamp == stamp && ID_IS_EQUAL(oaph->id, id)) {
+ log_warn("OAP header already known: " HASH_FMT64 ".",
+ HASH_VAL64(id));
+ goto fail_replay;
+ }
+ }
+
+ memcpy(new->id, id, OAP_ID_SIZE);
+ new->stamp = stamp;
+
+ list_add_tail(&new->next, &irmd.auth.list);
+
+ pthread_mutex_unlock(&irmd.auth.mtx);
+
+ return 0;
+
+ fail_replay:
+ pthread_mutex_unlock(&irmd.auth.mtx);
+ free(new);
+ return -EAUTH;
+}
+
+static int irm_auth_peer(const char * name,
+ const struct oap_hdr * oap_hdr,
+ const struct oap_hdr * r_oap_hdr)
+{
+ void * crt;
+ void * pk;
+ buffer_t sign;
+
+ if (memcmp(r_oap_hdr->id.data, oap_hdr->id.data, OAP_ID_SIZE) != 0) {
+ log_err("OAP ID mismatch in flow allocation.");
+ goto fail_check;
+ }
+
+ if (r_oap_hdr->crt.len == 0) {
+ log_info("No certificate provided by peer %s.", name);
+ return 0;
+ }
+
+ if (crypt_load_crt_der(r_oap_hdr->crt, &crt) < 0) {
+ log_err("Failed to load certificate from peer %s.", name);
+ goto fail_check;
+ }
+
+ log_dbg("Loaded peer certificate for %s.", name);
+
+ if (crypt_check_crt_name(crt, name) < 0) {
+ log_err("Certificate does not match name %s.", name);
+ goto fail_crt;
+ }
+
+ log_dbg("Certificate matches name %s.", name);
+
+ if (crypt_get_pubkey_crt(crt, &pk) < 0) {
+ log_err("Failed to get pubkey from certificate for %s.", name);
+ goto fail_crt;
+ }
+
+ log_dbg("Got public key from certificate for %s.", name);
+
+ if (auth_verify_crt(irmd.auth.ctx, crt) < 0) {
+ log_err("Failed to verify peer %s with CA store.", name);
+ goto fail_crt;
+ }
+
+ log_info("Successfully verified peer certificate for %s.", name);
+
+ sign = r_oap_hdr->hdr;
+ sign.len -= (r_oap_hdr->sig.len + sizeof(uint16_t));
+
+ if (auth_verify_sig(pk, sign, r_oap_hdr->sig) < 0) {
+ log_err("Failed to verify signature for peer %s.", name);
+ goto fail_check_sig;
+ }
+
+ crypt_free_key(pk);
+ crypt_free_crt(crt);
+
+ log_info("Successfully authenticated %s.", name);
+
+ return 0;
+
+ fail_check_sig:
+ crypt_free_key(pk);
+ fail_crt:
+ crypt_free_crt(crt);
+ fail_check:
+ return -1;
+}
+
static int flow_accept(struct flow_info * flow,
buffer_t * symmkey,
buffer_t * data,
struct timespec * abstime)
{
- struct oap_hdr oap_hdr; /* incoming request */
- struct oap_hdr r_oap_hdr; /* outgoing response */
- uint8_t buf[MSGBUFSZ]; /* buffer for local ephkey */
- buffer_t lpk = BUF_INIT; /* local ephemeral pubkey */
- ssize_t delta; /* allocation time difference */
- int err;
- struct timespec now;
+ struct oap_hdr oap_hdr; /* incoming request */
+ struct oap_hdr r_oap_hdr; /* outgoing response */
+ uint8_t buf[MSGBUFSZ]; /* buffer for local ephkey */
+ buffer_t lpk = BUF_INIT; /* local ephemeral pubkey */
+ char name[NAME_SIZE + 1]; /* name for flow */
+ void * pkp = NULL; /* signing private key */
+ void * crt = NULL; /* signing certificate */
+ int err;
/* piggyback of user data not yet implemented */
- assert(data != NULL && data->len == 0 && data->data == NULL);
- assert(symmkey != NULL && symmkey->len == 0 && symmkey->data == NULL);
+ assert(data != NULL && BUF_IS_EMPTY(data));
+ assert(symmkey != NULL && BUF_IS_EMPTY(symmkey));
if (!reg_has_proc(flow->n_pid)) {
log_err("Unknown process %d calling accept.", flow->n_pid);
@@ -816,23 +1071,28 @@ static int flow_accept(struct flow_info * flow,
assert(err == 0);
- if (oap_hdr_decode(oap_hdr.hdr, &oap_hdr) < 0) {
- log_err("Failed to decode OAP header.");
+ if (reg_get_name_for_flow_id(name, flow->id) < 0) {
+ log_err("Failed to get name for flow %d.", flow->id);
err = -EIPCP;
goto fail_oap_hdr;
}
- clock_gettime(CLOCK_REALTIME, &now);
-
- delta = (ssize_t)(TS_TO_UINT64(now) - oap_hdr.timestamp) / MILLION;
- if (delta > flow->mpl)
- log_warn("Flow alloc time exceeds MPL (%zd ms).", delta);
+ log_dbg("IPCP %d accepting flow %d for %s.",
+ flow->n_pid, flow->id, name);
- if (delta < -TIMESYNC_SLACK)
- log_warn("Flow alloc sent from the future (%zd ms).", -delta);
+ if (oap_hdr_decode(oap_hdr.hdr, &oap_hdr) < 0) {
+ log_err("Failed to decode OAP header from %s.", name);
+ err = -EIPCP;
+ goto fail_oap_hdr;
+ }
#ifdef DEBUG_PROTO_OAP
debug_oap_hdr_rcv(&oap_hdr);
#endif
+ if (irm_check_oap_hdr(&oap_hdr, flow->mpl) < 0) {
+ log_err("OAP header failed replay check.");
+ goto fail_oap_hdr;
+ }
+
if (flow->qs.cypher_s != 0) { /* crypto requested */
uint8_t * s; /* symmetric encryption key */
ssize_t key_len; /* length of local pubkey */
@@ -872,25 +1132,47 @@ static int flow_accept(struct flow_info * flow,
crypt_dh_pkp_destroy(pkp);
}
- if (oap_hdr_init(oap_hdr.id, NULL, NULL, lpk, *data, &r_oap_hdr) < 0) {
+ if (load_srv_credentials(name, &pkp, &crt) < 0) {
+ log_err("Failed to load security keys for %s.", name);
+ err = -EAUTH;
+ goto fail_cred;
+ }
+
+ if (oap_hdr_init(oap_hdr.id, pkp, crt, lpk, *data, &r_oap_hdr) < 0) {
log_err("Failed to create OAP header.");
err = -ENOMEM;
goto fail_r_oap_hdr;
}
+
+ if (irm_auth_peer(name, &oap_hdr, &r_oap_hdr) < 0) {
+ log_err("Failed to authenticate %s flow %d.", name, flow->id);
+ err = -EAUTH;
+ goto fail_r_oap_hdr;
+ }
+
+ crypt_free_crt(crt);
+ crypt_free_key(pkp);
+
#ifdef DEBUG_PROTO_OAP
- debug_oap_hdr_snd(&oap_hdr);
+ debug_oap_hdr_snd(&r_oap_hdr);
#endif
if (ipcp_flow_alloc_resp(flow, 0, r_oap_hdr.hdr) < 0) {
log_err("Failed to respond to flow allocation.");
goto fail_resp;
}
+ log_info("Flow %d accepted by %d for %s.",
+ flow->id, flow->n_pid, name);
+
oap_hdr_fini(&oap_hdr);
oap_hdr_fini(&r_oap_hdr);
return 0;
fail_r_oap_hdr:
+ crypt_free_crt(crt);
+ crypt_free_key(pkp);
+ fail_cred:
freebuf(*symmkey);
fail_derive:
clrbuf(lpk);
@@ -949,7 +1231,6 @@ static int flow_join(struct flow_info * flow,
reg_prepare_flow_alloc(flow);
-
if (ipcp_flow_join(flow, hash)) {
log_err("Flow join with layer %s failed.", dst);
err = -ENOTALLOC;
@@ -1059,14 +1340,16 @@ static int flow_alloc(struct flow_info * flow,
buffer_t lpk = BUF_INIT; /* local ephemeral pubkey */
void * pkp = NULL; /* ephemeral private key pair */
uint8_t * s = NULL; /* symmetric key */
+ void * cpkp = NULL; /* signing private key */
+ void * ccrt = NULL; /* signing certificate */
buffer_t hash;
uint8_t idbuf[OAP_ID_SIZE];
buffer_t id;
int err;
/* piggyback of user data not yet implemented */
- assert(data != NULL && data->len == 0 && data->data == NULL);
- assert(symmkey != NULL && symmkey->len == 0 && symmkey->data == NULL);
+ assert(data != NULL && BUF_IS_EMPTY(data));
+ assert(symmkey != NULL && BUF_IS_EMPTY(symmkey));
if (random_buffer(idbuf, OAP_ID_SIZE) < 0) {
log_err("Failed to generate ID.");
@@ -1100,7 +1383,13 @@ static int flow_alloc(struct flow_info * flow,
log_dbg("Generated ephemeral keys for %d.", flow->n_pid);
}
- if (oap_hdr_init(id, NULL, NULL, lpk, *data, &oap_hdr) < 0) {
+ if (load_cli_credentials(dst, &cpkp, &ccrt) < 0) {
+ log_err("Failed to load security keys for %s.", dst);
+ err = -EAUTH;
+ goto fail_cred;
+ }
+
+ if (oap_hdr_init(id, cpkp, ccrt, lpk, *data, &oap_hdr) < 0) {
log_err("Failed to create OAP header.");
err = -ENOMEM;
goto fail_oap_hdr;
@@ -1164,9 +1453,14 @@ static int flow_alloc(struct flow_info * flow,
#ifdef DEBUG_PROTO_OAP
debug_oap_hdr_rcv(&r_oap_hdr);
#endif
- if (memcmp(r_oap_hdr.id.data, oap_hdr.id.data, r_oap_hdr.id.len) != 0) {
- log_err("OAP ID mismatch in flow allocation.");
- err = -EIPCP;
+ if (irm_check_oap_hdr(&r_oap_hdr, flow->mpl) < 0) {
+ log_err("OAP header failed replay check.");
+ goto fail_r_oap_hdr;
+ }
+
+ if (irm_auth_peer(dst, &oap_hdr, &r_oap_hdr) < 0) {
+ log_err("Failed to authenticate %s (flow %d).", dst, flow->id);
+ err = -EAUTH;
goto fail_r_oap_hdr;
}
@@ -1186,6 +1480,9 @@ static int flow_alloc(struct flow_info * flow,
oap_hdr_fini(&r_oap_hdr);
oap_hdr_fini(&oap_hdr);
+ crypt_free_crt(ccrt);
+ crypt_free_key(cpkp);
+
/* TODO: piggyback user data if needed */
freebuf(hash);
@@ -1203,6 +1500,9 @@ static int flow_alloc(struct flow_info * flow,
fail_flow:
oap_hdr_fini(&oap_hdr);
fail_oap_hdr:
+ crypt_free_crt(ccrt);
+ crypt_free_key(cpkp);
+ fail_cred:
crypt_dh_pkp_destroy(pkp);
fail_pkp:
free(s);
@@ -1497,8 +1797,7 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
res = list_ipcps(&ret_msg->ipcps, &ret_msg->n_ipcps);
break;
case IRM_MSG_CODE__IRM_CREATE_NAME:
- strcpy(name.name, msg->names[0]->name);
- name.pol_lb = msg->names[0]->pol_lb;
+ name = name_info_msg_to_s(msg->name_info);
res = name_create(&name);
break;
case IRM_MSG_CODE__IRM_DESTROY_NAME:
@@ -1708,40 +2007,6 @@ static void * mainloop(void * o)
return (void *) 0;
}
-static void irm_fini(void)
-{
-#ifdef HAVE_FUSE
- struct timespec wait = TIMESPEC_INIT_MS(1);
- int retries = 5;
-#endif
- if (irmd_get_state() != IRMD_NULL)
- log_warn("Unsafe destroy.");
-
- tpm_destroy(irmd.tpm);
-
- close(irmd.sockfd);
-
- if (unlink(IRM_SOCK_PATH))
- log_dbg("Failed to unlink %s.", IRM_SOCK_PATH);
-
- if (irmd.rdrb != NULL)
- shm_rdrbuff_destroy(irmd.rdrb);
-
- if (irmd.lf != NULL)
- lockfile_destroy(irmd.lf);
-
- pthread_mutex_destroy(&irmd.cmd_lock);
- pthread_cond_destroy(&irmd.cmd_cond);
- pthread_rwlock_destroy(&irmd.state_lock);
-
-#ifdef HAVE_FUSE
- while (rmdir(FUSE_PREFIX) < 0 && retries-- > 0)
- nanosleep(&wait, NULL);
- if (retries < 0)
- log_err("Failed to remove " FUSE_PREFIX);
-#endif
-}
-
#ifdef HAVE_FUSE
static void destroy_mount(char * mnt)
{
@@ -1817,6 +2082,79 @@ void * irm_sanitize(void * o)
return (void *) 0;
}
+static int irm_load_store(char * dpath)
+{
+ struct stat st;
+ struct dirent * dent;
+ DIR * dir;
+ void * crt;
+
+ if (stat(dpath, &st) == -1) {
+ log_dbg("Store directory %s not found.", dpath);
+ return 0;
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ log_err("%s is not a directory.", dpath);
+ goto fail_dir;
+ }
+
+ /* loop through files in directory and load certificates */
+ dir = opendir(dpath);
+ if (dir == NULL) {
+ log_err("Failed to open %s.", dpath);
+ goto fail_dir;
+ }
+
+ while ((dent = readdir(dir)) != NULL) {
+ char path[NAME_PATH_SIZE + 1];
+
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+
+ snprintf(path, sizeof(path), "%s/%s", dpath,
+ dent->d_name);
+
+ if (stat(path, &st) == -1) {
+ log_dbg("Failed to stat %s.", path);
+ continue;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ log_dbg("%s is not a regular file.", path);
+ goto fail_file;
+ }
+
+ if (crypt_load_crt_file(path, &crt) < 0) {
+ log_err("Failed to load certificate from %s.", path);
+ goto fail_file;
+ }
+
+ if (auth_add_crt_to_store(irmd.auth.ctx, crt) < 0) {
+ log_err("Failed to add certificate from %s to store.",
+ path);
+ goto fail_crt_add;
+ }
+
+ log_dbg("Loaded certificate: %s.", path);
+
+ crypt_free_crt(crt);
+ }
+
+ closedir(dir);
+
+ log_info("Loaded certificates from %s.", dpath);
+
+ return 0;
+
+ fail_crt_add:
+ crypt_free_crt(crt);
+ fail_file:
+ closedir(dir);
+ fail_dir:
+ return -1;
+}
static int irm_init(void)
{
@@ -1917,6 +2255,30 @@ static int irm_init(void)
log_err("Failed to greate thread pool.");
goto fail_tpm_create;
}
+
+ if (pthread_mutex_init(&irmd.auth.mtx, NULL) < 0) {
+ log_err("Failed to initialize auth mutex.");
+ goto fail_auth_mtx;
+ }
+
+ irmd.auth.ctx = auth_create_ctx();
+ if (irmd.auth.ctx == NULL) {
+ log_err("Failed to create auth store context.");
+ goto fail_auth_ctx;
+ }
+
+ list_head_init(&irmd.auth.list);
+
+ if (irm_load_store(OUROBOROS_CA_CRT_DIR) < 0) {
+ log_err("Failed to load CA certificates.");
+ goto fail_auth_ctx;
+ }
+
+ if (irm_load_store(OUROBOROS_CHAIN_DIR) < 0) {
+ log_err("Failed to load intermediate certificates.");
+ goto fail_auth_ctx;
+ }
+
#ifdef HAVE_FUSE
mask = umask(0);
@@ -1941,7 +2303,6 @@ static int irm_init(void)
gcry_control(GCRYCTL_INITIALIZATION_FINISHED);
#endif
-
return 0;
#ifdef HAVE_LIBGCRYPT
@@ -1949,8 +2310,12 @@ static int irm_init(void)
#ifdef HAVE_FUSE
rmdir(FUSE_PREFIX);
#endif
- tpm_destroy(irmd.tpm);
+ auth_destroy_ctx(irmd.auth.ctx);
#endif
+ fail_auth_ctx:
+ pthread_mutex_destroy(&irmd.auth.mtx);
+ fail_auth_mtx:
+ tpm_destroy(irmd.tpm);
fail_tpm_create:
shm_rdrbuff_destroy(irmd.rdrb);
fail_rdrbuff:
@@ -1970,6 +2335,67 @@ static int irm_init(void)
return -1;
}
+static void irm_fini(void)
+{
+ struct list_head * p;
+ struct list_head * h;
+#ifdef HAVE_FUSE
+ struct timespec wait = TIMESPEC_INIT_MS(1);
+ int retries = 5;
+#endif
+ if (irmd_get_state() != IRMD_NULL)
+ log_warn("Unsafe destroy.");
+
+ pthread_mutex_lock(&irmd.auth.mtx);
+
+ list_for_each_safe(p, h, &irmd.auth.list) {
+ struct oaph * oaph = list_entry(p, struct oaph, next);
+ list_del(&oaph->next);
+ free(oaph);
+ }
+
+ pthread_mutex_unlock(&irmd.auth.mtx);
+ pthread_mutex_destroy(&irmd.auth.mtx);
+
+ auth_destroy_ctx(irmd.auth.ctx);
+
+ tpm_destroy(irmd.tpm);
+
+ close(irmd.sockfd);
+
+ if (unlink(IRM_SOCK_PATH))
+ log_dbg("Failed to unlink %s.", IRM_SOCK_PATH);
+
+ if (irmd.rdrb != NULL)
+ shm_rdrbuff_destroy(irmd.rdrb);
+
+ if (irmd.lf != NULL)
+ lockfile_destroy(irmd.lf);
+
+ pthread_mutex_lock(&irmd.cmd_lock);
+
+ list_for_each_safe(p, h, &irmd.cmds) {
+ struct cmd * cmd = list_entry(p, struct cmd, next);
+ list_del(&cmd->next);
+ close(cmd->fd);
+ free(cmd);
+ }
+
+ pthread_mutex_unlock(&irmd.cmd_lock);
+
+ pthread_mutex_destroy(&irmd.cmd_lock);
+ pthread_cond_destroy(&irmd.cmd_cond);
+ pthread_rwlock_destroy(&irmd.state_lock);
+
+#ifdef HAVE_FUSE
+ while (rmdir(FUSE_PREFIX) < 0 && retries-- > 0)
+ nanosleep(&wait, NULL);
+ if (retries < 0)
+ log_err("Failed to remove " FUSE_PREFIX);
+#endif
+ assert(list_is_empty(&irmd.cmds));
+}
+
static void usage(void)
{
printf("Usage: irmd \n"
@@ -2096,8 +2522,8 @@ static void * kill_dash_nine(void * o)
slept += intv;
}
- log_dbg("I am become Death, destroyer of hung processes.");
-
+ log_dbg("I guess I’ll have to shut you down for good this time,");
+ log_dbg("already tried a SIGQUIT, so now it’s KILL DASH 9.");
#ifdef IRMD_KILL_ALL_PROCESSES
reg_kill_all_proc(SIGKILL);
nanosleep(&ts, NULL);
@@ -2156,7 +2582,7 @@ int main(int argc,
if (geteuid() != 0) {
printf("IPC Resource Manager must be run as root.\n");
- exit(EXIT_FAILURE);
+ goto fail_irm_init;
}
if (irm_init() < 0)
diff --git a/src/irmd/reg/flow.h b/src/irmd/reg/flow.h
index b0f0c51c..aba0d7a4 100644
--- a/src/irmd/reg/flow.h
+++ b/src/irmd/reg/flow.h
@@ -25,6 +25,7 @@
#include <ouroboros/list.h>
#include <ouroboros/flow.h>
+#include <ouroboros/name.h>
#include <ouroboros/pthread.h>
#include <ouroboros/qos.h>
#include <ouroboros/shm_rbuff.h>
@@ -41,6 +42,8 @@ struct reg_flow {
buffer_t data;
struct timespec t0;
+ char name[NAME_SIZE + 1];
+
struct shm_rbuff * n_rb;
struct shm_rbuff * n_1_rb;
};
diff --git a/src/irmd/reg/name.c b/src/irmd/reg/name.c
index 1ac939a5..4e609711 100644
--- a/src/irmd/reg/name.c
+++ b/src/irmd/reg/name.c
@@ -66,15 +66,14 @@ struct reg_name * reg_name_create(const struct name_info * info)
goto fail_malloc;
}
+ memset(name, 0, sizeof(*name));
+
list_head_init(&name->next);
- list_head_init(&name->progs);
- list_head_init(&name->procs);
- list_head_init(&name->active);
+ list_head_init(&name->progs.list);
+ list_head_init(&name->procs.list);
+ list_head_init(&name->active.list);
- name->info = *info;
- name->n_progs = 0;
- name->n_procs = 0;
- name->n_active = 0;
+ name->info = *info;
return name;
@@ -88,13 +87,13 @@ void reg_name_destroy(struct reg_name * name)
assert(list_is_empty(&name->next));
- assert(name->n_progs == 0);
- assert(name->n_procs == 0);
- assert(name->n_active == 0);
+ assert(name->progs.len == 0);
+ assert(name->procs.len == 0);
+ assert(name->active.len == 0);
- assert(list_is_empty(&name->progs));
- assert(list_is_empty(&name->procs));
- assert(list_is_empty(&name->active));
+ assert(list_is_empty(&name->progs.list));
+ assert(list_is_empty(&name->procs.list));
+ assert(list_is_empty(&name->active.list));
free(name);
}
@@ -107,7 +106,7 @@ static struct proc_entry * __reg_name_get_active(const struct reg_name * name,
assert(name != NULL);
assert(pid > 0);
- list_for_each(p, &name->active) {
+ list_for_each(p, &name->active.list) {
struct proc_entry * entry;
entry = list_entry(p, struct proc_entry, next);
if (entry->pid == pid)
@@ -123,13 +122,13 @@ static void __reg_name_del_all_active(struct reg_name * name,
struct list_head * p;
struct list_head * h;
- list_for_each_safe(p, h, &name->active) {
+ list_for_each_safe(p, h, &name->active.list) {
struct proc_entry * entry;
entry = list_entry(p, struct proc_entry, next);
if (entry->pid == pid) {
list_del(&entry->next);
free(entry);
- name->n_active--;
+ --name->active.len;
}
}
}
@@ -142,7 +141,7 @@ static struct proc_entry * __reg_name_get_proc(const struct reg_name * name,
assert(name != NULL);
assert(pid > 0);
- list_for_each(p, &name->procs) {
+ list_for_each(p, &name->procs.list) {
struct proc_entry * entry;
entry = list_entry(p, struct proc_entry, next);
if (entry->pid == pid)
@@ -160,7 +159,7 @@ static struct prog_entry * __reg_name_get_prog(const struct reg_name * name,
assert(name != NULL);
assert(prog != NULL);
- list_for_each(p, &name->progs) {
+ list_for_each(p, &name->progs.list) {
struct prog_entry * entry;
entry = list_entry(p, struct prog_entry, next);
if (strcmp(entry->exec[0], prog) == 0)
@@ -195,16 +194,16 @@ int reg_name_add_active(struct reg_name * name,
switch (name->info.pol_lb) {
case LB_RR: /* Round robin policy. */
- list_add_tail(&entry->next, &name->active);
+ list_add_tail(&entry->next, &name->active.list);
break;
case LB_SPILL: /* Keep accepting flows on the current process */
- list_add(&entry->next, &name->active);
+ list_add(&entry->next, &name->active.list);
break;
default:
goto fail_unreachable;
}
- name->n_active++;
+ ++name->active.len;
return 0;
@@ -226,19 +225,23 @@ void reg_name_del_active(struct reg_name * name,
list_del(&entry->next);
- name->n_active--;
+ --name->active.len;
free(entry);
}
pid_t reg_name_get_active(struct reg_name * name)
{
+ struct proc_entry * e;
+
assert(name != NULL);
- if (list_is_empty(&name->active))
+ if (list_is_empty(&name->active.list))
return -1;
- return list_first_entry(&name->active, struct proc_entry, next)->pid;
+ e = list_first_entry(&name->active.list, struct proc_entry, next);
+
+ return e->pid;
}
int reg_name_add_proc(struct reg_name * name,
@@ -259,9 +262,9 @@ int reg_name_add_proc(struct reg_name * name,
entry->pid = pid;
- list_add(&entry->next, &name->procs);
+ list_add(&entry->next, &name->procs.list);
- name->n_procs++;
+ ++name->procs.len;
return 0;
@@ -287,7 +290,7 @@ void reg_name_del_proc(struct reg_name * name,
free(entry);
- name->n_procs--;
+ --name->procs.len;
assert(__reg_name_get_proc(name, pid) == NULL);
}
@@ -296,8 +299,7 @@ bool reg_name_has_proc(const struct reg_name * name,
pid_t pid)
{
return __reg_name_get_proc(name, pid) != NULL;
-} char ** exec;
-
+}
int reg_name_add_prog(struct reg_name * name,
char ** exec)
@@ -322,11 +324,11 @@ int reg_name_add_prog(struct reg_name * name,
goto fail_exec;
}
- list_add(&entry->next, &name->progs);
+ list_add(&entry->next, &name->progs.list);
log_dbg("Add prog %s to name %s.", exec[0], name->info.name);
- name->n_progs++;
+ ++name->progs.len;
return 0;
@@ -352,7 +354,7 @@ void reg_name_del_prog(struct reg_name * name,
__free_prog_entry(entry);
- name->n_progs--;
+ --name->progs.len;
assert(__reg_name_get_prog(name, prog) == NULL);
}
@@ -368,8 +370,12 @@ bool reg_name_has_prog(const struct reg_name * name,
char ** reg_name_get_exec(const struct reg_name * name)
{
- if (list_is_empty(&name->progs))
+ struct prog_entry * e;
+
+ if (list_is_empty(&name->progs.list))
return NULL;
- return list_first_entry(&name->progs, struct prog_entry, next)->exec;
+ e = list_first_entry(&name->progs.list, struct prog_entry, next);
+
+ return e->exec;
}
diff --git a/src/irmd/reg/name.h b/src/irmd/reg/name.h
index 97ca7f04..30a64e1c 100644
--- a/src/irmd/reg/name.h
+++ b/src/irmd/reg/name.h
@@ -33,14 +33,25 @@ struct reg_name {
struct name_info info;
- struct list_head progs; /* autostart programs for this name */
- size_t n_progs; /* number of programs */
-
- struct list_head procs; /* processes bound to this name */
- size_t n_procs; /* number of processes */
-
- struct list_head active; /* processes actively calling accept */
- size_t n_active; /* number of processes accepting */
+ struct {
+ void * key;
+ void * crt;
+ } cache;
+
+ struct {
+ struct list_head list;
+ size_t len;
+ } progs; /* autostart programs for this name */
+
+ struct {
+ struct list_head list;
+ size_t len;
+ } procs; /* processes bound to this name */
+
+ struct {
+ struct list_head list;
+ size_t len;
+ } active; /* processes actively calling accept */
};
struct reg_name * reg_name_create(const struct name_info * info);
@@ -74,5 +85,4 @@ pid_t reg_name_get_active(struct reg_name * name);
void reg_name_del_active(struct reg_name * name,
pid_t proc);
-
#endif /* OUROBOROS_IRMD_REG_NAME_H */
diff --git a/src/irmd/reg/reg.c b/src/irmd/reg/reg.c
index 8d1fa8cf..0d4c6f24 100644
--- a/src/irmd/reg/reg.c
+++ b/src/irmd/reg/reg.c
@@ -28,6 +28,7 @@ The IPC Resource Manager - Registry
#include <ouroboros/errno.h>
#include <ouroboros/list.h>
#include <ouroboros/logs.h>
+#include <ouroboros/protobuf.h>
#include <ouroboros/pthread.h>
#include "reg.h"
@@ -46,6 +47,7 @@ The IPC Resource Manager - Registry
struct {
struct bmp * flow_ids; /* flow_ids for flows */
+
struct list_head flows; /* flow information */
size_t n_flows; /* number of flows */
@@ -196,6 +198,10 @@ static int __reg_get_pending_flow_id(const char * name)
struct reg_flow * flow;
pid_t pid;
+ assert(name != NULL);
+ assert(strlen(name) > 0);
+ assert(strlen(name) < NAME_SIZE + 1);
+
entry =__reg_get_name(name);
if (entry == NULL)
return -ENAME;
@@ -205,7 +211,10 @@ static int __reg_get_pending_flow_id(const char * name)
return -EAGAIN;
flow = __reg_get_accept_flow(pid);
- assert(flow != NULL);
+ if (flow == NULL) /* compiler barks, this can't be NULL */
+ return -EAGAIN;
+
+ strcpy(flow->name, name);
return flow->info.id;
}
@@ -580,6 +589,14 @@ void reg_clear(void)
reg.n_procs--;
}
+ list_for_each_safe(p, h, &reg.flows) {
+ struct reg_flow * entry;
+ entry = list_entry(p, struct reg_flow, next);
+ list_del(&entry->next);
+ reg_flow_destroy(entry);
+ reg.n_flows--;
+ }
+
list_for_each_safe(p, h, &reg.names) {
struct reg_name * entry;
entry = list_entry(p, struct reg_name, next);
@@ -596,14 +613,6 @@ void reg_clear(void)
reg.n_ipcps--;
}
- list_for_each_safe(p, h, &reg.flows) {
- struct reg_flow * entry;
- entry = list_entry(p, struct reg_flow, next);
- list_del(&entry->next);
- reg_flow_destroy(entry);
- reg.n_flows--;
- }
-
pthread_mutex_unlock(&reg.mtx);
}
@@ -950,6 +959,34 @@ bool reg_has_name(const char * name)
return ret;
}
+int reg_get_name_info(const char * name,
+ struct name_info * info)
+{
+ struct reg_name * n;
+
+ assert(name != NULL);
+ assert(info != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ n = __reg_get_name(name);
+ if (n == NULL) {
+ log_err("Name %s does not exist.", name);
+ goto no_name;
+ }
+
+ *info = n->info;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+
+ no_name:
+ pthread_mutex_unlock(&reg.mtx);
+ return -ENOENT;
+
+}
+
int reg_get_name_for_hash(char * buf,
enum hash_algo algo,
const uint8_t * hash)
@@ -986,29 +1023,20 @@ int reg_get_name_for_hash(char * buf,
return name == NULL ? -ENOENT : 0;
}
-
-static int __get_name_info(name_info_msg_t ** msg,
- struct reg_name * n)
+int reg_get_name_for_flow_id(char * buf,
+ int flow_id)
{
- *msg = malloc(sizeof(**msg));
- if (*msg == NULL)
- goto fail;
-
- name_info_msg__init(*msg);
+ struct reg_flow * f;
- (*msg)->name = strdup(n->info.name);
- if ((*msg)->name == NULL)
- goto fail_msg;
+ pthread_mutex_lock(&reg.mtx);
- (*msg)->pol_lb = n->info.pol_lb;
+ f = __reg_get_flow(flow_id);
+ if (f != NULL)
+ strcpy(buf, f->name);
- return 0;
+ pthread_mutex_unlock(&reg.mtx);
- fail_msg:
- name_info_msg__free_unpacked(*msg, NULL);
- *msg = NULL;
- fail:
- return -1;
+ return f == NULL ? -ENOENT : 0;
}
int reg_list_names(name_info_msg_t *** names)
@@ -1030,10 +1058,20 @@ int reg_list_names(name_info_msg_t *** names)
list_for_each(p, &reg.names) {
struct reg_name * entry;
entry = list_entry(p, struct reg_name, next);
- if (__get_name_info(&(*names)[i], entry) < 0) {
+ (*names)[i] = name_info_s_to_msg(&entry->info);
+ if ((*names)[i] == NULL) {
log_err("Failed to create name list info.");
goto fail;
}
+ /* wipe security info to avoid huge messages */
+ free((*names)[i]->scrt);
+ (*names)[i]->scrt = NULL;
+ free((*names)[i]->skey);
+ (*names)[i]->skey = NULL;
+ free((*names)[i]->ccrt);
+ (*names)[i]->ccrt = NULL;
+ free((*names)[i]->ckey);
+ (*names)[i]->ckey = NULL;
i++;
}
@@ -1947,12 +1985,14 @@ void reg_dealloc_flow(struct flow_info * info)
assert(flow != NULL);
assert(flow->data.data == NULL);
assert(flow->data.len == 0);
-
assert(flow->info.state == FLOW_ALLOCATED);
+
flow->info.state = FLOW_DEALLOC_PENDING;
info->state = FLOW_DEALLOC_PENDING;
info->n_1_pid = flow->info.n_1_pid;
+ memset(flow->name, 0, sizeof(flow->name));
+
reg_flow_update(flow, info);
pthread_mutex_unlock(&reg.mtx);
diff --git a/src/irmd/reg/reg.h b/src/irmd/reg/reg.h
index 00db8f0b..57257dd5 100644
--- a/src/irmd/reg/reg.h
+++ b/src/irmd/reg/reg.h
@@ -90,10 +90,16 @@ int reg_destroy_name(const char * name);
bool reg_has_name(const char * name);
+int reg_get_name_info(const char * name,
+ struct name_info * info);
+
int reg_get_name_for_hash(char * buf,
enum hash_algo algo,
const uint8_t * hash);
+int reg_get_name_for_flow_id(char * buf,
+ int flow_id);
+
/* TODO don't rely on protobuf here */
int reg_list_names(name_info_msg_t *** names);
diff --git a/src/irmd/reg/tests/name_test.c b/src/irmd/reg/tests/name_test.c
index 64635eec..9071364b 100644
--- a/src/irmd/reg/tests/name_test.c
+++ b/src/irmd/reg/tests/name_test.c
@@ -76,8 +76,8 @@ static int test_reg_name_add_proc(void)
goto fail;
}
- if (n->n_procs != 1) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 1) {
+ printf("Proc not added to list.\n");
goto fail;
}
@@ -88,8 +88,8 @@ static int test_reg_name_add_proc(void)
reg_name_del_proc(n, TEST_PID);
- if (n->n_procs != 0) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 0) {
+ printf("Proc not removed from list.\n");
goto fail;
}
@@ -126,8 +126,8 @@ static int test_reg_name_add_prog(void)
goto fail;
}
- if (n->n_progs != 1) {
- printf("n_progs not updated.\n");
+ if (n->progs.len != 1) {
+ printf("Prog not added to list.\n");
goto fail;
}
@@ -138,8 +138,8 @@ static int test_reg_name_add_prog(void)
reg_name_del_prog(n, TEST_PROG);
- if (n->n_progs != 0) {
- printf("n_progs not updated.\n");
+ if (n->progs.len != 0) {
+ printf("Prog not removed from list.\n");
goto fail;
}
@@ -195,8 +195,8 @@ static int test_reg_name_add_active(enum pol_balance lb)
goto fail;
}
- if (n->n_active != 1) {
- printf("n_active not updated.\n");
+ if (n->active.len != 1) {
+ printf("Active list not updated.\n");
goto fail;
}
@@ -226,13 +226,13 @@ static int test_reg_name_add_active(enum pol_balance lb)
goto fail;
}
- if (n->n_procs != 3) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 3) {
+ printf("Procs list not updated.\n");
goto fail;
}
- if (n->n_active != 4) {
- printf("n_active not updated.\n");
+ if (n->active.len != 4) {
+ printf("Active list not updated.\n");
goto fail;
}
@@ -263,13 +263,13 @@ static int test_reg_name_add_active(enum pol_balance lb)
reg_name_del_proc(n, TEST_PID);
- if (n->n_procs != 0) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 0) {
+ printf("Procs list not cleared.\n");
goto fail;
}
- if (n->n_active != 0) {
- printf("n_active not updated.\n");
+ if (n->active.len != 0) {
+ printf("Active list not cleared.\n");
goto fail;
}
@@ -283,20 +283,19 @@ static int test_reg_name_add_active(enum pol_balance lb)
return TEST_RC_FAIL;
}
-
int name_test(int argc,
char ** argv)
{
- int res = 0;
+ int rc = 0;
(void) argc;
(void) argv;
- res |= test_reg_name_create();
- res |= test_reg_name_add_proc();
- res |= test_reg_name_add_prog();
- res |= test_reg_name_add_active(LB_RR);
- res |= test_reg_name_add_active(LB_SPILL);
+ rc |= test_reg_name_create();
+ rc |= test_reg_name_add_proc();
+ rc |= test_reg_name_add_prog();
+ rc |= test_reg_name_add_active(LB_RR);
+ rc |= test_reg_name_add_active(LB_SPILL);
- return res;
+ return rc;
}
diff --git a/src/irmd/reg/tests/reg_test.c b/src/irmd/reg/tests/reg_test.c
index fb99e6d3..280ea9a8 100644
--- a/src/irmd/reg/tests/reg_test.c
+++ b/src/irmd/reg/tests/reg_test.c
@@ -36,7 +36,7 @@
#define TEST_DATA2 "testpbufdata2"
#define TEST_LAYER "testlayer"
#define REG_TEST_FAIL() \
- do { TEST_FAIL(); memset(&reg, 0, sizeof(reg)); } while(0)
+ do { TEST_FAIL(); memset(&reg, 0, sizeof(reg)); abort();} while(0)
static int test_reg_init(void)
{
@@ -254,7 +254,7 @@ static int test_reg_accept_flow_success(void)
pthread_create(&thr, NULL, test_flow_respond_accept, &n_1_info);
- if (reg_wait_flow_accepted(&info, &rbuf, &abstime) < 0 ) {
+ if (reg_wait_flow_accepted(&info, &rbuf, &abstime) < 0) {
printf("Flow allocation failed.\n");
goto fail;
}
@@ -1344,13 +1344,14 @@ static int test_wait_accepting_success(void)
{
struct timespec abstime;
struct timespec timeo = TIMESPEC_INIT_S(1);
- int flow_id;
pthread_t thr;
+ int flow_id;
struct name_info ninfo = {
.name = TEST_NAME,
.pol_lb = LB_RR
};
+
TEST_START();
if (reg_init()) {
diff --git a/src/irmd/tests/oap_test.c b/src/irmd/tests/oap_test.c
index 2e27762d..4e7fb2d1 100644
--- a/src/irmd/tests/oap_test.c
+++ b/src/irmd/tests/oap_test.c
@@ -210,6 +210,16 @@ static int test_oap_hdr_init_fini_signed(void)
goto fail_req_hdr;
}
+ if (oap_hdr.crt.len == 0) {
+ printf("OAP request header has no public certificate.\n");
+ goto fail_req_hdr;
+ }
+
+ if (oap_hdr.sig.len == 0) {
+ printf("OAP request header no signature.\n");
+ goto fail_req_hdr;
+ }
+
if (crypt_load_crt_der(oap_hdr.crt, &pubcrt2) < 0) {
printf("Failed to load public certificate from DER.\n");
goto fail_crt_der;
diff --git a/src/lib/crypt.c b/src/lib/crypt.c
index e8c4d5ab..b39a4a73 100644
--- a/src/lib/crypt.c
+++ b/src/lib/crypt.c
@@ -393,7 +393,7 @@ int auth_add_crt_to_store(struct auth_ctx * ctx,
(void) ctx;
(void) crt;
- return -1;
+ return 0;
#endif
}
diff --git a/src/lib/crypt/openssl.c b/src/lib/crypt/openssl.c
index 1824d879..03662914 100644
--- a/src/lib/crypt/openssl.c
+++ b/src/lib/crypt/openssl.c
@@ -29,8 +29,6 @@
#include <ouroboros/random.h>
#include <ouroboros/utils.h>
-#include <assert.h>
-
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/ec.h>
@@ -39,6 +37,8 @@
#include <openssl/x509v3.h>
#include <openssl/x509_vfy.h>
+#include <assert.h>
+
/*
* Derive the common secret from
* - your public key pair (kp)
diff --git a/src/lib/irm.c b/src/lib/irm.c
index d25101f3..8333d0d3 100644
--- a/src/lib/irm.c
+++ b/src/lib/irm.c
@@ -523,32 +523,23 @@ int irm_unbind_process(pid_t pid,
return ret;
}
-int irm_create_name(const char * name,
- enum pol_balance pol)
+int irm_create_name(struct name_info * info)
{
irm_msg_t msg = IRM_MSG__INIT;
- name_info_msg_t ni_msg = NAME_INFO_MSG__INIT;
irm_msg_t * recv_msg;
int ret;
- if (name == NULL)
+ if (info == NULL)
return -EINVAL;
- msg.code = IRM_MSG_CODE__IRM_CREATE_NAME;
- ni_msg.name = (char *) name;
- ni_msg.pol_lb = pol;
- msg.n_names = 1;
-
- msg.names = malloc(sizeof(*msg.names));
- if (msg.names == NULL) {
- return -ENOMEM;
- }
-
- msg.names[0] = &ni_msg;
+ msg.code = IRM_MSG_CODE__IRM_CREATE_NAME;
+ msg.name_info = name_info_s_to_msg(info);
+ if (msg.name_info == NULL)
+ goto fail_info_msg;
recv_msg = send_recv_irm_msg(&msg);
- free(msg.names);
+ name_info_msg__free_unpacked(msg.name_info, NULL);
if (recv_msg == NULL)
return -EIRMD;
@@ -562,6 +553,9 @@ int irm_create_name(const char * name,
irm_msg__free_unpacked(recv_msg, NULL);
return ret;
+
+ fail_info_msg:
+ return -ENOMEM;
}
int irm_destroy_name(const char * name)
diff --git a/src/lib/pb/irm.proto b/src/lib/pb/irm.proto
index da3bd982..75f5f350 100644
--- a/src/lib/pb/irm.proto
+++ b/src/lib/pb/irm.proto
@@ -75,18 +75,19 @@ message irm_msg {
optional string name = 4;
optional flow_info_msg flow_info = 5;
optional ipcp_info_msg ipcp_info = 6;
- optional string layer = 7;
- repeated string exec = 8;
- optional sint32 response = 9;
- optional string dst = 10;
- optional bytes hash = 11;
- optional sint32 flow_id = 12;
- optional qosspec_msg qosspec = 13;
- optional ipcp_config_msg conf = 14;
- optional uint32 opts = 15;
- repeated ipcp_list_msg ipcps = 16;
- repeated name_info_msg names = 17;
- optional timespec_msg timeo = 18;
+ optional name_info_msg name_info = 7;
+ optional string layer = 8;
+ repeated string exec = 9;
+ optional sint32 response = 10;
+ optional string dst = 11;
+ optional bytes hash = 12;
+ optional sint32 flow_id = 13;
+ optional qosspec_msg qosspec = 14;
+ optional ipcp_config_msg conf = 15;
+ optional uint32 opts = 16;
+ repeated ipcp_list_msg ipcps = 17;
+ repeated name_info_msg names = 18;
+ optional timespec_msg timeo = 19;
optional sint32 mpl = 20;
optional string comp = 21;
optional bytes pk = 22; /* piggyback */
diff --git a/src/lib/pb/model.proto b/src/lib/pb/model.proto
index f1e401f9..56337b5b 100644
--- a/src/lib/pb/model.proto
+++ b/src/lib/pb/model.proto
@@ -44,8 +44,12 @@ message flow_info_msg {
}
message name_info_msg {
- required string name = 1;
- required uint32 pol_lb = 2;
+ required string name = 1;
+ required uint32 pol_lb = 2;
+ required string skey = 3;
+ required string scrt = 4;
+ required string ckey = 5;
+ required string ccrt = 6;
}
message layer_info_msg {
diff --git a/src/lib/protobuf.c b/src/lib/protobuf.c
index 43ef6ac6..b2a0cb3b 100644
--- a/src/lib/protobuf.c
+++ b/src/lib/protobuf.c
@@ -106,6 +106,66 @@ struct flow_info flow_info_msg_to_s(const flow_info_msg_t * msg)
return s;
}
+name_info_msg_t * name_info_s_to_msg(const struct name_info * info)
+{
+ name_info_msg_t * msg;
+
+ assert(info != NULL);
+
+ msg = malloc(sizeof(*msg));
+ if (msg == NULL)
+ goto fail_malloc;
+
+ name_info_msg__init(msg);
+
+ msg->name = strdup(info->name);
+ if (msg->name == NULL)
+ goto fail_msg;
+
+ msg->skey = strdup(info->s.key);
+ if (msg->skey == NULL)
+ goto fail_msg;
+
+ msg->scrt = strdup(info->s.crt);
+ if (msg->scrt == NULL)
+ goto fail_msg;
+
+ msg->ckey = strdup(info->c.key);
+ if (msg->skey == NULL)
+ goto fail_msg;
+
+ msg->ccrt = strdup(info->c.crt);
+ if (msg->ccrt == NULL)
+ goto fail_msg;
+
+ msg->pol_lb = info->pol_lb;
+
+ return msg;
+
+ fail_msg:
+ name_info_msg__free_unpacked(msg, NULL);
+ fail_malloc:
+ return NULL;
+}
+
+struct name_info name_info_msg_to_s(const name_info_msg_t * msg)
+{
+ struct name_info s;
+
+ assert(msg != NULL);
+ assert(strlen(msg->name) <= NAME_SIZE);
+
+ strcpy(s.name, msg->name);
+ strcpy(s.s.key, msg->skey);
+ strcpy(s.s.crt, msg->scrt);
+ strcpy(s.c.key, msg->ckey);
+ strcpy(s.c.crt, msg->ccrt);
+
+ s.pol_lb = msg->pol_lb;
+
+ return s;
+}
+
layer_info_msg_t * layer_info_s_to_msg(const struct layer_info * s)
{
layer_info_msg_t * msg;
diff --git a/src/lib/tests/auth_test.c b/src/lib/tests/auth_test.c
index a5bf931d..ede294b8 100644
--- a/src/lib/tests/auth_test.c
+++ b/src/lib/tests/auth_test.c
@@ -323,6 +323,45 @@ static int test_crypt_check_pubkey_crt(void)
return TEST_RC_FAIL;
}
+static int test_store_add(void)
+{
+ struct auth_ctx * ctx;
+ void * _root_ca_crt;
+
+ TEST_START();
+
+ ctx = auth_create_ctx();
+ if (ctx == NULL) {
+ printf("Failed to create auth context.\n");
+ goto fail_create;
+ }
+
+ if (crypt_load_crt_str(root_ca_crt, &_root_ca_crt) < 0) {
+ printf("Failed to load root crt from string.\n");
+ goto fail_load;
+ }
+
+ if (auth_add_crt_to_store(ctx, _root_ca_crt) < 0) {
+ printf("Failed to add root crt to auth store.\n");
+ goto fail_add;
+ }
+
+ crypt_free_crt(_root_ca_crt);
+ auth_destroy_ctx(ctx);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_add:
+ crypt_free_crt(_root_ca_crt);
+ fail_load:
+ crypt_free_crt(_root_ca_crt);
+ fail_create:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
static int test_verify_crt(void)
{
struct auth_ctx * auth;
@@ -532,6 +571,38 @@ int test_auth_bad_signature(void)
return TEST_RC_FAIL;
}
+int test_crt_str(void)
+{
+ char str[2295];
+ void * crt;
+
+ TEST_START();
+
+ if (crypt_load_crt_str(signed_server_crt, &crt) < 0) {
+ printf("Failed to load certificate from string.\n");
+ goto fail_load;
+ }
+
+ if (crypt_crt_str(crt, str) < 0) {
+ printf("Failed to convert certificate to string.\n");
+ goto fail_to_str;
+ }
+
+ printf("Certificate string:\n%s\n", str);
+
+ crypt_free_crt(crt);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_to_str:
+ crypt_free_crt(crt);
+ fail_load:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
int auth_test(int argc,
char ** argv)
{
@@ -548,9 +619,11 @@ int auth_test(int argc,
ret |= test_load_free_privkey();
ret |= test_load_free_pubkey();
ret |= test_crypt_check_pubkey_crt();
+ ret |= test_store_add();
ret |= test_verify_crt();
ret |= test_auth_sign();
ret |= test_auth_bad_signature();
+ ret |= test_crt_str();
#else
(void) test_load_free_crt;
(void) test_check_crt_name;
@@ -558,9 +631,11 @@ int auth_test(int argc,
(void) test_load_free_privkey;
(void) test_load_free_pubkey;
(void) test_crypt_check_pubkey_crt;
+ (void) test_store_add;
(void) test_verify_crt;
(void) test_auth_sign;
(void) test_auth_bad_signature;
+ (void) test_crt_str;
ret = TEST_RC_SKIP;
#endif
diff --git a/src/tools/irm/irm_name_create.c b/src/tools/irm/irm_name_create.c
index a0079cad..04d7f95f 100644
--- a/src/tools/irm/irm_name_create.c
+++ b/src/tools/irm/irm_name_create.c
@@ -36,31 +36,50 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#define _POSIX_C_SOURCE 200809L
+#define _XOPEN_SOURCE 500
+
+#include <ouroboros/errno.h>
#include <ouroboros/irm.h>
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
#include "irm_ops.h"
#include "irm_utils.h"
#define RR "round-robin"
#define SPILL "spillover"
+#define SCRT "<security_dir>/server/<name>/crt.pem"
+#define SKEY "<security_dir>/server/<name>/key.pem"
+#define CCRT "<security_dir>/client/<name>/crt.pem"
+#define CKEY "<security_dir>/client/<name>/key.pem"
static void usage(void)
{
printf("Usage: irm name create\n"
- " <name>\n"
- " lb [LB_POLICY], default: %s\n\n"
- "where LB_POLICY in {" RR " " SPILL "}\n", RR);
+ " <name>. max %d chars.\n"
+ " [lb LB_POLICY], default: %s\n"
+ " [scrtpath <path>, default: " SCRT "]\n"
+ " [skeypath <path>, default: " SKEY "]\n"
+ " [ccrtpath <path>, default: " CCRT "]\n"
+ " [ckeypath <path>, default: " CKEY "]\n"
+ "\n"
+ "where LB_POLICY in {" RR " " SPILL "}\n",
+ NAME_SIZE, RR);
}
int do_create_name(int argc,
char ** argv)
{
- char * name = NULL;
- char * lb_pol = RR;
- enum pol_balance pol_lb = LB_RR;
+ struct name_info info = {};
+ char * name = NULL;
+ char * scrtpath = NULL;
+ char * skeypath = NULL;
+ char * ccrtpath = NULL;
+ char * ckeypath = NULL;
+ char * lb_pol = RR;
name = *(argv++);
--argc;
@@ -68,6 +87,14 @@ int do_create_name(int argc,
while (argc > 0) {
if (matches(*argv, "lb") == 0) {
lb_pol = *(argv + 1);
+ } else if (matches(*argv, "scrtpath") == 0) {
+ scrtpath = *(argv + 1);
+ } else if (matches(*argv, "skeypath") == 0) {
+ skeypath = *(argv + 1);
+ } else if (matches(*argv, "ccrtpath") == 0) {
+ ccrtpath = *(argv + 1);
+ } else if (matches(*argv, "ckeypath") == 0) {
+ ckeypath = *(argv + 1);
} else {
printf("\"%s\" is unknown, try \"irm "
"name create\".\n", *argv);
@@ -78,19 +105,92 @@ int do_create_name(int argc,
argv += 2;
}
- if (name == NULL) {
- usage();
- return -1;
+ if (name == NULL)
+ goto fail;
+
+ if (strlen(name) > NAME_SIZE) {
+ printf("Name too long.\n");
+ goto fail;
+ }
+
+ strcpy(info.name, name);
+
+ if (scrtpath != NULL) {
+ scrtpath = realpath(scrtpath, NULL);
+ if (scrtpath == NULL) {
+ printf("Failed to resolve server crt path: %s.\n",
+ strerror(errno));
+ goto fail;
+ }
+ if (strlen(scrtpath) > NAME_PATH_SIZE) {
+ printf("Server crt path > %d chars.", NAME_PATH_SIZE);
+ free(scrtpath);
+ goto fail;
+ }
+ strcpy(info.s.crt, scrtpath);
+ free(scrtpath);
+ }
+
+ if (skeypath != NULL) {
+ skeypath = realpath(skeypath, NULL);
+ if (skeypath == NULL) {
+ printf("Failed to resolve server key path: %s.\n",
+ strerror(errno));
+ goto fail;
+ }
+ if (strlen(skeypath) > NAME_PATH_SIZE) {
+ printf("Server key path > %d chars.", NAME_PATH_SIZE);
+ free(skeypath);
+ goto fail;
+ }
+ strcpy(info.s.key, skeypath);
+ free(skeypath);
+ }
+
+ if (ccrtpath != NULL) {
+ ccrtpath = realpath(ccrtpath, NULL);
+ if (ccrtpath == NULL) {
+ printf("Failed to resolve client crt path: %s.\n",
+ strerror(errno));
+ goto fail;
+ }
+ if (strlen(ccrtpath) > NAME_PATH_SIZE) {
+ printf("Client crt path > %d chars.", NAME_PATH_SIZE);
+ free(ccrtpath);
+ goto fail;
+ }
+ strcpy(info.c.crt, ccrtpath);
+ free(ccrtpath);
+ }
+
+ if (ckeypath != NULL) {
+ ckeypath = realpath(ckeypath, NULL);
+ if (ckeypath == NULL) {
+ printf("Failed to resolve client key path: %s.\n",
+ strerror(errno));
+ goto fail;
+ }
+
+ if (strlen(ckeypath) > NAME_PATH_SIZE) {
+ printf("Client key path > %d chars.", NAME_PATH_SIZE);
+ free(ckeypath);
+ goto fail;
+ }
+ strcpy(info.c.key, ckeypath);
+ free(ckeypath);
}
if (strcmp(lb_pol, RR) == 0)
- pol_lb = LB_RR;
+ info.pol_lb = LB_RR;
else if (strcmp(lb_pol, SPILL) == 0)
- pol_lb = LB_SPILL;
+ info.pol_lb = LB_SPILL;
else {
usage();
return -1;
}
- return irm_create_name(name, pol_lb);
+ return irm_create_name(&info);
+ fail:
+ usage();
+ return -1;
}
diff --git a/src/tools/irm/irm_name_reg.c b/src/tools/irm/irm_name_reg.c
index 061ed8be..7689119a 100644
--- a/src/tools/irm/irm_name_reg.c
+++ b/src/tools/irm/irm_name_reg.c
@@ -107,14 +107,23 @@ int do_reg_name(int argc,
return -1;
}
+ if (strlen(name) > NAME_SIZE) {
+ printf("Name too long.\n");
+ usage();
+ return -1;
+ }
+
ipcps_len = irm_list_ipcps(&ipcps);
- if (ipcps_len < 0)
- return ipcps_len;
+ if (ipcps_len <= 0) {
+ printf("Failed to list IPCPs.\n");
+ return -1;
+ }
names_len = irm_list_names(&names);
if (names_len < 0) {
+ printf("Failed to list names.\n");
free(ipcps);
- return names_len;
+ return -1;
}
for (i = 0; i < names_len; ++i) {
@@ -124,11 +133,19 @@ int do_reg_name(int argc,
}
}
- if (name_create && irm_create_name(name, LB_SPILL)) {
- printf("Error creating name.");
- free(ipcps);
- free(name);
- return -1;
+ if (name_create) {
+ struct name_info info = {
+ .pol_lb = LB_SPILL
+ };
+
+ strcpy(info.name, name);
+
+ if (irm_create_name(&info) < 0) {
+ printf("Error creating name.");
+ free(ipcps);
+ free(names);
+ return -1;
+ }
}
for (i = 0; i < ipcps_len; ++i) {
@@ -136,6 +153,8 @@ int do_reg_name(int argc,
for (j = 0; j < layers_len; j++) {
if (wildcard_match(layers[j], ipcps[i].layer) == 0) {
if (irm_reg_name(name, ipcps[i].pid)) {
+ printf("Failed to register with %s",
+ ipcps[i].layer);
free(ipcps);
free(names);
return -1;
@@ -145,6 +164,8 @@ int do_reg_name(int argc,
for (j = 0; j < ipcp_len; j++) {
if (wildcard_match(ipcp[j], ipcps[i].name) == 0) {
if (irm_reg_name(name, ipcps[i].pid)) {
+ printf("Failed to register with %s",
+ ipcps[i].name);
free(ipcps);
free(names);
return -1;