diff options
Diffstat (limited to 'src/irmd/main.c')
-rw-r--r-- | src/irmd/main.c | 219 |
1 files changed, 171 insertions, 48 deletions
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 <ouroboros/crypt.h> #include <ouroboros/hash.h> #include <ouroboros/errno.h> #include <ouroboros/sockets.h> @@ -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: |