diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/ouroboros/crypt.h | 47 | ||||
| -rw-r--r-- | include/ouroboros/rcu.h | 110 |
2 files changed, 151 insertions, 6 deletions
diff --git a/include/ouroboros/crypt.h b/include/ouroboros/crypt.h index 543facaa..ce765158 100644 --- a/include/ouroboros/crypt.h +++ b/include/ouroboros/crypt.h @@ -28,7 +28,7 @@ #include <assert.h> -#define IVSZ 16 +#define NONCESZ 16 #define SYMMKEYSZ 32 #define MAX_HASH_SIZE 64 /* SHA-512/BLAKE2b max */ #define KEX_ALGO_BUFSZ 32 @@ -102,11 +102,15 @@ #define IS_KEX_ALGO_SET(cfg) ((cfg)->x.nid != NID_undef) #define IS_KEX_CIPHER_SET(cfg) ((cfg)->c.nid != NID_undef) +/* Flow role: forks the per-direction keys so each end's TX = peer's RX. */ +#define CRYPT_ROLE_INIT 0 /* flow allocator / OAP client */ +#define CRYPT_ROLE_RESP 1 /* flow acceptor / OAP server */ struct crypt_sk { int nid; uint8_t * key; - uint8_t rot_bit; /* Rotation bit to control epoch */ + uint8_t epoch; /* installed batch epoch */ + uint8_t role; /* CRYPT_ROLE_INIT / _RESP */ }; struct sec_config { @@ -308,12 +312,16 @@ const char * md_nid_to_str(uint16_t nid); uint16_t md_str_to_nid(const char * kdf); -ssize_t md_digest(int md_nid, - buffer_t in, - uint8_t * out); +ssize_t md_digest(int md_nid, + buffer_t in, + uint8_t * out); ssize_t md_len(int md_nid); +int crypt_hkdf_expand(buffer_t key, + buffer_t info, + buffer_t out); + int crypt_encrypt(struct crypt_ctx * ctx, buffer_t in, buffer_t * out); @@ -322,10 +330,37 @@ int crypt_decrypt(struct crypt_ctx * ctx, buffer_t in, buffer_t * out); -int crypt_get_ivsz(struct crypt_ctx * ctx); +/* One-shot AEAD over an explicit key/nonce. out = ciphertext ‖ tag. */ +int crypt_oneshot_seal(int nid, + const uint8_t * key, + const uint8_t * nonce, + buffer_t aad, + buffer_t in, + buffer_t * out); + +int crypt_oneshot_open(int nid, + const uint8_t * key, + const uint8_t * nonce, + buffer_t aad, + buffer_t in, + buffer_t * out); + +int crypt_get_headsz(struct crypt_ctx * ctx); int crypt_get_tagsz(struct crypt_ctx * ctx); +int crypt_rekey(struct crypt_ctx * ctx, + struct crypt_sk * sk); + +/* Nodes remaining in the TX batch (re-key watermark). */ +int crypt_nodes_left(struct crypt_ctx * ctx); + +/* 1 once the peer has been observed on the current generation. */ +int crypt_peer_synced(struct crypt_ctx * ctx); + +/* Switch TX to the installed (new) batch (after peer synced/grace). */ +void crypt_tx_promote(struct crypt_ctx * ctx); + int crypt_load_crt_file(const char * path, void ** crt); diff --git a/include/ouroboros/rcu.h b/include/ouroboros/rcu.h new file mode 100644 index 00000000..b4e7d27c --- /dev/null +++ b/include/ouroboros/rcu.h @@ -0,0 +1,110 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2026 + * + * Read-mostly pointer publication (RCU, with a locked fallback) + * + * 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/. + */ + +#ifndef OUROBOROS_LIB_RCU_H +#define OUROBOROS_LIB_RCU_H + +/* + * Lock-free reads of published pointers via liburcu (urcu-bp) when + * available; a per-object rwlock fallback otherwise. + * Include config.h before this header so HAVE_LIBURCU is defined. + * + * Embed a struct rcu_guard in the object. A reader brackets its access + * with rcu_rdlock/rcu_rdunlock and reads published pointers via rcu_deref. + * A writer serialises with rcu_wrlock/rcu_wrunlock and publishes via + * rcu_assign; after unlock it reclaims a now-unreachable object with + * rcu_reclaim (waits out live readers) before freeing it. rcu_drain waits + * out all readers at teardown. + */ + +#include <ouroboros/pthread.h> + +#ifdef HAVE_LIBURCU + +#include <urcu-bp.h> + +struct rcu_guard { + pthread_mutex_t w; /* serialises writers; readers use RCU */ +}; + +#define rcu_guard_init(g) pthread_mutex_init(&(g)->w, NULL) +#define rcu_guard_fini(g) pthread_mutex_destroy(&(g)->w) +#define rcu_rdlock(g) ((void) (g), rcu_read_lock()) +#define rcu_rdunlock(g) ((void) (g), rcu_read_unlock()) +#define rcu_wrlock(g) pthread_mutex_lock(&(g)->w) +#define rcu_wrunlock(g) pthread_mutex_unlock(&(g)->w) +#define rcu_deref(p) rcu_dereference(p) +#define rcu_assign(p, v) rcu_assign_pointer(p, v) +#define rcu_reclaim(g) ((void) (g), synchronize_rcu()) +#define rcu_drain(g) ((void) (g), synchronize_rcu()) + +/* TSan can miss the publish/consume barrier under urcu. */ +#if defined(__SANITIZE_THREAD__) +#define RCU_TSAN_ANNOTATE +#endif +#if defined(__has_feature) +#if __has_feature(thread_sanitizer) +#define RCU_TSAN_ANNOTATE +#endif +#endif + +/* + * Publish/consume annotations re-expose liburcu's rcu_assign/rcu_deref edge to + * TSan, which cannot see liburcu's barriers. Call rcu_publish(p) before + * publishing p with rcu_assign, and rcu_consume(p) after reading it with + * rcu_deref. No-op without liburcu (the rwlock fallback already gives TSan the + * edge) or without TSan. + */ +#ifdef RCU_TSAN_ANNOTATE +#include <sanitizer/tsan_interface.h> +#define rcu_publish(p) __tsan_release(p) +#define rcu_consume(p) __tsan_acquire(p) +#else +#define rcu_publish(p) ((void) (p)) +#define rcu_consume(p) ((void) (p)) +#endif + +#else /* !HAVE_LIBURCU : per-object rwlock fallback */ + +struct rcu_guard { + pthread_rwlock_t rw; /* readers rd, writers wr */ +}; + +#define rcu_guard_init(g) pthread_rwlock_init(&(g)->rw, NULL) +#define rcu_guard_fini(g) pthread_rwlock_destroy(&(g)->rw) +#define rcu_rdlock(g) pthread_rwlock_rdlock(&(g)->rw) +#define rcu_rdunlock(g) pthread_rwlock_unlock(&(g)->rw) +#define rcu_wrlock(g) pthread_rwlock_wrlock(&(g)->rw) +#define rcu_wrunlock(g) pthread_rwlock_unlock(&(g)->rw) +#define rcu_deref(p) (p) +#define rcu_assign(p, v) ((p) = (v)) +#define rcu_reclaim(g) ((void) (g)) /* wrlock already excluded readers */ +#define rcu_drain(g) (pthread_rwlock_wrlock(&(g)->rw), \ + pthread_rwlock_unlock(&(g)->rw)) + +/* rwlock already gives TSan the publish/consume edge; no annotation. */ +#define rcu_publish(p) ((void) (p)) +#define rcu_consume(p) ((void) (p)) + +#endif /* HAVE_LIBURCU */ + +#endif /* OUROBOROS_LIB_RCU_H */ |
