summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib/crypt.c8
-rw-r--r--src/lib/crypt/keyrot.c27
-rw-r--r--src/lib/tests/keyrot_test.c23
3 files changed, 42 insertions, 16 deletions
diff --git a/src/lib/crypt.c b/src/lib/crypt.c
index e4cf7885..cbbb9bc2 100644
--- a/src/lib/crypt.c
+++ b/src/lib/crypt.c
@@ -887,11 +887,17 @@ int crypt_get_headsz(struct crypt_ctx * ctx)
int crypt_rekey(struct crypt_ctx * ctx,
struct crypt_sk * sk)
{
+ int ret;
+
assert(ctx != NULL);
assert(sk != NULL);
assert(ctx->kr != NULL);
- return keyrot_rekey(ctx->kr, sk->key, sk->epoch) == 0 ? 0 : -ECRYPT;
+ ret = keyrot_rekey(ctx->kr, sk->key, sk->epoch);
+ if (ret == -EREPLAY)
+ return -EREPLAY;
+
+ return ret == 0 ? 0 : -ECRYPT;
}
int crypt_get_tagsz(struct crypt_ctx * ctx)
diff --git a/src/lib/crypt/keyrot.c b/src/lib/crypt/keyrot.c
index def29297..e98df356 100644
--- a/src/lib/crypt/keyrot.c
+++ b/src/lib/crypt/keyrot.c
@@ -26,6 +26,7 @@
#include <ouroboros/atomics.h>
#include <ouroboros/crypt.h>
+#include <ouroboros/errno.h>
#include <ouroboros/pthread.h>
#include <ouroboros/rcu.h>
@@ -470,17 +471,17 @@ void keyrot_destroy(struct keyrot * 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)
+static struct kr_batch * kr_live_batch(struct kr_batch * cur,
+ struct kr_batch * prev,
+ uint8_t epoch)
{
if (epoch == cur->epoch)
- return true;
+ return cur;
- if (prev == NULL)
- return false;
+ if (prev != NULL && epoch == prev->epoch)
+ return prev;
- return epoch == prev->epoch;
+ return NULL;
}
int keyrot_rekey(struct keyrot * kr,
@@ -491,6 +492,8 @@ int keyrot_rekey(struct keyrot * kr,
struct kr_batch * old_prev;
struct kr_batch * cur;
struct kr_batch * prev;
+ struct kr_batch * live;
+ int ret;
assert(kr != NULL);
assert(root != NULL);
@@ -507,10 +510,16 @@ int keyrot_rekey(struct keyrot * kr,
cur = rcu_deref(kr->cur);
prev = rcu_deref(kr->prev);
- if (kr_epoch_live(cur, prev, epoch)) {
+ live = kr_live_batch(cur, prev, epoch);
+ if (live != NULL) {
+ /* The first node key identifies the root. */
+ if (crypt_ct_cmp(live->nodes, nb->nodes, SYMMKEYSZ) == 0)
+ ret = -EREPLAY;
+ else
+ ret = -1;
rcu_wrunlock(&kr->guard);
kr_batch_free(nb);
- return -1;
+ return ret;
}
old_prev = kr->prev;
diff --git a/src/lib/tests/keyrot_test.c b/src/lib/tests/keyrot_test.c
index 10baee5c..efdc718e 100644
--- a/src/lib/tests/keyrot_test.c
+++ b/src/lib/tests/keyrot_test.c
@@ -28,6 +28,7 @@
#ifdef HAVE_OPENSSL
#include <ouroboros/crypt.h>
+#include <ouroboros/errno.h>
#include <ouroboros/pthread.h>
#include "crypt/keyrot.h"
@@ -112,8 +113,8 @@ static int test_rekey_dup_epoch(void)
if (a == NULL)
goto fail;
- if (keyrot_rekey(a, SEED_B, 0) == 0) {
- printf("Re-key to the current epoch accepted.\n");
+ if (keyrot_rekey(a, SEED_B, 0) != -1) {
+ printf("New key to the current epoch not a conflict.\n");
goto fail_a;
}
@@ -122,13 +123,23 @@ static int test_rekey_dup_epoch(void)
goto fail_a;
}
- if (keyrot_rekey(a, SEED_A, 1) == 0) {
- printf("Re-key to the current epoch accepted.\n");
+ if (keyrot_rekey(a, SEED_B, 1) != -EREPLAY) {
+ printf("Same key to the current epoch not a replay.\n");
goto fail_a;
}
- if (keyrot_rekey(a, SEED_A, 0) == 0) {
- printf("Re-key to the previous epoch accepted.\n");
+ if (keyrot_rekey(a, SEED_A, 1) != -1) {
+ printf("New key to the current epoch not a conflict.\n");
+ goto fail_a;
+ }
+
+ if (keyrot_rekey(a, SEED_A, 0) != -EREPLAY) {
+ printf("Same key to the previous epoch not a replay.\n");
+ goto fail_a;
+ }
+
+ if (keyrot_rekey(a, SEED_B, 0) != -1) {
+ printf("New key to the previous epoch not a conflict.\n");
goto fail_a;
}