From 676bd51161e7584175b97cfb7ec2bebd6d951acc Mon Sep 17 00:00:00 2001 From: Dimitri Staessens Date: Sun, 10 Dec 2023 14:53:41 +0100 Subject: lib: Move public key handling from app to IRMd The application was generating its public keypair for its ECDHE key exchange. This is now done by the IRMd, which will check the requested qosspec and then apply what is needed. The flow_alloc and flow_accept calls will just return the symmetric key to the application. This makes it easier when we add configurations with given public key pairs and other encryption algorithms, which can then all be configured globally in the IRMd instead of having all the options replicated and implemented in each and every application. Signed-off-by: Dimitri Staessens Signed-off-by: Sander Vrijders --- src/irmd/main.c | 219 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 171 insertions(+), 48 deletions(-) (limited to 'src/irmd/main.c') diff --git a/src/irmd/main.c b/src/irmd/main.c index 5e58052d..59c1c5ec 100644 --- a/src/irmd/main.c +++ b/src/irmd/main.c @@ -30,6 +30,7 @@ #define OUROBOROS_PREFIX "irmd" +#include #include #include #include @@ -76,6 +77,7 @@ #define IPCP_HASH_LEN(p) hash_len((p)->dir_hash_algo) #define BIND_TIMEOUT 10 /* ms */ #define DEALLOC_TIME 300 /* s */ +#define MSGBUFSZ 2048 #define registry_has_name(name) \ (registry_get_name(name) != NULL) @@ -1349,6 +1351,14 @@ static int flow_accept(pid_t pid, int flow_id; int ret; buffer_t tmp = {NULL, 0}; + void * pkp; /* my public key pair */ + ssize_t key_len; + uint8_t buf[MSGBUFSZ]; + uint8_t * s = NULL; + int err; + + /* piggyback of user data not yet implemented */ + assert(data != NULL && data->len == 0 && data->data == NULL); pthread_rwlock_wrlock(&irmd.reg_lock); @@ -1379,8 +1389,26 @@ static int flow_accept(pid_t pid, if (ret == -1) return -EPIPE; - if (irmd_get_state() != IRMD_RUNNING) + if (irmd_get_state() != IRMD_RUNNING) { + log_dbg("Terminating accept: IRMd shutting down."); return -EIRMD; + } + + s = malloc(SYMMKEYSZ); + if (s == NULL) { + log_err("Failed to malloc symmetric key."); + err = -ENOMEM; + goto fail_malloc_s; + } + + key_len = crypt_dh_pkp_create(&pkp, buf); + if (key_len < 0) { + log_err("Failed to generate key pair."); + err = -ECRYPT; + goto fail_pkp; + } + + log_dbg("Generated ephemeral keys for %d.", pid); pthread_rwlock_wrlock(&irmd.reg_lock); @@ -1388,7 +1416,8 @@ static int flow_accept(pid_t pid, if (f == NULL) { pthread_rwlock_unlock(&irmd.reg_lock); log_warn("Port_id was not created yet."); - return -EPERM; + err = -EPERM; + goto fail_rp; } pid_n = f->n_pid; @@ -1405,7 +1434,8 @@ static int flow_accept(pid_t pid, reg_flow_set_state(f, FLOW_NULL); reg_flow_destroy(f); log_dbg("Process gone while accepting flow."); - return -EPERM; + err = -EPERM; + goto fail_rp; } pthread_mutex_lock(&rp->lock); @@ -1423,7 +1453,8 @@ static int flow_accept(pid_t pid, reg_flow_set_state(f, FLOW_NULL); reg_flow_destroy(f); log_err("Entry in wrong state."); - return -EPERM; + err = -EPERM; + goto fail_rp; } registry_names_del_proc(pid); @@ -1434,11 +1465,26 @@ static int flow_accept(pid_t pid, f_out->qs = f->qs; f_out->mpl = f->mpl; - if (f->qs.cypher_s != 0) /* crypto requested, send pubkey */ - tmp = *data; + if (f->qs.cypher_s != 0) { /* crypto requested */ + tmp.len = key_len; /* send this pubkey */ + tmp.data = (uint8_t *) buf; + + if (crypt_dh_derive(pkp, f->data.data, f->data.len, s) < 0) { + list_del(&f->next); + bmp_release(irmd.flow_ids, f->flow_id); + freebuf(f->data); + pthread_rwlock_unlock(&irmd.reg_lock); + clear_reg_flow(f); + reg_flow_set_state(f, FLOW_NULL); + reg_flow_destroy(f); + log_err("Failed to derive common secret for %d.", + flow_id); + err = -ECRYPT; + goto fail_rp; + } + } - *data = f->data; /* pass owner */ - clrbuf (f->data); + freebuf(f->data); pthread_rwlock_unlock(&irmd.reg_lock); @@ -1450,14 +1496,29 @@ static int flow_accept(pid_t pid, clear_reg_flow(f); reg_flow_set_state(f, FLOW_NULL); reg_flow_destroy(f); - return -EPERM; + err = -EPERM; + goto fail_rp; } reg_flow_set_state(f, FLOW_ALLOCATED); + crypt_dh_pkp_destroy(pkp); + + if (f_out->qs.cypher_s > 0) { + data->data = s; + data->len = SYMMKEYSZ; + } + log_info("Flow on flow_id %d allocated.", f->flow_id); return 0; + + fail_rp: + crypt_dh_pkp_destroy(pkp); + fail_pkp: + free(s); + fail_malloc_s: + return err; } static int flow_join(pid_t pid, @@ -1466,11 +1527,11 @@ static int flow_join(pid_t pid, struct timespec * dl, struct reg_flow * f_out) { - struct reg_flow * f; + struct reg_flow * f; struct reg_ipcp * ipcp; - int flow_id; - int state; - uint8_t * hash; + int flow_id; + int state; + uint8_t * hash; log_info("Allocating flow for %d to %s.", pid, dst); @@ -1563,13 +1624,44 @@ static int flow_alloc(pid_t pid, int flow_id; int state; uint8_t * hash; + ssize_t key_len; + void * pkp; /* my public key pair */ + buffer_t tmp; /* buffer for public key */ + uint8_t buf[MSGBUFSZ]; + uint8_t * s = NULL; + int err; log_info("Allocating flow for %d to %s.", pid, dst); + /* piggyback of user data not yet implemented */ + assert(data != NULL && data->len == 0 && data->data == NULL); + + if (qs.cypher_s > 0) { + s = malloc(SYMMKEYSZ); + if (s == NULL) { + log_err("Failed to malloc symmetric key."); + err = -ENOMEM; + goto fail_malloc_s; + } + + key_len = crypt_dh_pkp_create(&pkp, buf); + if (key_len < 0) { + log_err("Failed to generate key pair."); + err = -ECRYPT; + goto fail_pkp; + } + + log_dbg("Generated ephemeral keys for %d.", pid); + + tmp.data = (uint8_t *) buf; + tmp.len = (size_t) key_len; + } + ipcp = registry_get_ipcp_by_dst_name(dst, pid); if (ipcp == NULL) { log_info("Destination %s unreachable.", dst); - return -1; + err = -ENOTALLOC; + goto fail_ipcp; } pthread_rwlock_wrlock(&irmd.reg_lock); @@ -1578,15 +1670,16 @@ static int flow_alloc(pid_t pid, if (!bmp_is_id_valid(irmd.flow_ids, flow_id)) { pthread_rwlock_unlock(&irmd.reg_lock); log_err("Could not allocate flow_id."); - return -EBADF; + err = -EBADF; + goto fail_ipcp; } f = reg_flow_create(pid, ipcp->pid, flow_id, qs); if (f == NULL) { - bmp_release(irmd.flow_ids, flow_id); pthread_rwlock_unlock(&irmd.reg_lock); log_err("Could not allocate flow_id."); - return -ENOMEM; + err = -ENOMEM; + goto fail_flow; } list_add(&f->next, &irmd.flows); @@ -1596,32 +1689,34 @@ static int flow_alloc(pid_t pid, assert(reg_flow_get_state(f) == FLOW_ALLOC_PENDING); hash = malloc(IPCP_HASH_LEN(ipcp)); - if (hash == NULL) - /* sanitizer cleans this */ - return -ENOMEM; + if (hash == NULL) { + /* sanitizer cleans regflow */ + err = -ENOMEM; + goto fail_flow; + } str_hash(ipcp->dir_hash_algo, hash, dst); if (ipcp_flow_alloc(ipcp->pid, flow_id, pid, hash, - IPCP_HASH_LEN(ipcp), qs, *data)) { + IPCP_HASH_LEN(ipcp), qs, tmp)) { reg_flow_set_state(f, FLOW_NULL); /* sanitizer cleans this */ log_warn("Flow_allocation %d failed.", flow_id); - free(hash); - return -EAGAIN; + err = -ENOTALLOC; + goto fail_alloc; } - free(hash); - state = reg_flow_wait_state(f, FLOW_ALLOCATED, dl); if (state != FLOW_ALLOCATED) { if (state == -ETIMEDOUT) { log_err("Flow allocation timed out"); - return -ETIMEDOUT; + err = -ETIMEDOUT; + goto fail_alloc; } log_warn("Pending flow to %s torn down.", dst); - return -EPIPE; + err = -EPIPE; + goto fail_alloc; } pthread_rwlock_wrlock(&irmd.reg_lock); @@ -1632,14 +1727,41 @@ static int flow_alloc(pid_t pid, f_out->n_pid = f->n_pid; f_out->n_1_pid = f->n_1_pid; f_out->mpl = f->mpl; - *data = f->data; /* pass owner */ - clrbuf(f->data); + if (qs.cypher_s > 0 && + crypt_dh_derive(pkp, f->data.data, f->data.len, s) < 0) { + freebuf(f->data); + pthread_rwlock_unlock(&irmd.reg_lock); + log_err("Failed to derive common secret for %d.", flow_id); + err = -ECRYPT; + goto fail_alloc; + } + + freebuf(f->data); pthread_rwlock_unlock(&irmd.reg_lock); + free(hash); + crypt_dh_pkp_destroy(pkp); + + data->data = s; + data->len = SYMMKEYSZ; + log_info("Flow on flow_id %d allocated.", flow_id); return 0; + + fail_alloc: + free(hash); + fail_flow: + bmp_release(irmd.flow_ids, flow_id); + fail_ipcp: + if (qs.cypher_s > 0) + crypt_dh_pkp_destroy(pkp); + fail_pkp: + free(s); + fail_malloc_s: + return err; + } static int flow_dealloc(pid_t pid, @@ -2178,34 +2300,35 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg) if (res == 0) { qosspec_msg_t * qs_msg; qs_msg = qos_spec_s_to_msg(&f.qs); - ret_msg->has_flow_id = true; - ret_msg->flow_id = f.flow_id; - ret_msg->has_pid = true; - ret_msg->pid = f.n_1_pid; - ret_msg->qosspec = qs_msg; - ret_msg->has_mpl = true; - ret_msg->mpl = f.mpl; - ret_msg->has_pk = true; - ret_msg->pk.data = data.data; - ret_msg->pk.len = data.len; + ret_msg->has_flow_id = true; + ret_msg->flow_id = f.flow_id; + ret_msg->has_pid = true; + ret_msg->pid = f.n_1_pid; + ret_msg->qosspec = qs_msg; + ret_msg->has_mpl = true; + ret_msg->mpl = f.mpl; + ret_msg->has_symmkey = data.len != 0; + ret_msg->symmkey.data = data.data; + ret_msg->symmkey.len = data.len; } break; case IRM_MSG_CODE__IRM_FLOW_ALLOC: data.len = msg->pk.len; data.data = msg->pk.data; + msg->has_pk = false; qs = qos_spec_msg_to_s(msg->qosspec); assert(data.len > 0 ? data.data != NULL : data.data == NULL); res = flow_alloc(msg->pid, msg->dst, qs, dl, &f, &data); if (res == 0) { - ret_msg->has_flow_id = true; - ret_msg->flow_id = f.flow_id; - ret_msg->has_pid = true; - ret_msg->pid = f.n_1_pid; - ret_msg->has_mpl = true; - ret_msg->mpl = f.mpl; - ret_msg->has_pk = true; - ret_msg->pk.data = data.data; - ret_msg->pk.len = data.len; + ret_msg->has_flow_id = true; + ret_msg->flow_id = f.flow_id; + ret_msg->has_pid = true; + ret_msg->pid = f.n_1_pid; + ret_msg->has_mpl = true; + ret_msg->mpl = f.mpl; + ret_msg->has_symmkey = data.len != 0; + ret_msg->symmkey.data = data.data; + ret_msg->symmkey.len = data.len; } break; case IRM_MSG_CODE__IRM_FLOW_JOIN: -- cgit v1.2.3