summaryrefslogtreecommitdiff
path: root/src/lib/crypt/keyrot.c
diff options
context:
space:
mode:
authorDimitri Staessens <dimitri@ouroboros.rocks>2026-07-02 01:03:45 +0200
committerSander Vrijders <sander@ouroboros.rocks>2026-07-08 11:02:23 +0200
commita16482e4d85394314553c27afcc37c0036b6d506 (patch)
treed563c3a2130a6c669085d1c86a9757c32cabbc23 /src/lib/crypt/keyrot.c
parent2f9fdfa5ae2749f10d9ebc805e388ab9962d9faa (diff)
downloadouroboros-a16482e4d85394314553c27afcc37c0036b6d506.tar.gz
ouroboros-a16482e4d85394314553c27afcc37c0036b6d506.zip
lib: Reject re-key to a live epoch
A re-key epoch arrives from the peer, so we need to reject duplicates to avoid two batches sharing a wire epoch with different keys. Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks> Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
Diffstat (limited to 'src/lib/crypt/keyrot.c')
-rw-r--r--src/lib/crypt/keyrot.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/src/lib/crypt/keyrot.c b/src/lib/crypt/keyrot.c
index 8b0d9429..def29297 100644
--- a/src/lib/crypt/keyrot.c
+++ b/src/lib/crypt/keyrot.c
@@ -469,12 +469,28 @@ void keyrot_destroy(struct keyrot * kr)
free(kr);
}
+/* A dup live epoch shadows straggler RX; epoch is peer-driven. */
+static bool kr_epoch_live(const struct kr_batch * cur,
+ const struct kr_batch * prev,
+ uint8_t epoch)
+{
+ if (epoch == cur->epoch)
+ return true;
+
+ if (prev == NULL)
+ return false;
+
+ return epoch == prev->epoch;
+}
+
int keyrot_rekey(struct keyrot * kr,
const uint8_t * root,
uint8_t epoch)
{
struct kr_batch * nb;
struct kr_batch * old_prev;
+ struct kr_batch * cur;
+ struct kr_batch * prev;
assert(kr != NULL);
assert(root != NULL);
@@ -488,6 +504,15 @@ int keyrot_rekey(struct keyrot * kr,
rcu_wrlock(&kr->guard);
+ cur = rcu_deref(kr->cur);
+ prev = rcu_deref(kr->prev);
+
+ if (kr_epoch_live(cur, prev, epoch)) {
+ rcu_wrunlock(&kr->guard);
+ kr_batch_free(nb);
+ return -1;
+ }
+
old_prev = kr->prev;
rcu_assign(kr->prev, kr->cur);
rcu_publish(nb);