Coverage Report

Created: 2026-04-05 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wolfssl-heapmath/wolfcrypt/src/cmac.c
Line
Count
Source
1
/* cmac.c
2
 *
3
 * Copyright (C) 2006-2026 wolfSSL Inc.
4
 *
5
 * This file is part of wolfSSL.
6
 *
7
 * wolfSSL is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * wolfSSL is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20
 */
21
22
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
23
24
#ifdef WOLFSSL_QNX_CAAM
25
#include <wolfssl/wolfcrypt/port/caam/wolfcaam.h>
26
#endif
27
#if defined(WOLFSSL_HASH_KEEP)
28
#include <wolfssl/wolfcrypt/hash.h>
29
#endif
30
31
#if defined(WOLFSSL_CMAC)
32
33
#if defined(HAVE_FIPS) && defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)
34
    /* set NO_WRAPPERS before headers, use direct internal f()s not wrappers */
35
    #define FIPS_NO_WRAPPERS
36
37
    #ifdef USE_WINDOWS_API
38
        #pragma code_seg(".fipsA$c")
39
        #pragma const_seg(".fipsB$c")
40
    #endif
41
#endif
42
43
#ifdef NO_INLINE
44
    #include <wolfssl/wolfcrypt/misc.h>
45
#else
46
    #define WOLFSSL_MISC_INCLUDED
47
    #include <wolfcrypt/src/misc.c>
48
#endif
49
50
#include <wolfssl/wolfcrypt/aes.h>
51
#include <wolfssl/wolfcrypt/cmac.h>
52
53
#ifdef WOLF_CRYPTO_CB
54
    #include <wolfssl/wolfcrypt/cryptocb.h>
55
#endif
56
57
#if FIPS_VERSION3_GE(6,0,0)
58
    const unsigned int wolfCrypt_FIPS_cmac_ro_sanity[2] =
59
                                                     { 0x1a2b3c4d, 0x00000003 };
60
    int wolfCrypt_FIPS_CMAC_sanity(void)
61
    {
62
        return 0;
63
    }
64
#endif
65
66
#ifdef WOLFSSL_HASH_KEEP
67
/* Some hardware have issues with update, this function stores the data to be
68
 * hashed into an array. Once ready, the Final operation is called on all of the
69
 * data to be hashed at once.
70
 * returns 0 on success
71
 */
72
int wc_CMAC_Grow(Cmac* cmac, const byte* in, int inSz)
73
{
74
    return _wc_Hash_Grow(&cmac->msg, &cmac->used, &cmac->len, in, inSz, cmac->aes.heap);
75
}
76
#endif /* WOLFSSL_HASH_KEEP */
77
78
#if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT)
79
/* Used by AES-SIV. See aes.c. */
80
void ShiftAndXorRb(byte* out, byte* in)
81
490
{
82
490
    int i, j, xorRb;
83
490
    int mask = 0, last = 0;
84
490
    byte Rb = 0x87;
85
86
490
    xorRb = (in[0] & 0x80) != 0;
87
88
8.33k
    for (i = 1, j = WC_AES_BLOCK_SIZE - 1; i <= WC_AES_BLOCK_SIZE; i++, j--) {
89
7.84k
        last = (in[j] & 0x80) ? 1 : 0;
90
7.84k
        out[j] = (byte)((in[j] << 1) | mask);
91
7.84k
        mask = last;
92
7.84k
        if (xorRb) {
93
3.02k
            out[j] ^= Rb;
94
3.02k
            Rb = 0;
95
3.02k
        }
96
7.84k
    }
97
490
}
98
#endif /* !NO_AES && WOLFSSL_AES_DIRECT */
99
100
/* returns 0 on success */
101
int wc_InitCmac_ex(Cmac* cmac, const byte* key, word32 keySz,
102
                int type, void* unused, void* heap, int devId)
103
245
{
104
245
    int ret = 0;
105
#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_CRYPT)
106
    byte useSW = 0;
107
#endif
108
109
245
    (void)unused;
110
245
    (void)heap;
111
112
245
    if (cmac == NULL || type != WC_CMAC_AES) {
113
0
        return BAD_FUNC_ARG;
114
0
    }
115
116
#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_CRYPT)
117
    /* save if we should use SW crypt, restore after memset */
118
    useSW = cmac->useSWCrypt;
119
#endif
120
245
    XMEMSET(cmac, 0, sizeof(Cmac));
121
122
245
#ifdef WOLF_CRYPTO_CB
123
    /* Set devId regardless of value (invalid or not) */
124
245
    cmac->devId = devId;
125
245
    #ifndef WOLF_CRYPTO_CB_FIND
126
245
    if (devId != INVALID_DEVID)
127
0
    #endif
128
0
    {
129
0
        cmac->devCtx = NULL;
130
131
0
        ret = wc_CryptoCb_Cmac(cmac, key, keySz, NULL, 0, NULL, NULL,
132
0
                type, unused);
133
0
        if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
134
0
            return ret;
135
        /* fall-through when unavailable */
136
0
    }
137
#else
138
    (void)devId;
139
#endif
140
141
245
    if (key == NULL || keySz == 0) {
142
0
        return BAD_FUNC_ARG;
143
0
    }
144
145
245
    switch (type) {
146
0
#if !defined (NO_AES) && defined(WOLFSSL_AES_DIRECT)
147
245
    case WC_CMAC_AES:
148
245
        cmac->type = WC_CMAC_AES;
149
245
        ret = wc_AesInit(&cmac->aes, heap, devId);
150
151
    #if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_CRYPT)
152
        cmac->useSWCrypt = useSW;
153
        if (cmac->useSWCrypt == 1) {
154
            cmac->aes.useSWCrypt = 1;
155
        }
156
    #endif
157
158
245
        if (ret == 0) {
159
245
            ret = wc_AesSetKey(&cmac->aes, key, keySz, NULL, AES_ENCRYPTION);
160
245
        }
161
162
245
        if (ret == 0) {
163
245
            byte l[WC_AES_BLOCK_SIZE];
164
165
245
            XMEMSET(l, 0, WC_AES_BLOCK_SIZE);
166
245
#ifndef HAVE_SELFTEST
167
245
            ret = wc_AesEncryptDirect(&cmac->aes, l, l);
168
245
            if (ret == 0) {
169
245
                ShiftAndXorRb(cmac->k1, l);
170
245
                ShiftAndXorRb(cmac->k2, cmac->k1);
171
245
                ForceZero(l, WC_AES_BLOCK_SIZE);
172
245
            }
173
#else
174
            wc_AesEncryptDirect(&cmac->aes, l, l);
175
            ShiftAndXorRb(cmac->k1, l);
176
            ShiftAndXorRb(cmac->k2, cmac->k1);
177
            ForceZero(l, WC_AES_BLOCK_SIZE);
178
#endif
179
245
        }
180
245
        break;
181
0
#endif /* !NO_AES && WOLFSSL_AES_DIRECT */
182
0
    default:
183
0
        return BAD_FUNC_ARG;
184
245
    }
185
186
245
    return ret;
187
245
}
188
189
190
int wc_InitCmac(Cmac* cmac, const byte* key, word32 keySz,
191
                int type, void* unused)
192
245
{
193
#ifdef WOLFSSL_QNX_CAAM
194
    int devId = WOLFSSL_CAAM_DEVID;
195
#else
196
245
    int devId = INVALID_DEVID;
197
245
#endif
198
245
    return wc_InitCmac_ex(cmac, key, keySz, type, unused, NULL, devId);
199
245
}
200
201
202
203
int wc_CmacUpdate(Cmac* cmac, const byte* in, word32 inSz)
204
1.96k
{
205
1.96k
    int ret = 0;
206
207
1.96k
    if ((cmac == NULL) || (in == NULL && inSz != 0)) {
208
0
        return BAD_FUNC_ARG;
209
0
    }
210
211
1.96k
#ifdef WOLF_CRYPTO_CB
212
1.96k
    #ifndef WOLF_CRYPTO_CB_FIND
213
1.96k
    if (cmac->devId != INVALID_DEVID)
214
0
    #endif
215
0
    {
216
0
        ret = wc_CryptoCb_Cmac(cmac, NULL, 0, in, inSz,
217
0
            NULL, NULL, (int)cmac->type, NULL);
218
0
        if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
219
0
            return ret;
220
        /* fall-through when unavailable */
221
0
    }
222
1.96k
#endif
223
224
    /* Clear CRYPTOCB_UNAVAILABLE return code */
225
1.96k
    ret = 0;
226
227
1.96k
    switch (cmac->type) {
228
0
#if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT)
229
1.96k
    case WC_CMAC_AES:
230
1.96k
    {
231
#ifdef HAVE_SELFTEST
232
        while ((ret == 0) && (inSz != 0)) {
233
            word32 add = min(inSz, WC_AES_BLOCK_SIZE - cmac->bufferSz);
234
            XMEMCPY(&cmac->buffer[cmac->bufferSz], in, add);
235
236
            cmac->bufferSz += add;
237
            in += add;
238
            inSz -= add;
239
240
            if (cmac->bufferSz == WC_AES_BLOCK_SIZE && inSz != 0) {
241
                if (cmac->totalSz != 0) {
242
                    xorbuf(cmac->buffer, cmac->digest, WC_AES_BLOCK_SIZE);
243
                }
244
                wc_AesEncryptDirect(&cmac->aes, cmac->digest,
245
                        cmac->buffer);
246
                cmac->totalSz += WC_AES_BLOCK_SIZE;
247
                cmac->bufferSz = 0;
248
            }
249
        }
250
#else
251
1.96k
        (void)ret;
252
1.96k
        ret = wc_local_CmacUpdateAes(cmac, in, inSz);
253
1.96k
#endif
254
1.96k
    }; break;
255
0
#endif /* !NO_AES && WOLFSSL_AES_DIRECT */
256
0
    default:
257
0
        ret = BAD_FUNC_ARG;
258
1.96k
    }
259
1.96k
    return ret;
260
1.96k
}
261
262
int wc_CmacFree(Cmac* cmac)
263
245
{
264
245
    if (cmac == NULL)
265
0
        return BAD_FUNC_ARG;
266
#if defined(WOLFSSL_HASH_KEEP)
267
    /* TODO: msg is leaked if wc_CmacFinal() is not called
268
     * e.g. when multiple calls to wc_CmacUpdate() and one fails but
269
     * wc_CmacFinal() not called. */
270
    XFREE(cmac->msg, cmac->aes.heap, DYNAMIC_TYPE_TMP_BUFFER);
271
#endif
272
245
    switch (cmac->type) {
273
0
#if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT)
274
245
    case WC_CMAC_AES:
275
245
        wc_AesFree(&cmac->aes);
276
245
        break;
277
0
#endif /* !NO_AES && WOLFSSL_AES_DIRECT */
278
0
    default:
279
        /* Nothing to do */
280
0
        (void)cmac;
281
245
    }
282
245
    ForceZero(cmac, sizeof(Cmac));
283
245
    return 0;
284
245
}
285
286
int wc_CmacFinalNoFree(Cmac* cmac, byte* out, word32* outSz)
287
245
{
288
245
    int ret = 0;
289
290
245
    if (cmac == NULL || out == NULL || outSz == NULL) {
291
0
        return BAD_FUNC_ARG;
292
0
    }
293
245
    if (*outSz < WC_CMAC_TAG_MIN_SZ || *outSz > WC_CMAC_TAG_MAX_SZ) {
294
0
        return BUFFER_E;
295
0
    }
296
297
245
#ifdef WOLF_CRYPTO_CB
298
245
    #ifndef WOLF_CRYPTO_CB_FIND
299
245
    if (cmac->devId != INVALID_DEVID)
300
0
    #endif
301
0
    {
302
0
        ret = wc_CryptoCb_Cmac(cmac, NULL, 0, NULL, 0, out, outSz,
303
0
            (int)cmac->type, NULL);
304
0
        if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
305
0
            return ret;
306
307
        /* Clear CRYPTOCB_UNAVAILABLE return code */
308
0
       ret = 0;
309
310
        /* fall-through when unavailable */
311
0
    }
312
245
#endif
313
245
    if (ret == 0) {
314
245
        switch (cmac->type) {
315
0
    #if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT)
316
245
        case WC_CMAC_AES:
317
245
        {
318
245
            const byte* subKey;
319
245
            word32 remainder;
320
321
245
            if (cmac->bufferSz == WC_AES_BLOCK_SIZE) {
322
27
                subKey = cmac->k1;
323
27
            }
324
218
            else {
325
                /* ensure we will have a valid remainder value */
326
218
                if (cmac->bufferSz > WC_AES_BLOCK_SIZE) {
327
0
                    ret = BAD_STATE_E;
328
0
                    break;
329
0
                }
330
218
                remainder = WC_AES_BLOCK_SIZE - cmac->bufferSz;
331
332
218
                if (remainder == 0) {
333
0
                    remainder = WC_AES_BLOCK_SIZE;
334
0
                }
335
218
                if (remainder > 1) {
336
167
                    XMEMSET(cmac->buffer + WC_AES_BLOCK_SIZE - remainder, 0,
337
167
                            remainder);
338
167
                }
339
340
218
                cmac->buffer[WC_AES_BLOCK_SIZE - remainder] = 0x80;
341
218
                subKey = cmac->k2;
342
218
            }
343
245
            xorbuf(cmac->buffer, cmac->digest, WC_AES_BLOCK_SIZE);
344
245
            xorbuf(cmac->buffer, subKey, WC_AES_BLOCK_SIZE);
345
245
#ifndef HAVE_SELFTEST
346
245
            ret = wc_AesEncryptDirect(&cmac->aes, cmac->digest, cmac->buffer);
347
245
            if (ret == 0) {
348
245
                XMEMCPY(out, cmac->digest, *outSz);
349
245
            }
350
#else
351
            wc_AesEncryptDirect(&cmac->aes, cmac->digest, cmac->buffer);
352
            XMEMCPY(out, cmac->digest, *outSz);
353
#endif
354
245
        }; break;
355
0
    #endif /* !NO_AES && WOLFSSL_AES_DIRECT */
356
0
        default:
357
0
            ret = BAD_FUNC_ARG;
358
245
        }
359
245
    }
360
245
    return ret;
361
245
}
362
363
int wc_CmacFinal(Cmac* cmac, byte* out, word32* outSz)
364
245
{
365
245
    int ret = 0;
366
367
245
    if (cmac == NULL)
368
0
        return BAD_FUNC_ARG;
369
245
    ret = wc_CmacFinalNoFree(cmac, out, outSz);
370
245
    (void)wc_CmacFree(cmac);
371
245
    return ret;
372
245
}
373
374
#if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT)
375
int wc_AesCmacGenerate_ex(Cmac* cmac,
376
                          byte* out, word32* outSz,
377
                          const byte* in, word32 inSz,
378
                          const byte* key, word32 keySz,
379
                          void* heap, int devId)
380
0
{
381
0
    int ret = 0;
382
383
0
    if (cmac == NULL) {
384
0
        return BAD_FUNC_ARG;
385
0
    }
386
387
0
#ifdef WOLF_CRYPTO_CB
388
    /* Set devId regardless of value (invalid or not) */
389
0
    cmac->devId = devId;
390
0
    #ifndef WOLF_CRYPTO_CB_FIND
391
0
    if (devId != INVALID_DEVID)
392
0
    #endif
393
0
    {
394
0
        ret = wc_CryptoCb_Cmac(cmac, key, keySz, in, inSz, out, outSz,
395
0
                WC_CMAC_AES, NULL);
396
0
        if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
397
0
            return ret;
398
399
         /* Clear CRYPTOCB_UNAVAILABLE return code */
400
0
        ret = 0;
401
402
        /* fall-through when unavailable */
403
0
    }
404
0
#endif
405
406
0
    if ( ((out == NULL) && (outSz != NULL) && (*outSz > 0))
407
0
         || (in == NULL && inSz > 0)
408
0
         || (key == NULL && keySz > 0))  {
409
0
        return BAD_FUNC_ARG;
410
0
    }
411
412
    /* Init step is optional */
413
0
    if (key != NULL) {
414
0
        ret = wc_InitCmac_ex(cmac, key, keySz, WC_CMAC_AES, NULL, heap, devId);
415
0
    }
416
0
    if (ret == 0) {
417
0
        ret = wc_CmacUpdate(cmac, in, inSz);
418
        /* Ensure we are freed and zeroed if not calling wc_CmacFinal */
419
0
        if (ret != 0) {
420
0
            (void)wc_CmacFree(cmac);
421
0
        }
422
0
    }
423
0
    if (ret == 0) {
424
0
        ret = wc_CmacFinal(cmac, out, outSz);
425
0
    }
426
427
0
    return ret;
428
0
}
429
430
431
int wc_AesCmacGenerate(byte* out, word32* outSz,
432
                       const byte* in, word32 inSz,
433
                       const byte* key, word32 keySz)
434
0
{
435
0
    int ret = 0;
436
0
    WC_DECLARE_VAR(cmac, Cmac, 1, 0);
437
438
0
    if (out == NULL || (in == NULL && inSz > 0) || key == NULL || keySz == 0) {
439
0
        return BAD_FUNC_ARG;
440
0
    }
441
442
0
#ifdef WOLFSSL_SMALL_STACK
443
0
    if ((cmac = (Cmac *)XMALLOC(sizeof *cmac, NULL,
444
0
                                DYNAMIC_TYPE_CMAC)) == NULL) {
445
0
        return MEMORY_E;
446
0
    }
447
0
#endif
448
449
#ifdef WOLFSSL_CHECK_MEM_ZERO
450
    XMEMSET(((unsigned char *)cmac) + sizeof(Aes), 0xff,
451
        sizeof(Cmac) - sizeof(Aes));
452
    /* Aes part is checked by wc_AesFree. */
453
    wc_MemZero_Add("wc_AesCmacGenerate_ex cmac",
454
        ((unsigned char *)cmac) + sizeof(Aes), sizeof(Cmac) - sizeof(Aes));
455
#endif
456
457
0
    ret = wc_AesCmacGenerate_ex(cmac,
458
0
                                out, outSz,
459
0
                                in, inSz,
460
0
                                key, keySz,
461
0
                                NULL,
462
0
                                INVALID_DEVID);
463
464
465
0
#ifdef WOLFSSL_SMALL_STACK
466
0
    XFREE(cmac, NULL, DYNAMIC_TYPE_CMAC);
467
#elif defined(WOLFSSL_CHECK_MEM_ZERO)
468
    wc_MemZero_Check(cmac, sizeof(Cmac));
469
#endif
470
471
0
    return ret;
472
0
}
473
474
475
int wc_AesCmacVerify_ex(Cmac* cmac,
476
                        const byte* check, word32 checkSz,
477
                        const byte* in, word32 inSz,
478
                        const byte* key, word32 keySz,
479
                        void* heap, int devId)
480
0
{
481
0
    int ret = 0;
482
0
    byte a[WC_AES_BLOCK_SIZE];
483
0
    word32 aSz = sizeof(a);
484
0
    int compareRet;
485
486
0
    if (cmac == NULL || check == NULL || checkSz == 0 ||
487
0
            (in == NULL && inSz != 0)) {
488
0
        return BAD_FUNC_ARG;
489
0
    }
490
491
0
    XMEMSET(a, 0, aSz);
492
0
    ret = wc_AesCmacGenerate_ex(cmac,
493
0
                                a, &aSz,
494
0
                                in, inSz,
495
0
                                key, keySz,
496
0
                                heap,
497
0
                                devId);
498
0
    if (ret == 0) {
499
0
        compareRet = ConstantCompare(check, a, (int)min(checkSz, aSz));
500
0
        ret = compareRet ? 1 : 0;
501
0
    }
502
503
0
    return ret;
504
0
}
505
506
507
int wc_AesCmacVerify(const byte* check, word32 checkSz,
508
                     const byte* in, word32 inSz,
509
                     const byte* key, word32 keySz)
510
0
{
511
0
    int ret = 0;
512
0
    WC_DECLARE_VAR(cmac, Cmac, 1, 0);
513
514
0
    if (check == NULL || checkSz == 0 || (in == NULL && inSz > 0) ||
515
0
            key == NULL || keySz == 0) {
516
0
        return BAD_FUNC_ARG;
517
0
    }
518
519
0
#ifdef WOLFSSL_SMALL_STACK
520
0
    if ((cmac = (Cmac *)XMALLOC(sizeof *cmac, NULL,
521
0
                                DYNAMIC_TYPE_CMAC)) == NULL) {
522
0
        return MEMORY_E;
523
0
    }
524
0
#endif
525
526
#ifdef WOLFSSL_CHECK_MEM_ZERO
527
    XMEMSET(((unsigned char *)cmac) + sizeof(Aes), 0xff,
528
        sizeof(Cmac) - sizeof(Aes));
529
    /* Aes part is checked by wc_AesFree. */
530
    wc_MemZero_Add("wc_AesCmacGenerate_ex cmac",
531
        ((unsigned char *)cmac) + sizeof(Aes), sizeof(Cmac) - sizeof(Aes));
532
#endif
533
534
0
    ret = wc_AesCmacVerify_ex(cmac,
535
0
                              check, checkSz,
536
0
                              in, inSz,
537
0
                              key, keySz,
538
0
                              NULL,
539
0
                              INVALID_DEVID);
540
541
0
#ifdef WOLFSSL_SMALL_STACK
542
0
    XFREE(cmac, NULL, DYNAMIC_TYPE_CMAC);
543
#elif defined(WOLFSSL_CHECK_MEM_ZERO)
544
    wc_MemZero_Check(cmac, sizeof(Cmac));
545
#endif
546
547
0
    return ret;
548
0
}
549
#endif /* !NO_AES && WOLFSSL_AES_DIRECT */
550
551
#endif /* WOLFSSL_CMAC */