Skip to content

Commit b4e345f

Browse files
cmac: take a NULL key in init as a restart with the cached key
- wp_cmac_set_key() takes key as NULL to mean the cached key is kept: the length and expKeySize checks and the cleanse/copy of macCtx->key are conditioned on key being non-NULL, and a NULL key with no cached key returns failure. - wp_cmac_init() calls wp_cmac_set_key() with restart set whenever a key is passed in or one is already cached. - The doxygen for the key parameter of both functions covers the NULL case. - test_cmac_reinit drives one EVP_MAC_CTX through init, update and final rounds with no key argument and through an init mid-stream, comparing the MACs with OpenSSL; it is declared in unit.h and registered in unit.c. Issue: F-11550
1 parent 52398d9 commit b4e345f

4 files changed

Lines changed: 155 additions & 9 deletions

File tree

src/wp_cmac.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ static void wp_cmac_free(wp_CmacCtx* macCtx)
104104
* Allocates space for the key in the wolfSSL CMAC object.
105105
*
106106
* @param [in, out] macCtx CMAC context object.
107-
* @param [in] key Key data to set.
107+
* @param [in] key Key data to set. NULL keeps the cached key.
108108
* @param [in] keyLen Length of key data in bytes.
109109
* @param [in] restart Restart CMAC calculation.
110110
* @return 1 on success.
@@ -117,18 +117,24 @@ static int wp_cmac_set_key(wp_CmacCtx* macCtx, const unsigned char* key,
117117

118118
WOLFPROV_ENTER(WP_LOG_COMP_MAC, "wp_cmac_set_key");
119119

120-
if (keyLen > AES_256_KEY_SIZE) {
120+
if ((key == NULL) && (macCtx->keyLen == 0)) {
121121
ok = 0;
122122
}
123-
if (ok && (macCtx->expKeySize != 0) && (keyLen != macCtx->expKeySize)) {
123+
if (ok && (key != NULL) && (keyLen > AES_256_KEY_SIZE)) {
124+
ok = 0;
125+
}
126+
if (ok && (key != NULL) && (macCtx->expKeySize != 0) &&
127+
(keyLen != macCtx->expKeySize)) {
124128
ok = 0;
125129
}
126130
if (ok) {
127-
if (macCtx->keyLen > 0) {
128-
OPENSSL_cleanse(macCtx->key, macCtx->keyLen);
131+
if (key != NULL) {
132+
if (macCtx->keyLen > 0) {
133+
OPENSSL_cleanse(macCtx->key, macCtx->keyLen);
134+
}
135+
macCtx->keyLen = keyLen;
136+
XMEMCPY(macCtx->key, key, keyLen);
129137
}
130-
macCtx->keyLen = keyLen;
131-
XMEMCPY(macCtx->key, key, keyLen);
132138

133139
if (restart) {
134140
#if LIBWOLFSSL_VERSION_HEX >= 0x05000000
@@ -190,7 +196,8 @@ static wp_CmacCtx* wp_cmac_dup(wp_CmacCtx* src)
190196
* Initializes an CMAC context object with a key and parameters.
191197
*
192198
* @param [in, out] macCtx CMAC context object to initialize.
193-
* @param [in] key Key data to set.
199+
* @param [in] key Key data to set. NULL restarts with the cached
200+
* key, if one is set.
194201
* @param [in] keyLen Length of key data in bytes.
195202
* @param [in] params Extra parameters to set.
196203
* @return 1 on success.
@@ -211,7 +218,8 @@ static int wp_cmac_init(wp_CmacCtx* macCtx, const unsigned char* key,
211218
}
212219
if (ok) {
213220
macCtx->size = AES_BLOCK_SIZE;
214-
if ((key != NULL) && (!wp_cmac_set_key(macCtx, key, keyLen, 1))) {
221+
if (((key != NULL) || (macCtx->keyLen > 0)) &&
222+
(!wp_cmac_set_key(macCtx, key, keyLen, 1))) {
215223
ok = 0;
216224
}
217225
}

test/test_cmac.c

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,142 @@ int test_cmac_multi_update(void *data)
358358
return err;
359359
}
360360

361+
/**
362+
* Test that one CMAC context can be reset by calling EVP_MAC_init() with no
363+
* key, both after EVP_MAC_final() and mid-stream, reusing the cached key.
364+
*/
365+
static int test_cmac_reinit_helper(OSSL_LIB_CTX *libCtx, unsigned char *macA,
366+
unsigned char *macB)
367+
{
368+
int err;
369+
EVP_MAC *emac = NULL;
370+
EVP_MAC_CTX *ctx = NULL;
371+
OSSL_PARAM params[3];
372+
char cipher[] = "AES-256-CBC";
373+
unsigned char key[32] = {
374+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
375+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
376+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
377+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
378+
};
379+
unsigned char msgA[32];
380+
unsigned char msgB[21];
381+
unsigned char macC[AES_BLOCK_SIZE];
382+
unsigned char macD[AES_BLOCK_SIZE];
383+
size_t macASz = AES_BLOCK_SIZE;
384+
size_t macBSz = AES_BLOCK_SIZE;
385+
size_t macCSz = sizeof(macC);
386+
size_t macDSz = sizeof(macD);
387+
388+
memset(msgA, 0x41, sizeof(msgA));
389+
memset(msgB, 0x5a, sizeof(msgB));
390+
391+
params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER,
392+
cipher, 0);
393+
params[1] = OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY,
394+
(void *)key, sizeof(key));
395+
params[2] = OSSL_PARAM_construct_end();
396+
397+
err = (emac = EVP_MAC_fetch(libCtx, "CMAC", NULL)) == NULL;
398+
if (err == 0) {
399+
err = (ctx = EVP_MAC_CTX_new(emac)) == NULL;
400+
}
401+
if (err == 0) {
402+
err = EVP_MAC_CTX_set_params(ctx, params) != 1;
403+
}
404+
405+
/* First round with installed key by EVP_MAC_CTX_set_params() above. */
406+
if (err == 0) {
407+
err = EVP_MAC_init(ctx, NULL, 0, NULL) != 1;
408+
}
409+
if (err == 0) {
410+
err = EVP_MAC_update(ctx, msgA, sizeof(msgA)) != 1;
411+
}
412+
if (err == 0) {
413+
err = EVP_MAC_final(ctx, macA, &macASz, AES_BLOCK_SIZE) != 1;
414+
}
415+
416+
/* Reset after final and MAC a different message with the cached key. */
417+
if (err == 0) {
418+
err = EVP_MAC_init(ctx, NULL, 0, NULL) != 1;
419+
}
420+
if (err == 0) {
421+
err = EVP_MAC_update(ctx, msgB, sizeof(msgB)) != 1;
422+
}
423+
if (err == 0) {
424+
err = EVP_MAC_final(ctx, macB, &macBSz, AES_BLOCK_SIZE) != 1;
425+
}
426+
427+
/* The first message must produce the first MAC again. */
428+
if (err == 0) {
429+
err = EVP_MAC_init(ctx, NULL, 0, NULL) != 1;
430+
}
431+
if (err == 0) {
432+
err = EVP_MAC_update(ctx, msgA, sizeof(msgA)) != 1;
433+
}
434+
if (err == 0) {
435+
err = EVP_MAC_final(ctx, macC, &macCSz, sizeof(macC)) != 1;
436+
}
437+
if ((err == 0) && ((macCSz != macASz) ||
438+
(memcmp(macC, macA, macASz) != 0))) {
439+
PRINT_ERR_MSG("CMAC after reset doesn't match the first MAC");
440+
err = 1;
441+
}
442+
443+
/* A reset mid-stream must discard the data buffered so far. */
444+
if (err == 0) {
445+
err = EVP_MAC_init(ctx, NULL, 0, NULL) != 1;
446+
}
447+
if (err == 0) {
448+
err = EVP_MAC_update(ctx, msgA, sizeof(msgA)) != 1;
449+
}
450+
if (err == 0) {
451+
err = EVP_MAC_init(ctx, NULL, 0, NULL) != 1;
452+
}
453+
if (err == 0) {
454+
err = EVP_MAC_update(ctx, msgB, sizeof(msgB)) != 1;
455+
}
456+
if (err == 0) {
457+
err = EVP_MAC_final(ctx, macD, &macDSz, sizeof(macD)) != 1;
458+
}
459+
if ((err == 0) && ((macDSz != macBSz) ||
460+
(memcmp(macD, macB, macBSz) != 0))) {
461+
PRINT_ERR_MSG("CMAC after mid-stream reset covers stale data");
462+
err = 1;
463+
}
464+
465+
EVP_MAC_CTX_free(ctx);
466+
EVP_MAC_free(emac);
467+
return err;
468+
}
469+
470+
int test_cmac_reinit(void *data)
471+
{
472+
int err;
473+
unsigned char osslMacA[AES_BLOCK_SIZE];
474+
unsigned char osslMacB[AES_BLOCK_SIZE];
475+
unsigned char wpMacA[AES_BLOCK_SIZE];
476+
unsigned char wpMacB[AES_BLOCK_SIZE];
477+
478+
(void)data;
479+
480+
PRINT_MSG("CMAC context reset with OpenSSL");
481+
err = test_cmac_reinit_helper(osslLibCtx, osslMacA, osslMacB);
482+
if (err == 0) {
483+
PRINT_MSG("CMAC context reset with wolfProvider");
484+
err = test_cmac_reinit_helper(wpLibCtx, wpMacA, wpMacB);
485+
}
486+
if ((err == 0) && (memcmp(osslMacA, wpMacA, AES_BLOCK_SIZE) != 0)) {
487+
PRINT_ERR_MSG("First CMAC doesn't match OpenSSL");
488+
err = 1;
489+
}
490+
if ((err == 0) && (memcmp(osslMacB, wpMacB, AES_BLOCK_SIZE) != 0)) {
491+
PRINT_ERR_MSG("CMAC after reset doesn't match OpenSSL");
492+
err = 1;
493+
}
494+
return err;
495+
}
496+
361497
int test_cmac_dup(void *data)
362498
{
363499
int ret = 0;

test/unit.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ TEST_CASE test_case[] = {
225225
#ifdef WP_HAVE_CMAC
226226
TEST_DECL(test_cmac_create, &flags),
227227
TEST_DECL(test_cmac_multi_update, &flags),
228+
TEST_DECL(test_cmac_reinit, &flags),
228229
TEST_DECL(test_cmac_dup, &flags),
229230
TEST_DECL(test_cmac_size_query, &flags),
230231
#endif

test/unit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ int test_mac_sig_dup(void *data);
164164
#ifdef WP_HAVE_CMAC
165165
int test_cmac_create(void *data);
166166
int test_cmac_multi_update(void *data);
167+
int test_cmac_reinit(void *data);
167168
int test_cmac_dup(void *data);
168169
int test_cmac_size_query(void *data);
169170
#endif /* WP_HAVE_CMAC */

0 commit comments

Comments
 (0)