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 ++++++++++++++++++++++++++++++++++++++++----------- src/lib/crypt.c | 4 +- src/lib/dev.c | 87 +++----------------- src/lib/pb/irm.proto | 3 +- 4 files changed, 188 insertions(+), 125 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 #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: diff --git a/src/lib/crypt.c b/src/lib/crypt.c index c5d6101a..2f0404a2 100644 --- a/src/lib/crypt.c +++ b/src/lib/crypt.c @@ -154,8 +154,8 @@ static int __openssl_ecdh_gen_key(void ** kp) static ssize_t openssl_ecdh_pkp_create(void ** pkp, uint8_t * pk) { - uint8_t * pos; - ssize_t len; + uint8_t * pos; + ssize_t len; assert(pkp != NULL); assert(*pkp == NULL); diff --git a/src/lib/dev.c b/src/lib/dev.c index 3d45f016..d1f827f3 100644 --- a/src/lib/dev.c +++ b/src/lib/dev.c @@ -759,13 +759,8 @@ int flow_accept(qosspec_t * qs, irm_msg_t msg = IRM_MSG__INIT; irm_msg_t * recv_msg; int fd; - void * pkp; /* public key pair */ - uint8_t s[SYMMKEYSZ]; /* secret key for flow */ - uint8_t buf[MSGBUFSZ]; int err = -EIRMD; - ssize_t key_len; - - memset(s, 0, SYMMKEYSZ); + uint8_t * symmkey; msg.code = IRM_MSG_CODE__IRM_FLOW_ACCEPT; msg.has_pid = true; @@ -778,23 +773,7 @@ int flow_accept(qosspec_t * qs, msg.timeo_nsec = timeo->tv_nsec; } - key_len = crypt_dh_pkp_create(&pkp, buf); - if (key_len < 0) { - err = -ECRYPT; - goto fail_crypt_pkp; - } - if (key_len > 0) { - msg.has_pk = true; - msg.pk.data = buf; - msg.pk.len = (uint32_t) key_len; - } - - pthread_cleanup_push(crypt_dh_pkp_destroy, pkp); - recv_msg = send_recv_irm_msg(&msg); - - pthread_cleanup_pop(false); - if (recv_msg == NULL) goto fail_recv; @@ -810,17 +789,11 @@ int flow_accept(qosspec_t * qs, !recv_msg->has_mpl || recv_msg->qosspec == NULL) goto fail_msg; - if (recv_msg->pk.len != 0 && - crypt_dh_derive(pkp, recv_msg->pk.data, - recv_msg->pk.len, s) < 0) { - err = -ECRYPT; - goto fail_msg; - } - - crypt_dh_pkp_destroy(pkp); + symmkey = recv_msg->has_symmkey ? recv_msg->symmkey.data : NULL; fd = flow_init(recv_msg->flow_id, recv_msg->pid, - qos_spec_msg_to_s(recv_msg->qosspec), s, + qos_spec_msg_to_s(recv_msg->qosspec), + symmkey, recv_msg->mpl); irm_msg__free_unpacked(recv_msg, NULL); @@ -828,7 +801,6 @@ int flow_accept(qosspec_t * qs, if (fd < 0) return fd; - pthread_rwlock_rdlock(&ai.lock); if (qs != NULL) @@ -841,8 +813,6 @@ int flow_accept(qosspec_t * qs, fail_msg: irm_msg__free_unpacked(recv_msg, NULL); fail_recv: - crypt_dh_pkp_destroy(pkp); - fail_crypt_pkp: return err; } @@ -850,15 +820,10 @@ int flow_alloc(const char * dst, qosspec_t * qs, const struct timespec * timeo) { - irm_msg_t msg = IRM_MSG__INIT; - irm_msg_t * recv_msg; - int fd; - void * pkp = NULL; /* public key pair */ - uint8_t s[SYMMKEYSZ]; /* secret key for flow */ - uint8_t buf[MSGBUFSZ]; - int err = -EIRMD; - - memset(s, 0, SYMMKEYSZ); + irm_msg_t msg = IRM_MSG__INIT; + irm_msg_t * recv_msg; + int fd; + int err = -EIRMD; #ifdef QOS_DISABLE_CRC if (qs != NULL) @@ -877,25 +842,10 @@ int flow_alloc(const char * dst, msg.timeo_nsec = timeo->tv_nsec; } - if (qs != NULL && qs->cypher_s != 0) { - ssize_t key_len; - - key_len = crypt_dh_pkp_create(&pkp, buf); - if (key_len < 0) { - err = -ECRYPT; - goto fail_crypt_pkp; - } - - msg.has_pk = true; - msg.pk.data = buf; - msg.pk.len = (uint32_t) key_len; - } - recv_msg = send_recv_irm_msg(&msg); qosspec_msg__free_unpacked(msg.qosspec, NULL); - if (recv_msg == NULL) - goto fail_send; + goto fail_send_recv; if (!recv_msg->has_result) goto fail_result; @@ -909,19 +859,10 @@ int flow_alloc(const char * dst, !recv_msg->has_mpl) goto fail_result; - if (qs != NULL && qs->cypher_s != 0) { - if (!recv_msg->has_pk || recv_msg->pk.len == 0) { - err = -ECRYPT; - goto fail_result; - } - - if (crypt_dh_derive(pkp, recv_msg->pk.data, - recv_msg->pk.len, s) < 0) { + if ((qs != NULL && qs->cypher_s != 0) && + (!recv_msg->has_symmkey || recv_msg->symmkey.len != SYMMKEYSZ)) { err = -ECRYPT; goto fail_result; - } - - crypt_dh_pkp_destroy(pkp); } /* TODO: Make sure qosspec is set in msg */ @@ -929,7 +870,7 @@ int flow_alloc(const char * dst, *qs = qos_spec_msg_to_s(recv_msg->qosspec); fd = flow_init(recv_msg->flow_id, recv_msg->pid, - qs == NULL ? qos_raw : *qs, s, + qs == NULL ? qos_raw : *qs, recv_msg->symmkey.data, recv_msg->mpl); irm_msg__free_unpacked(recv_msg, NULL); @@ -938,9 +879,7 @@ int flow_alloc(const char * dst, fail_result: irm_msg__free_unpacked(recv_msg, NULL); - fail_send: - crypt_dh_pkp_destroy(pkp); - fail_crypt_pkp: + fail_send_recv: return err; } diff --git a/src/lib/pb/irm.proto b/src/lib/pb/irm.proto index 94db28a4..366e462c 100644 --- a/src/lib/pb/irm.proto +++ b/src/lib/pb/irm.proto @@ -92,5 +92,6 @@ message irm_msg { optional sint32 mpl = 19; optional string comp = 20; optional bytes pk = 21; /* piggyback */ - optional sint32 result = 22; + optional bytes symmkey = 22; + optional sint32 result = 23; } -- cgit v1.2.3