summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorDimitri Staessens <dimitri@ouroboros.rocks>2019-08-02 19:12:34 +0200
committerSander Vrijders <sander@ouroboros.rocks>2019-08-03 12:10:57 +0200
commit9e8d603d14561095fb8d08871319a315d3bf6763 (patch)
tree7a87c212fcd642a8696145b4246a4fc4cf964e10 /src/lib
parent8a37ffbf8c0776a38f2de18a63e885383960ee68 (diff)
downloadouroboros-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')
-rw-r--r--src/lib/config.h.in4
-rw-r--r--src/lib/crypt.c490
-rw-r--r--src/lib/dev.c121
-rw-r--r--src/lib/qosspec.proto1
-rw-r--r--src/lib/sockets.c6
5 files changed, 605 insertions, 17 deletions
diff --git a/src/lib/config.h.in b/src/lib/config.h.in
index 3e5a7b1e..70261cab 100644
--- a/src/lib/config.h.in
+++ b/src/lib/config.h.in
@@ -24,6 +24,10 @@
#cmakedefine HAVE_LIBGCRYPT
#cmakedefine HAVE_OPENSSL
+#ifdef HAVE_OPENSSL
+#define HAVE_ENCRYPTION
+#endif
+
#define SYS_MAX_FLOWS @SYS_MAX_FLOWS@
#cmakedefine SHM_RBUFF_LOCKLESS
diff --git a/src/lib/crypt.c b/src/lib/crypt.c
new file mode 100644
index 00000000..94f1b50e
--- /dev/null
+++ b/src/lib/crypt.c
@@ -0,0 +1,490 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2019
+ *
+ * Elliptic curve Diffie-Hellman key exchange and
+ * AES encryption for flows using OpenSSL
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifdef HAVE_OPENSSL
+
+#include <openssl/evp.h>
+#include <openssl/ec.h>
+#include <openssl/pem.h>
+
+#define MSGBUFSZ 2048
+#define IVSZ 16
+#define DH_TIMEO 2 /* seconds */
+/* SYMMKEYSZ defined in dev.c */
+
+/*
+ * Derive the common secret from
+ * your public key pair (kp)
+ * the remote public key (pub).
+ * Store it in a preallocated buffer (s).
+ */
+static int __openssl_ecdh_derive_secret(EVP_PKEY * kp,
+ EVP_PKEY * pub,
+ uint8_t * s)
+{
+ EVP_PKEY_CTX * ctx;
+ int ret;
+ uint8_t * secret;
+ size_t secret_len;
+
+ ctx = EVP_PKEY_CTX_new(kp, NULL);
+ if (ctx == NULL)
+ goto fail_new;
+
+ ret = EVP_PKEY_derive_init(ctx);
+ if (ret != 1)
+ goto fail_ctx;
+
+ ret = EVP_PKEY_derive_set_peer(ctx, pub);
+ if (ret != 1)
+ goto fail_ctx;
+
+ ret = EVP_PKEY_derive(ctx, NULL, &secret_len);
+ if (ret != 1)
+ goto fail_ctx;
+
+ if (secret_len < SYMMKEYSZ)
+ goto fail_ctx;
+
+ secret = OPENSSL_malloc(secret_len);
+ if (secret == NULL)
+ goto fail_ctx;
+
+ ret = EVP_PKEY_derive(ctx, secret, &secret_len);
+ if (ret != 1)
+ goto fail_derive;
+
+ /* Hash the secret for use as AES key. */
+ mem_hash(HASH_SHA3_256, s, secret, secret_len);
+
+ OPENSSL_free(secret);
+ EVP_PKEY_CTX_free(ctx);
+
+ return 0;
+
+ fail_derive:
+ OPENSSL_free(s);
+ fail_ctx:
+ EVP_PKEY_CTX_free(ctx);
+ fail_new:
+ return -ECRYPT;
+}
+
+static int __openssl_ecdh_gen_key(EVP_PKEY ** kp)
+{
+ EVP_PKEY_CTX * ctx = NULL;
+ EVP_PKEY_CTX * kctx = NULL;
+ EVP_PKEY * params = NULL;
+ int ret;
+
+ ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+ if (ctx == NULL)
+ goto fail_new_id;
+
+ ret = EVP_PKEY_paramgen_init(ctx);
+ if (ret != 1)
+ goto fail_paramgen;
+
+ ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, NID_X9_62_prime256v1);
+ if (ret != 1)
+ goto fail_paramgen;
+
+ ret = EVP_PKEY_paramgen(ctx, &params);
+ if (ret != 1)
+ goto fail_paramgen;
+
+ kctx = EVP_PKEY_CTX_new(params, NULL);
+ if (kctx == NULL)
+ goto fail_keygen_init;
+
+ ret = EVP_PKEY_keygen_init(kctx);
+ if (ret != 1)
+ goto fail_keygen;
+
+ ret = EVP_PKEY_keygen(kctx, kp);
+ if (ret != 1)
+ goto fail_keygen;
+
+ EVP_PKEY_free(params);
+ EVP_PKEY_CTX_free(kctx);
+ EVP_PKEY_CTX_free(ctx);
+
+ return 0;
+
+ fail_keygen:
+ EVP_PKEY_CTX_free(kctx);
+ fail_keygen_init:
+ EVP_PKEY_free(params);
+ fail_paramgen:
+ EVP_PKEY_CTX_free(ctx);
+ fail_new_id:
+ return -ECRYPT;
+}
+
+/* ECDH from the server side. */
+static int openssl_ecdh_srv(int fd,
+ uint8_t * s)
+{
+ EVP_PKEY * kp = NULL;
+ EVP_PKEY * pub = NULL;
+ uint8_t buf[MSGBUFSZ];
+ ssize_t len;
+ int buf_sz;
+ uint8_t * pos;
+ struct timespec timeo = {DH_TIMEO,0};
+
+ assert(s != NULL);
+
+ (void) fd;
+ (void) s;
+
+ if (__openssl_ecdh_gen_key(&kp) < 0)
+ goto fail_gen_key;
+
+ fccntl(fd, FLOWSRCVTIMEO, &timeo);
+
+ len = flow_read(fd, buf, MSGBUFSZ);
+ if (len < 0) {
+ fccntl(fd, FLOWSRCVTIMEO, NULL);
+ goto fail_get_key;
+ }
+
+ fccntl(fd, FLOWSRCVTIMEO, NULL);
+
+ pos = buf; /* i2d_PUBKEY increments the pointer, don't use buf! */
+ pub = d2i_PUBKEY(NULL, (const uint8_t **) &pos, (long) len);
+
+ pos = buf; /* i2d_PUBKEY increments the pointer, don't use buf! */
+ buf_sz = i2d_PUBKEY(kp, &pos);
+ if (buf_sz < 0)
+ goto fail_get_key;
+
+ if (flow_write(fd, buf, (size_t) buf_sz) < 0)
+ goto fail_get_key;
+
+ if (__openssl_ecdh_derive_secret(kp, pub, s) < 0)
+ goto fail_get_key;
+
+ EVP_PKEY_free(kp);
+ EVP_PKEY_free(pub);
+
+ return 0;
+
+ fail_get_key:
+ EVP_PKEY_free(kp);
+ fail_gen_key:
+ return -ECRYPT;
+}
+
+/* ECDH from the client side. */
+static int openssl_ecdh_clt(int fd,
+ uint8_t * s)
+{
+ EVP_PKEY * kp = NULL;
+ EVP_PKEY * pub = NULL;
+ uint8_t buf[MSGBUFSZ];
+ int buf_sz;
+ uint8_t * pos;
+ ssize_t len;
+ struct timespec timeo = {DH_TIMEO,0};
+
+ assert(s != NULL);
+
+ (void) fd;
+ (void) s;
+
+ if (__openssl_ecdh_gen_key(&kp) < 0)
+ goto fail_gen_key;
+
+ pos = buf; /* i2d_PUBKEY increments the pointer, don't use buf! */
+ buf_sz = i2d_PUBKEY(kp, &pos);
+ if (buf_sz < 0)
+ goto fail_get_key;
+
+ if (flow_write(fd, buf, (size_t) buf_sz) < 0)
+ goto fail_get_key;
+
+ fccntl(fd, FLOWSRCVTIMEO, &timeo);
+
+ len = flow_read(fd, buf, MSGBUFSZ);
+ if (len < 0) {
+ fccntl(fd, FLOWSRCVTIMEO, NULL);
+ goto fail_get_key;
+ }
+
+ fccntl(fd, FLOWSRCVTIMEO, NULL);
+
+ pos = buf; /* i2d_PUBKEY increments the pointer, don't use buf! */
+ pub = d2i_PUBKEY(NULL, (const uint8_t **) &pos, (long) len);
+
+ if (__openssl_ecdh_derive_secret(kp, pub, s) < 0)
+ goto fail_get_key;
+
+ EVP_PKEY_free(kp);
+ EVP_PKEY_free(pub);
+
+ return 0;
+
+ fail_get_key:
+ EVP_PKEY_free(kp);
+ fail_gen_key:
+ return -ECRYPT;
+}
+
+/*
+ * AES encryption calls. If FRCT is disabled, we should generate a
+ * 128-bit random IV and append it to the packet. If the flow is
+ * reliable, we could initialize the context once, and consider the
+ * stream a single encrypted message to avoid initializing the
+ * encryption context for each packet.
+ */
+
+static int openssl_encrypt(struct flow * f,
+ struct shm_du_buff * sdb)
+{
+ uint8_t * out;
+ uint8_t * in;
+ uint8_t * head;
+ uint8_t iv[IVSZ];
+ int in_sz;
+ int out_sz;
+ int tmp_sz;
+ int ret;
+
+ in = shm_du_buff_head(sdb);
+ in_sz = shm_du_buff_tail(sdb) - in;
+
+ if (random_buffer(iv, IVSZ) < 0)
+ goto fail_iv;
+
+ out = malloc(in_sz + EVP_MAX_BLOCK_LENGTH);
+ if (out == NULL)
+ goto fail_iv;
+
+ EVP_CIPHER_CTX_reset(f->ctx);
+
+ ret = EVP_EncryptInit_ex(f->ctx,
+ EVP_aes_256_cbc(),
+ NULL,
+ f->key,
+ iv);
+ if (ret != 1)
+ goto fail_encrypt_init;
+
+ ret = EVP_EncryptUpdate(f->ctx, out, &tmp_sz, in, in_sz);
+ if (ret != 1)
+ goto fail_encrypt;
+
+ out_sz = tmp_sz;
+ ret = EVP_EncryptFinal_ex(f->ctx, out + tmp_sz, &tmp_sz);
+ if (ret != 1)
+ goto fail_encrypt;
+
+ out_sz += tmp_sz;
+
+ EVP_CIPHER_CTX_cleanup(f->ctx);
+
+ assert(out_sz >= in_sz);
+
+ head = shm_du_buff_head_alloc(sdb, IVSZ);
+ if (head == NULL)
+ goto fail_encrypt;
+
+ if (shm_du_buff_tail_alloc(sdb, out_sz - in_sz) == NULL)
+ goto fail_tail_alloc;
+
+ memcpy(head, iv, IVSZ);
+ memcpy(in, out, out_sz);
+
+ free(out);
+
+ return 0;
+
+ fail_tail_alloc:
+ shm_du_buff_head_release(sdb, IVSZ);
+ fail_encrypt:
+ EVP_CIPHER_CTX_cleanup(f->ctx);
+ fail_encrypt_init:
+ free(out);
+ fail_iv:
+ return -ECRYPT;
+}
+
+static int openssl_decrypt(struct flow * f,
+ struct shm_du_buff * sdb)
+{
+ uint8_t * in;
+ uint8_t * out;
+ uint8_t iv[IVSZ];
+ int ret;
+ int out_sz;
+ int in_sz;
+ int tmp_sz;
+
+ in = shm_du_buff_head_release(sdb, IVSZ);
+
+ memcpy(iv, in, IVSZ);
+
+ in = shm_du_buff_head(sdb);
+
+ in_sz = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb);
+
+ out = malloc(in_sz);
+ if (out == NULL)
+ goto fail_malloc;
+
+ EVP_CIPHER_CTX_reset(f->ctx);
+
+ ret = EVP_DecryptInit_ex(f->ctx,
+ EVP_aes_256_cbc(),
+ NULL,
+ f->key,
+ iv);
+ if (ret != 1)
+ goto fail_decrypt_init;
+
+ ret = EVP_DecryptUpdate(f->ctx, out, &tmp_sz, in, in_sz);
+ if (ret != 1)
+ goto fail_decrypt;
+
+ out_sz = tmp_sz;
+
+ ret = EVP_DecryptFinal_ex(f->ctx, out + tmp_sz, &tmp_sz);
+ if (ret != 1)
+ goto fail_decrypt;
+
+ out_sz += tmp_sz;
+
+ assert(out_sz <= in_sz);
+
+ shm_du_buff_tail_release(sdb, in_sz - out_sz);
+
+ memcpy(in, out, out_sz);
+
+ free(out);
+
+ return 0;
+
+ fail_decrypt:
+ EVP_CIPHER_CTX_cleanup(f->ctx);
+ fail_decrypt_init:
+ free(out);
+ fail_malloc:
+ return -ECRYPT;
+
+}
+
+static int openssl_crypt_init(struct flow * f)
+{
+ f->ctx = EVP_CIPHER_CTX_new();
+ if (f->ctx == NULL)
+ goto fail_new;
+
+ return 0;
+
+ fail_new:
+ return -ECRYPT;
+}
+
+static void openssl_crypt_fini(struct flow * f)
+{
+ EVP_CIPHER_CTX_free(f->ctx);
+ f->ctx = NULL;
+}
+
+#endif /* HAVE_OPENSSL */
+
+static int crypt_dh_srv(int fd,
+ uint8_t * s)
+{
+#ifdef HAVE_OPENSSL
+ return openssl_ecdh_clt(fd, s);
+#else
+ (void) fd;
+
+ memset(s, 0, SYMMKEYSZ);
+
+ return -ECRYPT;
+#endif
+}
+
+static int crypt_dh_clt(int fd,
+ uint8_t * s)
+{
+#ifdef HAVE_OPENSSL
+ return openssl_ecdh_srv(fd, s);
+#else
+ (void) fd;
+
+ memset(s, 0, SYMMKEYSZ);
+
+ return 0;
+#endif
+}
+
+static int crypt_encrypt(struct flow * f,
+ struct shm_du_buff * sdb)
+{
+#ifdef HAVE_OPENSSL
+ return openssl_encrypt(f, sdb);
+#else
+ (void) f;
+ (void) sdb;
+
+ return 0;
+#endif
+}
+
+static int crypt_decrypt(struct flow * f,
+ struct shm_du_buff * sdb)
+{
+#ifdef HAVE_OPENSSL
+ return openssl_decrypt(f, sdb);
+#else
+ (void) f;
+ (void) sdb;
+
+ return 0;
+#endif
+}
+
+
+static int crypt_init(struct flow * f)
+{
+#ifdef HAVE_OPENSSL
+ return openssl_crypt_init(f);
+#else
+ (void) f;
+
+ return 0;
+#endif
+}
+
+static void crypt_fini(struct flow * f)
+{
+#ifdef HAVE_OPENSSL
+ openssl_crypt_fini(f);
+#else
+ (void) f;
+#endif
+}
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);
}
}
diff --git a/src/lib/qosspec.proto b/src/lib/qosspec.proto
index c9e5a6e6..0cbcd41a 100644
--- a/src/lib/qosspec.proto
+++ b/src/lib/qosspec.proto
@@ -30,4 +30,5 @@ message qosspec_msg {
required uint32 ber = 5; /* Bit error rate, ppb */
required uint32 in_order = 6; /* In-order delivery */
required uint32 max_gap = 7; /* In ms */
+ required uint32 cypher_s = 8; /* Crypto strength in bits */
};
diff --git a/src/lib/sockets.c b/src/lib/sockets.c
index b08bae8e..347e9244 100644
--- a/src/lib/sockets.c
+++ b/src/lib/sockets.c
@@ -166,7 +166,7 @@ char * ipcp_sock_path(pid_t pid)
return full_name;
}
-qosspec_msg_t spec_to_msg(qosspec_t * qs)
+qosspec_msg_t spec_to_msg(const qosspec_t * qs)
{
qosspec_t spec;
qosspec_msg_t msg = QOSSPEC_MSG__INIT;
@@ -180,11 +180,12 @@ qosspec_msg_t spec_to_msg(qosspec_t * qs)
msg.ber = spec.ber;
msg.in_order = spec.in_order;
msg.max_gap = spec.max_gap;
+ msg.cypher_s = spec.cypher_s;
return msg;
}
-qosspec_t msg_to_spec(qosspec_msg_t * msg)
+qosspec_t msg_to_spec(const qosspec_msg_t * msg)
{
qosspec_t spec;
@@ -197,6 +198,7 @@ qosspec_t msg_to_spec(qosspec_msg_t * msg)
spec.ber = msg->ber;
spec.in_order = msg->in_order;
spec.max_gap = msg->max_gap;
+ spec.cypher_s = msg->cypher_s;
return spec;
}