summaryrefslogtreecommitdiff
path: root/src/irmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/irmd')
-rw-r--r--src/irmd/CMakeLists.txt4
-rw-r--r--src/irmd/config.h.in1
-rw-r--r--src/irmd/ipcp.c2
-rw-r--r--src/irmd/main.c244
-rw-r--r--src/irmd/oap.c220
-rw-r--r--src/irmd/oap.h88
-rw-r--r--src/irmd/reg/reg.c13
-rw-r--r--src/irmd/reg/reg.h3
-rw-r--r--src/irmd/reg/tests/reg_test.c37
-rw-r--r--src/irmd/tests/CMakeLists.txt4
-rw-r--r--src/irmd/tests/irm_test.c33
-rw-r--r--src/irmd/tests/oap_test.c273
12 files changed, 795 insertions, 127 deletions
diff --git a/src/irmd/CMakeLists.txt b/src/irmd/CMakeLists.txt
index c7e4cbd9..fce89bef 100644
--- a/src/irmd/CMakeLists.txt
+++ b/src/irmd/CMakeLists.txt
@@ -71,6 +71,7 @@ set(SOURCE_FILES
ipcp.c
configfile.c
main.c
+ oap.c
reg/flow.c
reg/ipcp.c
reg/proc.c
@@ -95,6 +96,5 @@ endif ()
install(TARGETS irmd RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR})
-# Enable once irmd has tests
-#add_subdirectory(tests)
add_subdirectory(reg)
+add_subdirectory(tests)
diff --git a/src/irmd/config.h.in b/src/irmd/config.h.in
index fa1156b9..aa37b0ac 100644
--- a/src/irmd/config.h.in
+++ b/src/irmd/config.h.in
@@ -66,6 +66,7 @@
#cmakedefine IRMD_KILL_ALL_PROCESSES
#cmakedefine HAVE_LIBGCRYPT
+#cmakedefine HAVE_OPENSSL
#define O7S_ASCII_ART \
"\n" \
diff --git a/src/irmd/ipcp.c b/src/irmd/ipcp.c
index 28f870a7..8a42be42 100644
--- a/src/irmd/ipcp.c
+++ b/src/irmd/ipcp.c
@@ -170,7 +170,7 @@ ipcp_msg_t * send_recv_ipcp_msg(pid_t pid,
recv_msg = ipcp_msg__unpack(NULL, len, buf);
else {
if (errno == EAGAIN && !dealloc) {
- int diff = ts_diff_ms(&tic, &toc);
+ int diff = ts_diff_ms(&toc, &tic);
log_warn("IPCP %s timed out after %d ms.",
str_ipcp_cmd(msg->code), diff);
}
diff --git a/src/irmd/main.c b/src/irmd/main.c
index cf079698..5cda9559 100644
--- a/src/irmd/main.c
+++ b/src/irmd/main.c
@@ -40,6 +40,7 @@
#include <ouroboros/lockfile.h>
#include <ouroboros/logs.h>
#include <ouroboros/pthread.h>
+#include <ouroboros/random.h>
#include <ouroboros/rib.h>
#include <ouroboros/shm_rdrbuff.h>
#include <ouroboros/sockets.h>
@@ -50,6 +51,7 @@
#include "irmd.h"
#include "ipcp.h"
+#include "oap.h"
#include "reg/reg.h"
#include "configfile.h"
@@ -760,66 +762,46 @@ static void __cleanup_flow(void * flow)
}
static int flow_accept(struct flow_info * flow,
+ buffer_t * symmkey,
buffer_t * data,
struct timespec * abstime)
{
- uint8_t buf[MSGBUFSZ];
- buffer_t lpk; /* local public key */
- buffer_t rpk; /* remote public key */
- void * pkp; /* my public/private key pair */
- ssize_t key_len;
- uint8_t * s;
- int err;
+ struct oap_hdr oap_hdr; /* incoming request */
+ struct oap_hdr r_oap_hdr; /* outgoing response */
+ uint8_t buf[MSGBUFSZ]; /* buffer for local ephkey */
+ buffer_t lpk = BUF_INIT; /* local ephemeral pubkey */
+ int err;
+ struct timespec now;
/* piggyback of user data not yet implemented */
assert(data != NULL && data->len == 0 && data->data == NULL);
+ assert(symmkey != NULL && symmkey->len == 0 && symmkey->data == NULL);
if (!reg_has_proc(flow->n_pid)) {
log_err("Unknown process %d calling accept.", flow->n_pid);
err = -EINVAL;
- goto fail;
- }
-
- s = malloc(SYMMKEYSZ);
- if (s == NULL) {
- log_err("Failed to malloc symmkey.");
- err = -ENOMEM;
- goto fail;
- }
-
- key_len = crypt_dh_pkp_create(&pkp, buf);
- if (key_len < 0) {
- log_err("Failed to generate key pair.");
- err = -ECRYPT;
- goto fail_pkp;
+ goto fail_flow;
}
- lpk.data = buf;
- lpk.len = (size_t) key_len;
-
- log_dbg("Generated ephemeral keys for %d.", flow->n_pid);
-
if (reg_create_flow(flow) < 0) {
log_err("Failed to create flow.");
err = -EBADF;
goto fail_flow;
}
- if (reg_prepare_flow_accept(flow, &lpk) < 0) {
+ if (reg_prepare_flow_accept(flow) < 0) {
log_err("Failed to prepare accept.");
err = -EBADF;
goto fail_wait;
}
+ log_dbg("Waiting for flow accept %d.", flow->id);
+
pthread_cleanup_push(__cleanup_flow, flow);
- pthread_cleanup_push(__cleanup_pkp, pkp);
- pthread_cleanup_push(free, s);
- err = reg_wait_flow_accepted(flow, &rpk, abstime);
+ err = reg_wait_flow_accepted(flow, &oap_hdr.hdr, abstime);
pthread_cleanup_pop(false);
- pthread_cleanup_pop(false);
- pthread_cleanup_pop(false);
if (err == -ETIMEDOUT) {
log_err("Flow accept timed out.");
@@ -834,45 +816,96 @@ static int flow_accept(struct flow_info * flow,
assert(err == 0);
- if (flow->qs.cypher_s != 0) { /* crypto requested */
- if (crypt_dh_derive(pkp, rpk, s) < 0) {
+ if (oap_hdr_decode(oap_hdr.hdr, &oap_hdr) < 0) {
+ log_err("Failed to decode OAP header.");
+ err = -EIPCP;
+ goto fail_oap_hdr;
+ }
+
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ if (now.tv_sec - (time_t) (oap_hdr.timestamp / MILLION) > flow->mpl)
+ log_warn("Flow alloc time exceeds MPL by %zu ms.",
+ now.tv_sec - oap_hdr.timestamp / MILLION);
+
+ if (flow->qs.cypher_s != 0) { /* crypto requested */
+ uint8_t * s; /* symmetric encryption key */
+ ssize_t key_len; /* length of local pubkey */
+ void * pkp = NULL; /* ephemeral private key pair */
+
+ s = malloc(SYMMKEYSZ);
+ if (s == NULL) {
+ log_err("Failed to malloc symmkey.");
+ err = -ENOMEM;
+ goto fail_keys;
+ }
+
+ key_len = crypt_dh_pkp_create(&pkp, buf);
+ if (key_len < 0) {
+ free(s);
+ log_err("Failed to generate key pair.");
+ err = -ECRYPT;
+ goto fail_keys;
+ }
+
+ lpk.data = buf;
+ lpk.len = (size_t) key_len;
+
+ log_dbg("Generated ephemeral keys for %d.", flow->n_pid);
+
+ if (crypt_dh_derive(pkp, oap_hdr.eph, s) < 0) {
log_err("Failed to derive secret for %d.", flow->id);
+ crypt_dh_pkp_destroy(pkp);
+ free(s);
err = -ECRYPT;
goto fail_derive;
}
- freebuf(rpk);
- data->data = s;
- data->len = SYMMKEYSZ;
- s= NULL;
- } else {
- clrbuf(lpk);
+
+ symmkey->data = s;
+ symmkey->len = SYMMKEYSZ;
+
+ crypt_dh_pkp_destroy(pkp);
+ }
+
+ if (oap_hdr_init(oap_hdr.id, NULL, NULL, lpk, *data, &r_oap_hdr) < 0) {
+ log_err("Failed to create OAP header.");
+ err = -ENOMEM;
+ goto fail_r_oap_hdr;
}
- if (ipcp_flow_alloc_resp(flow, 0, lpk) < 0) {
+ if (ipcp_flow_alloc_resp(flow, 0, r_oap_hdr.hdr) < 0) {
log_err("Failed to respond to flow allocation.");
- err = -EIPCP;
- goto fail_alloc_resp;
+ goto fail_resp;
}
- crypt_dh_pkp_destroy(pkp);
- free(s);
+ oap_hdr_fini(&oap_hdr);
+ oap_hdr_fini(&r_oap_hdr);
return 0;
+ fail_r_oap_hdr:
+ freebuf(*symmkey);
fail_derive:
- freebuf(rpk);
clrbuf(lpk);
+ fail_keys:
+ oap_hdr_fini(&oap_hdr);
+ fail_oap_hdr:
+ assert(lpk.data == NULL && lpk.len == 0);
ipcp_flow_alloc_resp(flow, err, lpk);
- fail_alloc_resp:
- flow->state = FLOW_NULL;
fail_wait:
reg_destroy_flow(flow->id);
fail_flow:
- crypt_dh_pkp_destroy(pkp);
- fail_pkp:
- free(s);
- fail:
return err;
+
+ fail_resp:
+ flow->state = FLOW_NULL;
+ oap_hdr_fini(&r_oap_hdr);
+ freebuf(*symmkey);
+ clrbuf(lpk);
+ oap_hdr_fini(&oap_hdr);
+ assert(lpk.data == NULL && lpk.len == 0);
+ reg_destroy_flow(flow->id);
+ return -EIPCP;
}
static int flow_join(struct flow_info * flow,
@@ -910,6 +943,7 @@ static int flow_join(struct flow_info * flow,
reg_prepare_flow_alloc(flow);
+
if (ipcp_flow_join(flow, hash)) {
log_err("Flow join with layer %s failed.", dst);
err = -ENOTALLOC;
@@ -935,6 +969,7 @@ static int flow_join(struct flow_info * flow,
goto fail_alloc;
}
+ assert(pbuf.data == NULL && pbuf.len == 0);
assert(err == 0);
freebuf(hash);
@@ -1008,20 +1043,33 @@ static int get_ipcp_by_dst(const char * dst,
static int flow_alloc(struct flow_info * flow,
const char * dst,
+ buffer_t * symmkey,
buffer_t * data,
struct timespec * abstime)
{
- uint8_t buf[MSGBUFSZ];
- buffer_t lpk ={NULL, 0}; /* local public key */
- buffer_t rpk; /* remote public key */
- void * pkp = NULL; /* my public/private key pair */
- uint8_t * s = NULL;
- buffer_t hash;
- int err;
+ struct oap_hdr oap_hdr; /* outgoing request */
+ struct oap_hdr r_oap_hdr; /* incoming response */
+ uint8_t buf[MSGBUFSZ]; /* buffer for local ephkey */
+ buffer_t lpk = BUF_INIT; /* local ephemeral pubkey */
+ void * pkp = NULL; /* ephemeral private key pair */
+ uint8_t * s = NULL; /* symmetric key */
+ buffer_t hash;
+ uint8_t idbuf[OAP_ID_SIZE];
+ buffer_t id;
+ int err;
+
/* piggyback of user data not yet implemented */
assert(data != NULL && data->len == 0 && data->data == NULL);
+ assert(symmkey != NULL && symmkey->len == 0 && symmkey->data == NULL);
- log_info("Allocating flow for %d to %s.", flow->n_pid, dst);
+ if (random_buffer(idbuf, OAP_ID_SIZE) < 0) {
+ log_err("Failed to generate ID.");
+ err = -EIRMD;
+ goto fail_id;
+ }
+
+ id.data = idbuf;
+ id.len = OAP_ID_SIZE;
if (flow->qs.cypher_s > 0) {
ssize_t key_len;
@@ -1046,6 +1094,14 @@ static int flow_alloc(struct flow_info * flow,
log_dbg("Generated ephemeral keys for %d.", flow->n_pid);
}
+ if (oap_hdr_init(id, NULL, NULL, lpk, *data, &oap_hdr) < 0) {
+ log_err("Failed to create OAP header.");
+ err = -ENOMEM;
+ goto fail_oap_hdr;
+ }
+
+ log_info("Allocating flow for %d to %s.", flow->n_pid, dst);
+
if (reg_create_flow(flow) < 0) {
log_err("Failed to create flow.");
err = -EBADF;
@@ -1060,7 +1116,7 @@ static int flow_alloc(struct flow_info * flow,
reg_prepare_flow_alloc(flow);
- if (ipcp_flow_alloc(flow, hash, lpk)) {
+ if (ipcp_flow_alloc(flow, hash, oap_hdr.hdr)) {
log_err("Flow allocation %d failed.", flow->id);
err = -ENOTALLOC;
goto fail_alloc;
@@ -1071,7 +1127,7 @@ static int flow_alloc(struct flow_info * flow,
pthread_cleanup_push(free, hash.data);
pthread_cleanup_push(free, s);
- err = reg_wait_flow_allocated(flow, &rpk, abstime);
+ err = reg_wait_flow_allocated(flow, &r_oap_hdr.hdr, abstime);
pthread_cleanup_pop(false);
pthread_cleanup_pop(false);
@@ -1091,37 +1147,57 @@ static int flow_alloc(struct flow_info * flow,
assert(err == 0);
+ if (oap_hdr_decode(r_oap_hdr.hdr, &r_oap_hdr) < 0) {
+ log_err("Failed to decode OAP header.");
+ err = -EIPCP;
+ goto fail_r_oap_hdr;
+ }
+
+ if (memcmp(r_oap_hdr.id.data, oap_hdr.id.data, r_oap_hdr.id.len) != 0) {
+ log_err("OAP ID mismatch in flow allocation.");
+ err = -EIPCP;
+ goto fail_r_oap_hdr;
+ }
+
if (flow->qs.cypher_s != 0) { /* crypto requested */
- if (crypt_dh_derive(pkp, rpk, s) < 0) {
+ if (crypt_dh_derive(pkp, r_oap_hdr.eph, s) < 0) {
log_err("Failed to derive secret for %d.", flow->id);
err = -ECRYPT;
- goto fail_derive;
+ goto fail_r_oap_hdr;
}
crypt_dh_pkp_destroy(pkp);
- freebuf(rpk);
- data->data = s;
- data->len = SYMMKEYSZ;
+
+ symmkey->data = s;
+ symmkey->len = SYMMKEYSZ;
s = NULL;
}
+ oap_hdr_fini(&r_oap_hdr);
+ oap_hdr_fini(&oap_hdr);
+
+ /* TODO: piggyback user data if needed */
+
freebuf(hash);
free(s);
return 0;
- fail_derive:
- freebuf(rpk);
+ fail_r_oap_hdr:
flow->state = FLOW_DEALLOCATED;
+ oap_hdr_fini(&r_oap_hdr);
fail_alloc:
freebuf(hash);
fail_ipcp:
reg_destroy_flow(flow->id);
fail_flow:
- if (flow->qs.cypher_s > 0)
- crypt_dh_pkp_destroy(pkp);
+ oap_hdr_fini(&oap_hdr);
+ fail_oap_hdr:
+ crypt_dh_pkp_destroy(pkp);
fail_pkp:
free(s);
fail_malloc:
+ clrbuf(id);
+ fail_id:
return err;
}
@@ -1325,6 +1401,7 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
int res;
irm_msg_t * ret_msg;
buffer_t data;
+ buffer_t symmkey = BUF_INIT;;
memset(&flow, 0, sizeof(flow));
@@ -1421,17 +1498,21 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
res = name_unreg(msg->name, msg->pid);
break;
case IRM_MSG_CODE__IRM_FLOW_ACCEPT:
+ tpm_wait_work(irmd.tpm);
data.len = msg->pk.len;
data.data = msg->pk.data;
msg->has_pk = false;
assert(data.len > 0 ? data.data != NULL : data.data == NULL);
flow = flow_info_msg_to_s(msg->flow_info);
- res = flow_accept(&flow, &data, abstime);
+ res = flow_accept(&flow, &symmkey, &data, abstime);
if (res == 0) {
ret_msg->flow_info = flow_info_s_to_msg(&flow);
- ret_msg->has_symmkey = data.len != 0;
- ret_msg->symmkey.data = data.data;
- ret_msg->symmkey.len = data.len;
+ ret_msg->has_symmkey = symmkey.len != 0;
+ ret_msg->symmkey.data = symmkey.data;
+ ret_msg->symmkey.len = symmkey.len;
+ ret_msg->has_pk = data.len != 0;
+ ret_msg->pk.data = data.data;
+ ret_msg->pk.len = data.len;
}
break;
case IRM_MSG_CODE__IRM_FLOW_ALLOC:
@@ -1441,12 +1522,15 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
assert(data.len > 0 ? data.data != NULL : data.data == NULL);
flow = flow_info_msg_to_s(msg->flow_info);
abstime = abstime == NULL ? &max : abstime;
- res = flow_alloc(&flow, msg->dst, &data, abstime);
+ res = flow_alloc(&flow, msg->dst, &symmkey, &data, abstime);
if (res == 0) {
ret_msg->flow_info = flow_info_s_to_msg(&flow);
- ret_msg->has_symmkey = data.len != 0;
- ret_msg->symmkey.data = data.data;
- ret_msg->symmkey.len = data.len;
+ ret_msg->has_symmkey = symmkey.len != 0;
+ ret_msg->symmkey.data = symmkey.data;
+ ret_msg->symmkey.len = symmkey.len;
+ ret_msg->has_pk = data.len != 0;
+ ret_msg->pk.data = data.data;
+ ret_msg->pk.len = data.len;
}
break;
case IRM_MSG_CODE__IRM_FLOW_JOIN:
diff --git a/src/irmd/oap.c b/src/irmd/oap.c
new file mode 100644
index 00000000..d5e5b7cc
--- /dev/null
+++ b/src/irmd/oap.c
@@ -0,0 +1,220 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Ouroboros flow allocation protocol header
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#if defined(__linux__) || defined(__CYGWIN__)
+ #define _DEFAULT_SOURCE
+#else
+ #define _POSIX_C_SOURCE 200809L
+#endif
+
+#include <ouroboros/crypt.h>
+#include <ouroboros/endian.h>
+#include <ouroboros/time.h>
+
+#include "oap.h"
+
+#include <assert.h>
+
+int oap_hdr_init(buffer_t id,
+ void * pkp,
+ void * pubcrt,
+ buffer_t ephkey,
+ buffer_t data,
+ struct oap_hdr * oap_hdr)
+{
+ struct timespec now;
+ uint64_t stamp;
+ buffer_t hdr;
+ buffer_t der = BUF_INIT;
+ buffer_t sig = BUF_INIT;
+ buffer_t sign;
+ uint16_t len;
+ off_t offset;
+
+ assert(id.data != NULL && id.len == OAP_ID_SIZE);
+ assert(oap_hdr != NULL);
+ memset(oap_hdr, 0, sizeof(*oap_hdr));
+
+ clock_gettime(CLOCK_REALTIME, &now);
+ stamp = hton64(TS_TO_UINT64(now));
+
+ if (pubcrt != NULL && crypt_crt_der(pubcrt, &der) < 0)
+ goto fail_der;
+
+ hdr.len = id.len +
+ sizeof(stamp) +
+ sizeof(len) + der.len +
+ sizeof(len) + ephkey.len +
+ sizeof(len) + data.len +
+ sizeof(len); /* sig len */
+
+ hdr.data = malloc(hdr.len);
+ if (hdr.data == NULL)
+ goto fail_hdr;
+
+ offset = 0;
+
+ memcpy(hdr.data, id.data, id.len);
+ offset += id.len;
+
+ memcpy(hdr.data + offset, &stamp, sizeof(stamp));
+ offset += sizeof(stamp);
+
+ /* pubcrt */
+ len = hton16((uint16_t) der.len);
+ memcpy(hdr.data + offset, &len, sizeof(len));
+ offset += sizeof(len);
+ if (der.len != 0)
+ memcpy(hdr.data + offset, der.data, der.len);
+ offset += der.len;
+
+ /* ephkey */
+ len = hton16((uint16_t) ephkey.len);
+ memcpy(hdr.data + offset, &len, sizeof(len));
+ offset += sizeof(len);
+ if (ephkey.len != 0)
+ memcpy(hdr.data + offset, ephkey.data, ephkey.len);
+ offset += ephkey.len;
+
+ /* data */
+ len = hton16((uint16_t) data.len);
+ memcpy(hdr.data + offset, &len, sizeof(len));
+ offset += sizeof(len);
+ if (data.len != 0)
+ memcpy(hdr.data + offset, data.data, data.len);
+ offset += data.len;
+
+ sign.data = hdr.data;
+ sign.len = hdr.len - sizeof(len);
+
+ if (pkp != NULL && auth_sign(pkp, sign, &sig) < 0)
+ goto fail_sig;
+
+ len = hton16((uint16_t) sig.len);
+ memcpy(hdr.data + offset, &len, sizeof(len));
+ offset += sizeof(len);
+
+ oap_hdr->hdr = hdr;
+
+ assert((size_t) offset == hdr.len);
+
+ if (sig.len > 0) {
+ oap_hdr->hdr.len += sig.len;
+ oap_hdr->hdr.data = realloc(hdr.data, oap_hdr->hdr.len);
+ if (oap_hdr->hdr.data == NULL)
+ goto fail_oap_hdr;
+
+ memcpy(oap_hdr->hdr.data + offset, sig.data, sig.len);
+ clrbuf(hdr);
+ }
+
+ if (oap_hdr_decode(oap_hdr->hdr, oap_hdr) < 0)
+ goto fail_decode;
+
+ freebuf(der);
+ freebuf(sig);
+
+ return 0;
+
+ fail_decode:
+ oap_hdr_fini(oap_hdr);
+ fail_oap_hdr:
+ freebuf(sig);
+ fail_sig:
+ freebuf(hdr);
+ fail_hdr:
+ freebuf(der);
+ fail_der:
+ memset(oap_hdr, 0, sizeof(*oap_hdr));
+ return -1;
+}
+
+void oap_hdr_fini(struct oap_hdr * oap_hdr)
+{
+ assert(oap_hdr != NULL);
+
+ freebuf(oap_hdr->hdr);
+ memset(oap_hdr, 0, sizeof(*oap_hdr));
+}
+
+int oap_hdr_decode(buffer_t hdr,
+ struct oap_hdr * oap_hdr)
+{
+ off_t offset;
+
+ assert(oap_hdr != NULL);
+ memset(oap_hdr, 0, sizeof(*oap_hdr));
+
+ if (hdr.len < OAP_HDR_MIN_SIZE)
+ goto fail_decode;
+
+ oap_hdr->id.data = hdr.data;
+ oap_hdr->id.len = OAP_ID_SIZE;
+
+ offset = OAP_ID_SIZE;
+
+ oap_hdr->timestamp = ntoh64(*(uint64_t *)(hdr.data + offset));
+
+ offset += sizeof(uint64_t);
+
+ oap_hdr->crt.len = (size_t) ntoh16(*(uint16_t *)(hdr.data + offset));
+ oap_hdr->crt.data = hdr.data + offset + sizeof(uint16_t);
+
+ offset += sizeof(uint16_t) + oap_hdr->crt.len;
+
+ if ((size_t) offset + sizeof(uint16_t) >= hdr.len)
+ goto fail_decode;
+
+ oap_hdr->eph.len = (size_t) ntoh16(*(uint16_t *)(hdr.data + offset));
+ oap_hdr->eph.data = hdr.data + offset + sizeof(uint16_t);
+
+ offset += sizeof(uint16_t) + oap_hdr->eph.len;
+
+ if ((size_t) offset + sizeof(uint16_t) >= hdr.len)
+ goto fail_decode;
+
+ oap_hdr->data.len = (size_t) ntoh16(*(uint16_t *)(hdr.data + offset));
+ oap_hdr->data.data = hdr.data + offset + sizeof(uint16_t);
+
+ offset += sizeof(uint16_t) + oap_hdr->data.len;
+
+ if ((size_t) offset + sizeof(uint16_t) > hdr.len)
+ goto fail_decode;
+
+ oap_hdr->sig.len = (size_t) ntoh16(*(uint16_t *)(hdr.data + offset));
+ oap_hdr->sig.data = hdr.data + offset + sizeof(uint16_t);
+
+ offset += sizeof(uint16_t) + oap_hdr->sig.len;
+
+ if ((size_t) offset != hdr.len)
+ goto fail_decode;
+
+ oap_hdr->hdr = hdr;
+
+ return 0;
+
+ fail_decode:
+ memset(oap_hdr, 0, sizeof(*oap_hdr));
+ return -1;
+}
+
+
diff --git a/src/irmd/oap.h b/src/irmd/oap.h
new file mode 100644
index 00000000..460a89de
--- /dev/null
+++ b/src/irmd/oap.h
@@ -0,0 +1,88 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Ouroboros flow allocation protocol header
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_IRMD_OAP_H
+#define OUROBOROS_IRMD_OAP_H
+
+#include <ouroboros/utils.h>
+
+#define OAP_ID_SIZE (16)
+#define OAP_HDR_MIN_SIZE (OAP_ID_SIZE + sizeof(uint64_t) + 4 * sizeof(uint16_t))
+
+
+/*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +---------------------------------------------------------------+
+ * | |
+ * | id (128 bits) |
+ * | |
+ * | |
+ * +---------------------------------------------------------------+
+ * | timestamp (64 bits) |
+ * | |
+ * +---------------------------------------------------------------+
+ * | crt_len (16 bits) | |
+ * +-----------+-----------------+ |
+ * | certificate |
+ * | |
+ * +---------------------------------------------------------------+
+ * | eph_len (16 bits) | |
+ * +-----------+-----------------+ |
+ * | public key for ECDHE |
+ * | |
+ * +---------------------------------------------------------------+
+ * | data_len (16 bits) | |
+ * +-----------+-----------------+ |
+ * | piggy backed application data |
+ * | |
+ * +---------------------------------------------------------------+
+ * | sig_len (16 bits) | |
+ * +-----------+-----------------+ |
+ * | signature |
+ * | |
+ * +---------------------------------------------------------------+
+ */
+
+struct oap_hdr {
+ uint64_t timestamp;
+ buffer_t id;
+ buffer_t crt;
+ buffer_t eph;
+ buffer_t data;
+ buffer_t sig;
+ buffer_t hdr;
+};
+
+int oap_hdr_init(buffer_t id,
+ void * pkp,
+ void * pubcrt,
+ buffer_t ephkey,
+ buffer_t data,
+ struct oap_hdr * oap_hdr);
+
+void oap_hdr_fini(struct oap_hdr * oap_hdr);
+
+int oap_hdr_decode(buffer_t hdr,
+ struct oap_hdr * oap_hdr);
+
+#endif /* OUROBOROS_IRMD_OAP_H */
diff --git a/src/irmd/reg/reg.c b/src/irmd/reg/reg.c
index d95a4722..339e7fa0 100644
--- a/src/irmd/reg/reg.c
+++ b/src/irmd/reg/reg.c
@@ -1771,8 +1771,7 @@ int reg_respond_alloc(struct flow_info * info,
return -1;
}
-int reg_prepare_flow_accept(struct flow_info * info,
- buffer_t * pbuf)
+int reg_prepare_flow_accept(struct flow_info * info)
{
struct reg_flow * flow;
int ret;
@@ -1790,8 +1789,6 @@ int reg_prepare_flow_accept(struct flow_info * info,
ret = reg_flow_update(flow, info);
- reg_flow_set_data(flow, pbuf);
-
pthread_mutex_unlock(&reg.mtx);
return ret;
@@ -1915,7 +1912,6 @@ int reg_respond_accept(struct flow_info * info,
buffer_t * pbuf)
{
struct reg_flow * flow;
- buffer_t temp;
assert(info != NULL);
assert(info->state == FLOW_ALLOCATED);
@@ -1933,11 +1929,8 @@ int reg_respond_accept(struct flow_info * info,
info->n_pid = flow->info.n_pid;
- if (info->qs.cypher_s > 0) {
- reg_flow_get_data(flow, &temp);
- reg_flow_set_data(flow, pbuf);
- *pbuf = temp;
- }
+ reg_flow_set_data(flow, pbuf);
+ clrbuf(pbuf);
if (reg_flow_update(flow, info) < 0) {
log_err("Failed to create flow structs.");
diff --git a/src/irmd/reg/reg.h b/src/irmd/reg/reg.h
index 17dfcc32..f1899d65 100644
--- a/src/irmd/reg/reg.h
+++ b/src/irmd/reg/reg.h
@@ -119,8 +119,7 @@ int reg_wait_flow_allocated(struct flow_info * info,
int reg_respond_alloc(struct flow_info * info,
buffer_t * pbuf);
-int reg_prepare_flow_accept(struct flow_info * info,
- buffer_t * pbuf);
+int reg_prepare_flow_accept(struct flow_info * info);
int reg_wait_flow_accepted(struct flow_info * info,
buffer_t * pbuf,
diff --git a/src/irmd/reg/tests/reg_test.c b/src/irmd/reg/tests/reg_test.c
index 80fc64d6..b69cf476 100644
--- a/src/irmd/reg/tests/reg_test.c
+++ b/src/irmd/reg/tests/reg_test.c
@@ -115,7 +115,6 @@ static int test_reg_allocate_flow_timeout(void)
{
struct timespec abstime;
struct timespec timeo = TIMESPEC_INIT_MS(1);
- buffer_t pbuf;
buffer_t rbuf = {NULL, 0};
struct flow_info info = {
@@ -125,14 +124,6 @@ static int test_reg_allocate_flow_timeout(void)
TEST_START();
- pbuf.data = (uint8_t *) strdup(TEST_DATA);;
- if (pbuf.data == NULL) {
- printf("Failed to strdup data.\n");
- goto fail;
- }
-
- pbuf.len = strlen((char *) pbuf.data) + 1;
-
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeo, &abstime);
@@ -147,7 +138,7 @@ static int test_reg_allocate_flow_timeout(void)
goto fail;
}
- if (reg_prepare_flow_accept(&info, &pbuf) < 0) {
+ if (reg_prepare_flow_accept(&info) < 0) {
printf("Failed to prepare flow for accept.\n");
goto fail;
}
@@ -162,12 +153,6 @@ static int test_reg_allocate_flow_timeout(void)
goto fail;
}
- if (pbuf.data == NULL) {
- printf("Flow data was updated on timeout.");
- goto fail;
- }
-
- freebuf(pbuf);
reg_destroy_flow(info.id);
if (reg.n_flows != 0) {
@@ -220,13 +205,6 @@ static void * test_flow_respond_accept(void * o)
reg_respond_accept(info, &pbuf);
- if (info->qs.cypher_s == 0) {
- freebuf(pbuf);
- } else if (strcmp((char *) pbuf.data, TEST_DATA) != 0) {
- printf("Data was not passed correctly.\n");
- goto fail;
- }
-
return (void *) 0;
fail:
return (void *) -1;
@@ -237,7 +215,6 @@ static int test_reg_accept_flow_success(void)
pthread_t thr;
struct timespec abstime;
struct timespec timeo = TIMESPEC_INIT_S(1);
- buffer_t pbuf = {(uint8_t *) TEST_DATA, strlen(TEST_DATA)};
buffer_t rbuf = {NULL, 0};
struct flow_info info = {
@@ -267,7 +244,7 @@ static int test_reg_accept_flow_success(void)
goto fail;
}
- if (reg_prepare_flow_accept(&info, &pbuf) < 0) {
+ if (reg_prepare_flow_accept(&info) < 0) {
printf("Failed to prepare flow for accept.\n");
goto fail;
}
@@ -332,7 +309,6 @@ static int test_reg_accept_flow_success_no_crypt(void)
pthread_t thr;
struct timespec abstime;
struct timespec timeo = TIMESPEC_INIT_S(1);
- buffer_t pbuf = {(uint8_t *) TEST_DATA, strlen(TEST_DATA)};
buffer_t rbuf = {NULL, 0};
struct flow_info info = {
@@ -362,7 +338,7 @@ static int test_reg_accept_flow_success_no_crypt(void)
goto fail;
}
- if (reg_prepare_flow_accept(&info, &pbuf) < 0) {
+ if (reg_prepare_flow_accept(&info) < 0) {
printf("Failed to prepare flow for accept.\n");
goto fail;
}
@@ -389,10 +365,7 @@ static int test_reg_accept_flow_success_no_crypt(void)
goto fail;
}
- if (strcmp((char *) rbuf.data, TEST_DATA) != 0) {
- printf("Data was updated.\n");
- goto fail;
- }
+ freebuf(rbuf);
n_1_info.state = FLOW_DEALLOCATED;
@@ -1177,7 +1150,7 @@ static void * test_call_flow_accept(void * o)
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeo, &abstime);
- reg_prepare_flow_accept(&info, &pbuf);
+ reg_prepare_flow_accept(&info);
if (reg_wait_flow_accepted(&info, &pbuf, &abstime) != -ETIMEDOUT) {
printf("Wait allocated did not timeout.\n");
diff --git a/src/irmd/tests/CMakeLists.txt b/src/irmd/tests/CMakeLists.txt
index 99743052..e860acce 100644
--- a/src/irmd/tests/CMakeLists.txt
+++ b/src/irmd/tests/CMakeLists.txt
@@ -3,6 +3,8 @@ get_filename_component(src_folder "${tmp}" NAME)
create_test_sourcelist(${src_folder}_tests test_suite.c
# Add new tests here
+ irm_test.c
+ oap_test.c
)
add_executable(${src_folder}_test EXCLUDE_FROM_ALL ${${src_folder}_tests})
@@ -21,3 +23,5 @@ foreach(test ${tests_to_run})
get_filename_component(test_name ${test} NAME_WE)
add_test(irmd/${test_name} ${C_TEST_PATH}/${src_folder}_test ${test_name})
endforeach(test)
+
+set_property(TEST irmd/oap_test PROPERTY SKIP_RETURN_CODE 1)
diff --git a/src/irmd/tests/irm_test.c b/src/irmd/tests/irm_test.c
new file mode 100644
index 00000000..d440289c
--- /dev/null
+++ b/src/irmd/tests/irm_test.c
@@ -0,0 +1,33 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Unit tests of IRMd functions
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+
+
+int irm_test(int argc,
+ char **argv)
+{
+ int ret = 0;
+
+ (void) argc;
+ (void) argv;
+
+ return ret;
+}
diff --git a/src/irmd/tests/oap_test.c b/src/irmd/tests/oap_test.c
new file mode 100644
index 00000000..e9f67505
--- /dev/null
+++ b/src/irmd/tests/oap_test.c
@@ -0,0 +1,273 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Unit tests of Ouroboros flow allocation protocol
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include "config.h"
+
+#include "oap.c"
+
+#include <ouroboros/random.h>
+#include <ouroboros/test.h>
+
+static const char * pkp_str = \
+"-----BEGIN EC PRIVATE KEY-----\n"
+"MHcCAQEEIC13y+5jdKe80HBJD7WITpQamcn3rrkTX1r0v+JwSk4NoAoGCCqGSM49\n"
+"AwEHoUQDQgAEcC0yLAfUtufH8cdLybrdWPc6U+xRuhDhqqrEcBO5+eob2xyqEaNk\n"
+"nIV/86724zPptGRahWz0rzW2PvNppJdNBg==\n"
+"-----END EC PRIVATE KEY-----\n";
+
+/* Valid signed server certificate for server-2.unittest.o7s */
+static const char * crt_str = \
+"-----BEGIN CERTIFICATE-----\n"
+"MIIDgjCCAyigAwIBAgICEAIwCgYIKoZIzj0EAwIwWzELMAkGA1UEBhMCQkUxDDAK\n"
+"BgNVBAgMA09WTDEMMAoGA1UECgwDbzdzMRUwEwYDVQQLDAx1bml0dGVzdC5vN3Mx\n"
+"GTAXBgNVBAMMEGltMi51bml0dGVzdC5vN3MwHhcNMjUwNzA0MTMxODI5WhcNMzUw\n"
+"NzAyMTMxODI5WjBwMQswCQYDVQQGEwJCRTEMMAoGA1UECAwDT1ZMMQ4wDAYDVQQH\n"
+"DAVHaGVudDEMMAoGA1UECgwDbzdzMRUwEwYDVQQLDAx1bml0dGVzdC5vN3MxHjAc\n"
+"BgNVBAMMFXNlcnZlci0yLnVuaXR0ZXN0Lm83czBZMBMGByqGSM49AgEGCCqGSM49\n"
+"AwEHA0IABHAtMiwH1Lbnx/HHS8m63Vj3OlPsUboQ4aqqxHATufnqG9scqhGjZJyF\n"
+"f/Ou9uMz6bRkWoVs9K81tj7zaaSXTQajggHFMIIBwTAJBgNVHRMEAjAAMBEGCWCG\n"
+"SAGG+EIBAQQEAwIGQDA6BglghkgBhvhCAQ0ELRYrR3JpbGxlZCBDaGVlc2UgR2Vu\n"
+"ZXJhdGVkIFNlcnZlciBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUTt3xHTwE9amoglxh\n"
+"cEMqWv+PpDMwgb8GA1UdIwSBtzCBtIAUFfeZRx8QWWKQr7Aw8zjDu2shvcShgZek\n"
+"gZQwgZExCzAJBgNVBAYTAkJFMQwwCgYDVQQIDANPVkwxDjAMBgNVBAcMBUdoZW50\n"
+"MQwwCgYDVQQKDANvN3MxFTATBgNVBAsMDHVuaXR0ZXN0Lm83czEZMBcGA1UEAwwQ\n"
+"Y2EyLnVuaXR0ZXN0Lm83czEkMCIGCSqGSIb3DQEJARYVZHVtbXlAb3Vyb2Jvcm9z\n"
+"LnJvY2tzggIQAjAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEw\n"
+"EQYDVR0fBAowCDAGoASgAoYAMCoGCCsGAQUFBwEBBB4wHDAMBggrBgEFBQcwAoYA\n"
+"MAwGCCsGAQUFBzABhgAwIAYDVR0RBBkwF4IVc2VydmVyLTEudW5pdHRlc3Qubzdz\n"
+"MAoGCCqGSM49BAMCA0gAMEUCIQDHuDb62w/Uah4nKwUFoJVkr4rgdNGh2Rn3SWaK\n"
+"0FV/gAIgOLKorTwSgrTFdyOUkuPOhRs8BEMpah+dp8UTO8AnLvY=\n"
+"-----END CERTIFICATE-----\n";
+
+static int test_oap_hdr_init_fini(void)
+{
+ struct oap_hdr oap_hdr;
+ struct timespec now;
+ uint64_t stamp;
+ buffer_t ephkey = BUF_INIT;
+ buffer_t data = BUF_INIT;
+ uint8_t buf[OAP_ID_SIZE];
+ buffer_t id;
+ void * pkp = NULL;
+ void * pubcrt = NULL;
+
+ TEST_START();
+
+ random_buffer(buf, OAP_ID_SIZE);
+ id.data = buf;
+ id.len = OAP_ID_SIZE;
+
+ clock_gettime(CLOCK_REALTIME, &now);
+ stamp = TS_TO_UINT64(now);
+
+ if (oap_hdr_init(id, pkp, pubcrt, ephkey, data, &oap_hdr) < 0) {
+ printf("Failed to init OAP request header.\n");
+ goto fail_req_hdr;
+ }
+
+ if (oap_hdr.hdr.len != OAP_HDR_MIN_SIZE) {
+ printf("OAP request header wrong: %zu < %zu.\n",
+ oap_hdr.hdr.len, OAP_HDR_MIN_SIZE);
+ goto fail_req_hdr_chk;
+ }
+
+ if (oap_hdr.id.len != OAP_ID_SIZE) {
+ printf("OAP request header ID wrong size: %zu != %zu.\n",
+ oap_hdr.id.len, (size_t) OAP_ID_SIZE);
+ goto fail_req_hdr_chk;
+ }
+
+ if (memcmp(oap_hdr.id.data, id.data, OAP_ID_SIZE) != 0) {
+ printf("OAP request header ID mismatch.\n");
+ goto fail_req_hdr_chk;
+ }
+
+ if (oap_hdr.timestamp < stamp) {
+ printf("OAP request header timestamp is too old.\n");
+ goto fail_req_hdr_chk;
+ }
+
+ if (oap_hdr.timestamp > stamp + 1 * BILLION) {
+ printf("OAP request header timestamp is too new.\n");
+ goto fail_req_hdr_chk;
+ }
+
+ oap_hdr_fini(&oap_hdr);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_req_hdr_chk:
+ oap_hdr_fini(&oap_hdr);
+ fail_req_hdr:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_oap_hdr_init_fini_data(void)
+
+{
+ struct oap_hdr oap_hdr;
+ buffer_t data;
+ buffer_t ephkey = BUF_INIT;
+ uint8_t buf[OAP_ID_SIZE];
+ buffer_t id;
+ void * pkp = NULL;
+ void * pubcrt = NULL;
+
+ TEST_START();
+
+ random_buffer(buf, OAP_ID_SIZE);
+ id.data = buf;
+ id.len = OAP_ID_SIZE;
+
+ data.len = 100;
+ data.data = malloc(data.len);
+ if (data.data == NULL) {
+ printf("Failed to allocate data buffer.\n");
+ goto fail_data;
+ }
+
+ random_buffer(data.data, data.len);
+
+ if (oap_hdr_init(id, pkp, pubcrt, ephkey, data, &oap_hdr) < 0) {
+ printf("Failed to create OAP request header.\n");
+ goto fail_req_hdr;
+ }
+
+ if (oap_hdr.hdr.len != OAP_HDR_MIN_SIZE + data.len) {
+ printf("OAP request header wrong: %zu < %zu.\n",
+ oap_hdr.hdr.len, OAP_HDR_MIN_SIZE + data.len);
+ goto fail_req_hdr_sz;
+ }
+
+ oap_hdr_fini(&oap_hdr);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_req_hdr_sz:
+ oap_hdr_fini(&oap_hdr);
+ fail_req_hdr:
+ freebuf(data);
+ fail_data:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_oap_hdr_init_fini_signed(void)
+{
+ struct oap_hdr oap_hdr;
+ buffer_t ephkey = BUF_INIT;
+ buffer_t data = BUF_INIT;
+ buffer_t sign;
+ buffer_t id;
+ uint8_t buf[OAP_ID_SIZE];
+ void * pkp;
+ void * pk;
+ void * pubcrt;
+ void * pubcrt2;
+
+ TEST_START();
+
+ random_buffer(buf, OAP_ID_SIZE);
+ id.data = buf;
+ id.len = OAP_ID_SIZE;
+
+ if (crypt_load_privkey_str(pkp_str, &pkp) < 0) {
+ printf("Failed to load private key.\n");
+ goto fail_pkp;
+ }
+
+ if (crypt_load_crt_str(crt_str, &pubcrt) < 0) {
+ printf("Failed to load public certificate.\n");
+ goto fail_pubcrt;
+ }
+
+ if (oap_hdr_init(id, pkp, pubcrt, ephkey, data, &oap_hdr) < 0) {
+ printf("Failed to create OAP request header.\n");
+ goto fail_req_hdr;
+ }
+
+ if (crypt_load_crt_der(oap_hdr.crt, &pubcrt2) < 0) {
+ printf("Failed to load public certificate from DER.\n");
+ goto fail_crt_der;
+ }
+
+ if (crypt_get_pubkey_crt(pubcrt2, &pk) < 0) {
+ printf("Failed to get public key from certificate.\n");
+ goto fail_crt_pk;
+ }
+
+ sign = oap_hdr.hdr;
+ sign.len -= (oap_hdr.sig.len + sizeof(uint16_t));
+
+ if (auth_verify_sig(pk, sign, oap_hdr.sig) < 0) {
+ printf("Failed to verify OAP request header signature.\n");
+ goto fail_check_sig;
+ }
+
+ oap_hdr_fini(&oap_hdr);
+
+ crypt_free_crt(pubcrt2);
+ crypt_free_crt(pubcrt);
+ crypt_free_key(pk);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_check_sig:
+ crypt_free_key(pk);
+ fail_crt_pk:
+ crypt_free_crt(pubcrt2);
+ fail_crt_der:
+ oap_hdr_fini(&oap_hdr);
+ fail_req_hdr:
+ crypt_free_crt(pubcrt);
+ fail_pubcrt:
+ crypt_free_key(pkp);
+ fail_pkp:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+int oap_test(int argc,
+ char **argv)
+{
+ int ret = 0;
+
+ (void) argc;
+ (void) argv;
+
+ ret |= test_oap_hdr_init_fini();
+ ret |= test_oap_hdr_init_fini_data();
+#ifdef HAVE_OPENSSL
+ ret |= test_oap_hdr_init_fini_signed();
+#else
+ (void) test_oap_hdr_init_fini_signed;
+
+ ret = TEST_RC_SKIP;
+#endif
+ return ret;
+}