diff options
| -rw-r--r-- | src/lib/crypt.c | 8 | ||||
| -rw-r--r-- | src/lib/crypt/keyrot.c | 27 | ||||
| -rw-r--r-- | src/lib/tests/keyrot_test.c | 23 |
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; } |
