summaryrefslogtreecommitdiff
path: root/src/irmd/oap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/irmd/oap.c')
-rw-r--r--src/irmd/oap.c220
1 files changed, 220 insertions, 0 deletions
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;
+}
+
+