diff options
author | Dimitri Staessens <dimitri@ouroboros.rocks> | 2019-08-02 19:12:34 +0200 |
---|---|---|
committer | Sander Vrijders <sander@ouroboros.rocks> | 2019-08-03 12:10:57 +0200 |
commit | 9e8d603d14561095fb8d08871319a315d3bf6763 (patch) | |
tree | 7a87c212fcd642a8696145b4246a4fc4cf964e10 /src/lib/dev.c | |
parent | 8a37ffbf8c0776a38f2de18a63e885383960ee68 (diff) | |
download | ouroboros-9e8d603d14561095fb8d08871319a315d3bf6763.tar.gz ouroboros-9e8d603d14561095fb8d08871319a315d3bf6763.zip |
lib: Add per-message encryption with OpenSSL
This adds a per-message symmetric encryption using the OpenSSL
library. At flow allocation, an Elliptic Curve Diffie-Hellman exchange
is performed to derive a shared secret, which is then hashed using
SHA3-256 to be used as a key for symmetric AES-256 encryption. Each
message on an encrypted flow adds a small crypto header that includes
a random 128-bit Initialization Vector (IV). If the server does not
have OpenSSL enabled, the flow allocation will fail with an -ECRYPT
error.
Future optimizations are to piggyback the public keys on the flow
allocation message, and to enable per-flow encryption that maintains
the context of the encryption over multiple packets and doesn't
require sending IVs.
Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks>
Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
Diffstat (limited to 'src/lib/dev.c')
-rw-r--r-- | src/lib/dev.c | 121 |
1 files changed, 106 insertions, 15 deletions
diff --git a/src/lib/dev.c b/src/lib/dev.c index 229a1470..1e0a177d 100644 --- a/src/lib/dev.c +++ b/src/lib/dev.c @@ -29,6 +29,7 @@ #include "config.h" #include <ouroboros/hash.h> +#include <ouroboros/cacep.h> #include <ouroboros/errno.h> #include <ouroboros/dev.h> #include <ouroboros/ipcp-dev.h> @@ -59,6 +60,8 @@ #define DONE_PART -2 #define CRCLEN (sizeof(uint32_t)) +#define SECMEMSZ 16384 +#define SYMMKEYSZ 32 struct flow_set { size_t idx; @@ -98,6 +101,9 @@ struct flow { qosspec_t spec; ssize_t part_idx; + void * ctx; + uint8_t key[SYMMKEYSZ]; + pid_t pid; bool snd_timesout; @@ -237,6 +243,8 @@ static void flow_clear(int fd) ai.flows[fd].pid = -1; } +#include "crypt.c" + static void flow_fini(int fd) { assert(fd >= 0 && fd < SYS_MAX_FLOWS); @@ -266,6 +274,9 @@ static void flow_fini(int fd) if (ai.flows[fd].frcti != NULL) frcti_destroy(ai.flows[fd].frcti); + if (ai.flows[fd].spec.cypher_s > 0) + crypt_fini(&ai.flows[fd]); + flow_clear(fd); } @@ -286,15 +297,15 @@ static int flow_init(int flow_id, ai.flows[fd].rx_rb = shm_rbuff_open(ai.pid, flow_id); if (ai.flows[fd].rx_rb == NULL) - goto fail; + goto fail_rx_rb; ai.flows[fd].tx_rb = shm_rbuff_open(pid, flow_id); if (ai.flows[fd].tx_rb == NULL) - goto fail; + goto fail_tx_rb; ai.flows[fd].set = shm_flow_set_open(pid); if (ai.flows[fd].set == NULL) - goto fail; + goto fail_set; ai.flows[fd].flow_id = flow_id; ai.flows[fd].oflags = FLOWFDEFAULT; @@ -302,6 +313,9 @@ static int flow_init(int flow_id, ai.flows[fd].part_idx = NO_PART; ai.flows[fd].spec = qs; + if (qs.cypher_s > 0 && crypt_init(&ai.flows[fd]) < 0) + goto fail_crypt; + ai.ports[flow_id].fd = fd; port_set_state(&ai.ports[flow_id], PORT_ID_ASSIGNED); @@ -310,8 +324,14 @@ static int flow_init(int flow_id, return fd; - fail: - flow_fini(fd); + fail_crypt: + shm_flow_set_close(ai.flows[fd].set); + fail_set: + shm_rbuff_close(ai.flows[fd].tx_rb); + fail_tx_rb: + shm_rbuff_close(ai.flows[fd].rx_rb); + fail_rx_rb: + bmp_release(ai.fds, fd); fail_fds: pthread_rwlock_unlock(&ai.lock); return err; @@ -344,12 +364,11 @@ static void init(int argc, ai.pid = getpid(); #ifdef HAVE_LIBGCRYPT - if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) { + if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) { if (!gcry_check_version(GCRYPT_VERSION)) goto fail_fds; - /* Needs to be enabled when we add encryption. */ - gcry_control (GCRYCTL_DISABLE_SECMEM, 0); - gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + gcry_control(GCRYCTL_DISABLE_SECMEM, 0); + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); } #endif ai.fds = bmp_create(PROG_MAX_FLOWS - PROG_RES_FDS, PROG_RES_FDS); @@ -550,8 +569,8 @@ int flow_accept(qosspec_t * qs, if (ai.flows[fd].spec.in_order != 0) { ai.flows[fd].frcti = frcti_create(fd); if (ai.flows[fd].frcti == NULL) { - flow_fini(fd); pthread_rwlock_unlock(&ai.lock); + flow_dealloc(fd); return -ENOMEM; } } @@ -561,6 +580,31 @@ int flow_accept(qosspec_t * qs, pthread_rwlock_unlock(&ai.lock); + /* TODO: piggyback public keys at flow allocation. */ + if (ai.flows[fd].spec.cypher_s > 0) { + uint8_t key[SYMMKEYSZ]; + uint16_t tmp; + + pthread_rwlock_wrlock(&ai.lock); + + tmp = ai.flows[fd].spec.cypher_s; + ai.flows[fd].spec.cypher_s = 0; + + pthread_rwlock_unlock(&ai.lock); + + if (crypt_dh_srv(fd, key) < 0) { + flow_dealloc(fd); + return -ECRYPT; + } + + pthread_rwlock_wrlock(&ai.lock); + + ai.flows[fd].spec.cypher_s = tmp; + memcpy(ai.flows[fd].key, key, SYMMKEYSZ); + + pthread_rwlock_unlock(&ai.lock); + } + return fd; } @@ -579,9 +623,9 @@ static int __flow_alloc(const char * dst, qs->ber = 1; #endif if (join) - msg.code = IRM_MSG_CODE__IRM_FLOW_JOIN; + msg.code = IRM_MSG_CODE__IRM_FLOW_JOIN; else - msg.code = IRM_MSG_CODE__IRM_FLOW_ALLOC; + msg.code = IRM_MSG_CODE__IRM_FLOW_ALLOC; msg.dst = (char *) dst; msg.has_pid = true; msg.pid = ai.pid; @@ -605,7 +649,7 @@ static int __flow_alloc(const char * dst, } if (recv_msg->result != 0) { - int res = recv_msg->result; + int res = recv_msg->result; irm_msg__free_unpacked(recv_msg, NULL); return res; } @@ -630,14 +674,39 @@ static int __flow_alloc(const char * dst, if (ai.flows[fd].spec.in_order != 0) { ai.flows[fd].frcti = frcti_create(fd); if (ai.flows[fd].frcti == NULL) { - flow_fini(fd); pthread_rwlock_unlock(&ai.lock); + flow_dealloc(fd); return -ENOMEM; } } pthread_rwlock_unlock(&ai.lock); + /* TODO: piggyback public keys at flow allocation. */ + if (!join && ai.flows[fd].spec.cypher_s > 0) { + uint8_t key[SYMMKEYSZ]; + uint16_t tmp; + + pthread_rwlock_wrlock(&ai.lock); + + tmp = ai.flows[fd].spec.cypher_s; + ai.flows[fd].spec.cypher_s = 0; + + pthread_rwlock_unlock(&ai.lock); + + if (crypt_dh_clt(fd, key) < 0) { + flow_dealloc(fd); + return -ECRYPT; + } + + pthread_rwlock_wrlock(&ai.lock); + + ai.flows[fd].spec.cypher_s = tmp; + memcpy(ai.flows[fd].key, key, SYMMKEYSZ); + + pthread_rwlock_unlock(&ai.lock); + } + return fd; } @@ -931,6 +1000,15 @@ ssize_t flow_write(int fd, return -ENOMEM; } + pthread_rwlock_wrlock(&ai.lock); + if (flow->spec.cypher_s > 0) + if (crypt_encrypt(flow, sdb) < 0) { + pthread_rwlock_unlock(&ai.lock); + shm_rdrbuff_remove(ai.rdrb, idx); + return -ENOMEM; + } + pthread_rwlock_unlock(&ai.lock); + if (flow->spec.ber == 0 && add_crc(sdb) != 0) { shm_rdrbuff_remove(ai.rdrb, idx); return -ENOMEM; @@ -1009,9 +1087,22 @@ ssize_t flow_read(int fd, shm_rbuff_read_b(rb, abstime); if (idx < 0) return idx; + sdb = shm_rdrbuff_get(ai.rdrb, idx); - if (flow->spec.ber == 0 && chk_crc(sdb) != 0) + if (flow->spec.ber == 0 && chk_crc(sdb) != 0) { + shm_rdrbuff_remove(ai.rdrb, idx); continue; + } + + pthread_rwlock_wrlock(&ai.lock); + if (flow->spec.cypher_s > 0) + if (crypt_decrypt(flow, sdb) < 0) { + pthread_rwlock_unlock(&ai.lock); + shm_rdrbuff_remove(ai.rdrb, + idx); + return -ENOMEM; + } + pthread_rwlock_unlock(&ai.lock); } while (frcti_rcv(flow->frcti, sdb) != 0); } } |