From b03c1ab75f9e62a65b654bce74f32845b4a00500 Mon Sep 17 00:00:00 2001 From: Joseph Birr-Pixton Date: Sat, 16 Apr 2016 17:48:21 +0100 Subject: [PATCH] Make CMAC API more resistant to misuse Set 'finalised' flag only when finalisation happens, not when we get a final 'empty' block. Assert that if we have a non-empty message, we get the final flag along with some data. --- src/cmac.c | 12 ++++++++---- src/modes.h | 5 +++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/cmac.c b/src/cmac.c index f96d4d2..51f5843 100644 --- a/src/cmac.c +++ b/src/cmac.c @@ -95,12 +95,14 @@ static void cmac_process_final_nopad(void *vctx, const uint8_t *block) { cf_cmac_stream *ctx = vctx; cmac_process_final(ctx, block, ctx->cmac.B); + ctx->finalised = 1; } static void cmac_process_final_pad(void *vctx, const uint8_t *block) { cf_cmac_stream *ctx = vctx; cmac_process_final(ctx, block, ctx->cmac.P); + ctx->finalised = 1; } void cf_cmac_stream_update(cf_cmac_stream *ctx, const uint8_t *data, size_t len, int isfinal) @@ -111,13 +113,15 @@ void cf_cmac_stream_update(cf_cmac_stream *ctx, const uint8_t *data, size_t len, if (isfinal) { - assert(!ctx->finalised); - ctx->finalised = 1; + int whole_number_of_blocks = ((len + ctx->used) & 0xf) == 0; + int empty_message = len == 0 && ctx->used == 0 && ctx->processed == 0; + + assert(!ctx->finalised); /* finalised before? */ + assert(len != 0 || empty_message); /* we can't be told we're done after the fact. */ /* If we have a whole number of blocks, and at least 1 block, we XOR in B. * Otherwise, we need to pad and XOR in P. */ - if (((len + ctx->used) & 0xf) == 0 && - !(len == 0 && ctx->used == 0 && ctx->processed == 0)) + if (whole_number_of_blocks && !empty_message) final_fn = cmac_process_final_nopad; else needpad = 1; diff --git a/src/modes.h b/src/modes.h index 9790f39..75f9bfd 100644 --- a/src/modes.h +++ b/src/modes.h @@ -263,6 +263,11 @@ void cf_cmac_sign(cf_cmac *ctx, const uint8_t *data, size_t bytes, /* .. c:type:: cf_cmac_stream * Stream interface to CMAC signing. * + * Input data in arbitrary chunks using :c:func:`cf_cmac_stream_update`. + * The last bit of data must be signalled with the `isfinal` flag to + * that function, and the data cannot be zero length unless the whole + * message is empty. + * * .. c:member:: cf_cmac_stream.cmac * CMAC one-shot data. *