Coverage Report

Created: 2025-07-23 06:59

/src/wolfssl-fastmath/wolfcrypt/src/cmac.c
Line
Count
Source (jump to first uncovered line)
1
/* cmac.c
2
 *
3
 * Copyright (C) 2006-2025 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, NULL);
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
466
{
82
466
    int i, j, xorRb;
83
466
    int mask = 0, last = 0;
84
466
    byte Rb = 0x87;
85
86
466
    xorRb = (in[0] & 0x80) != 0;
87
88
7.92k
    for (i = 1, j = WC_AES_BLOCK_SIZE - 1; i <= WC_AES_BLOCK_SIZE; i++, j--) {
89
7.45k
        last = (in[j] & 0x80) ? 1 : 0;
90
7.45k
        out[j] = (byte)((in[j] << 1) | mask);
91
7.45k
        mask = last;
92
7.45k
        if (xorRb) {
93
3.52k
            out[j] ^= Rb;
94
3.52k
            Rb = 0;
95
3.52k
        }
96
7.45k
    }
97
466
}
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
233
{
104
233
    int ret = 0;
105
#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_CRYPT)
106
    byte useSW = 0;
107
#endif
108
109
233
    (void)unused;
110
233
    (void)heap;
111
112
233
    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
233
    XMEMSET(cmac, 0, sizeof(Cmac));
121
122
233
#ifdef WOLF_CRYPTO_CB
123
    /* Set devId regardless of value (invalid or not) */
124
233
    cmac->devId = devId;
125
233
    #ifndef WOLF_CRYPTO_CB_FIND
126
233
    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
233
    if (key == NULL || keySz == 0) {
142
0
        return BAD_FUNC_ARG;
143
0
    }
144
145
233
    switch (type) {
146
0
#if !defined (NO_AES) && defined(WOLFSSL_AES_DIRECT)
147
233
    case WC_CMAC_AES:
148
233
        cmac->type = WC_CMAC_AES;
149
233
        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
233
        if (ret == 0) {
159
233
            ret = wc_AesSetKey(&cmac->aes, key, keySz, NULL, AES_ENCRYPTION);
160
233
        }
161
162
233
        if (ret == 0) {
163
233
            byte l[WC_AES_BLOCK_SIZE];
164
165
233
            XMEMSET(l, 0, WC_AES_BLOCK_SIZE);
166
233
            ret = wc_AesEncryptDirect(&cmac->aes, l, l);
167
233
            if (ret == 0) {
168
233
                ShiftAndXorRb(cmac->k1, l);
169
233
                ShiftAndXorRb(cmac->k2, cmac->k1);
170
233
                ForceZero(l, WC_AES_BLOCK_SIZE);
171
233
            }
172
233
        }
173
233
        break;
174
0
#endif /* !NO_AES && WOLFSSL_AES_DIRECT */
175
0
    default:
176
0
        return BAD_FUNC_ARG;
177
233
    }
178
179
233
    return ret;
180
233
}
181
182
183
int wc_InitCmac(Cmac* cmac, const byte* key, word32 keySz,
184
                int type, void* unused)
185
233
{
186
#ifdef WOLFSSL_QNX_CAAM
187
    int devId = WOLFSSL_CAAM_DEVID;
188
#else
189
233
    int devId = INVALID_DEVID;
190
233
#endif
191
233
    return wc_InitCmac_ex(cmac, key, keySz, type, unused, NULL, devId);
192
233
}
193
194
195
196
int wc_CmacUpdate(Cmac* cmac, const byte* in, word32 inSz)
197
1.23k
{
198
1.23k
    int ret = 0;
199
200
1.23k
    if ((cmac == NULL) || (in == NULL && inSz != 0)) {
201
0
        return BAD_FUNC_ARG;
202
0
    }
203
204
1.23k
#ifdef WOLF_CRYPTO_CB
205
1.23k
    #ifndef WOLF_CRYPTO_CB_FIND
206
1.23k
    if (cmac->devId != INVALID_DEVID)
207
0
    #endif
208
0
    {
209
0
        ret = wc_CryptoCb_Cmac(cmac, NULL, 0, in, inSz,
210
0
            NULL, NULL, (int)cmac->type, NULL);
211
0
        if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
212
0
            return ret;
213
        /* fall-through when unavailable */
214
0
    }
215
1.23k
#endif
216
217
    /* Clear CRYPTOCB_UNAVAILABLE return code */
218
1.23k
    ret = 0;
219
220
1.23k
    switch (cmac->type) {
221
0
#if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT)
222
1.23k
    case WC_CMAC_AES:
223
1.23k
    {
224
2.92k
        while ((ret == 0) && (inSz != 0)) {
225
1.69k
            word32 add = min(inSz, WC_AES_BLOCK_SIZE - cmac->bufferSz);
226
1.69k
            XMEMCPY(&cmac->buffer[cmac->bufferSz], in, add);
227
228
1.69k
            cmac->bufferSz += add;
229
1.69k
            in += add;
230
1.69k
            inSz -= add;
231
232
1.69k
            if (cmac->bufferSz == WC_AES_BLOCK_SIZE && inSz != 0) {
233
1.39k
                if (cmac->totalSz != 0) {
234
1.34k
                    xorbuf(cmac->buffer, cmac->digest, WC_AES_BLOCK_SIZE);
235
1.34k
                }
236
1.39k
                ret = wc_AesEncryptDirect(&cmac->aes, cmac->digest,
237
1.39k
                        cmac->buffer);
238
1.39k
                if (ret == 0) {
239
1.39k
                    cmac->totalSz += WC_AES_BLOCK_SIZE;
240
1.39k
                    cmac->bufferSz = 0;
241
1.39k
                }
242
1.39k
            }
243
1.69k
        }
244
1.23k
    }; break;
245
0
#endif /* !NO_AES && WOLFSSL_AES_DIRECT */
246
0
    default:
247
0
        ret = BAD_FUNC_ARG;
248
1.23k
    }
249
1.23k
    return ret;
250
1.23k
}
251
252
int wc_CmacFree(Cmac* cmac)
253
233
{
254
233
    if (cmac == NULL)
255
0
        return BAD_FUNC_ARG;
256
#if defined(WOLFSSL_HASH_KEEP)
257
    /* TODO: msg is leaked if wc_CmacFinal() is not called
258
     * e.g. when multiple calls to wc_CmacUpdate() and one fails but
259
     * wc_CmacFinal() not called. */
260
    XFREE(cmac->msg, cmac->heap, DYNAMIC_TYPE_TMP_BUFFER);
261
#endif
262
233
    switch (cmac->type) {
263
0
#if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT)
264
233
    case WC_CMAC_AES:
265
233
        wc_AesFree(&cmac->aes);
266
233
        break;
267
0
#endif /* !NO_AES && WOLFSSL_AES_DIRECT */
268
0
    default:
269
        /* Nothing to do */
270
0
        (void)cmac;
271
233
    }
272
233
    ForceZero(cmac, sizeof(Cmac));
273
233
    return 0;
274
233
}
275
276
int wc_CmacFinalNoFree(Cmac* cmac, byte* out, word32* outSz)
277
233
{
278
233
    int ret = 0;
279
280
233
    if (cmac == NULL || out == NULL || outSz == NULL) {
281
0
        return BAD_FUNC_ARG;
282
0
    }
283
233
    if (*outSz < WC_CMAC_TAG_MIN_SZ || *outSz > WC_CMAC_TAG_MAX_SZ) {
284
0
        return BUFFER_E;
285
0
    }
286
287
233
#ifdef WOLF_CRYPTO_CB
288
233
    #ifndef WOLF_CRYPTO_CB_FIND
289
233
    if (cmac->devId != INVALID_DEVID)
290
0
    #endif
291
0
    {
292
0
        ret = wc_CryptoCb_Cmac(cmac, NULL, 0, NULL, 0, out, outSz,
293
0
            (int)cmac->type, NULL);
294
0
        if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
295
0
            return ret;
296
297
        /* Clear CRYPTOCB_UNAVAILABLE return code */
298
0
       ret = 0;
299
300
        /* fall-through when unavailable */
301
0
    }
302
233
#endif
303
233
    if (ret == 0) {
304
233
        switch (cmac->type) {
305
0
    #if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT)
306
233
        case WC_CMAC_AES:
307
233
        {
308
233
            const byte* subKey;
309
233
            word32 remainder;
310
311
233
            if (cmac->bufferSz == WC_AES_BLOCK_SIZE) {
312
17
                subKey = cmac->k1;
313
17
            }
314
216
            else {
315
                /* ensure we will have a valid remainder value */
316
216
                if (cmac->bufferSz > WC_AES_BLOCK_SIZE) {
317
0
                    ret = BAD_STATE_E;
318
0
                    break;
319
0
                }
320
216
                remainder = WC_AES_BLOCK_SIZE - cmac->bufferSz;
321
322
216
                if (remainder == 0) {
323
0
                    remainder = WC_AES_BLOCK_SIZE;
324
0
                }
325
216
                if (remainder > 1) {
326
210
                    XMEMSET(cmac->buffer + WC_AES_BLOCK_SIZE - remainder, 0,
327
210
                            remainder);
328
210
                }
329
330
216
                cmac->buffer[WC_AES_BLOCK_SIZE - remainder] = 0x80;
331
216
                subKey = cmac->k2;
332
216
            }
333
233
            xorbuf(cmac->buffer, cmac->digest, WC_AES_BLOCK_SIZE);
334
233
            xorbuf(cmac->buffer, subKey, WC_AES_BLOCK_SIZE);
335
233
            ret = wc_AesEncryptDirect(&cmac->aes, cmac->digest, cmac->buffer);
336
233
            if (ret == 0) {
337
233
                XMEMCPY(out, cmac->digest, *outSz);
338
233
            }
339
233
        }; break;
340
0
    #endif /* !NO_AES && WOLFSSL_AES_DIRECT */
341
0
        default:
342
0
            ret = BAD_FUNC_ARG;
343
233
        }
344
233
    }
345
233
    return ret;
346
233
}
347
348
int wc_CmacFinal(Cmac* cmac, byte* out, word32* outSz)
349
233
{
350
233
    int ret = 0;
351
352
233
    if (cmac == NULL)
353
0
        return BAD_FUNC_ARG;
354
233
    ret = wc_CmacFinalNoFree(cmac, out, outSz);
355
233
    (void)wc_CmacFree(cmac);
356
233
    return ret;
357
233
}
358
359
#if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT)
360
int wc_AesCmacGenerate_ex(Cmac* cmac,
361
                          byte* out, word32* outSz,
362
                          const byte* in, word32 inSz,
363
                          const byte* key, word32 keySz,
364
                          void* heap, int devId)
365
0
{
366
0
    int ret = 0;
367
368
0
    if (cmac == NULL) {
369
0
        return BAD_FUNC_ARG;
370
0
    }
371
372
0
#ifdef WOLF_CRYPTO_CB
373
    /* Set devId regardless of value (invalid or not) */
374
0
    cmac->devId = devId;
375
0
    #ifndef WOLF_CRYPTO_CB_FIND
376
0
    if (devId != INVALID_DEVID)
377
0
    #endif
378
0
    {
379
0
        ret = wc_CryptoCb_Cmac(cmac, key, keySz, in, inSz, out, outSz,
380
0
                WC_CMAC_AES, NULL);
381
0
        if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
382
0
            return ret;
383
384
         /* Clear CRYPTOCB_UNAVAILABLE return code */
385
0
        ret = 0;
386
387
        /* fall-through when unavailable */
388
0
    }
389
0
#endif
390
391
0
    if ( ((out == NULL) && (outSz != NULL) && (*outSz > 0))
392
0
         || (in == NULL && inSz > 0)
393
0
         || (key == NULL && keySz > 0))  {
394
0
        return BAD_FUNC_ARG;
395
0
    }
396
397
    /* Init step is optional */
398
0
    if (key != NULL) {
399
0
        ret = wc_InitCmac_ex(cmac, key, keySz, WC_CMAC_AES, NULL, heap, devId);
400
0
    }
401
0
    if (ret == 0) {
402
0
        ret = wc_CmacUpdate(cmac, in, inSz);
403
        /* Ensure we are freed and zeroed if not calling wc_CmacFinal */
404
0
        if (ret != 0) {
405
0
            (void)wc_CmacFree(cmac);
406
0
        }
407
0
    }
408
0
    if (ret == 0) {
409
0
        ret = wc_CmacFinal(cmac, out, outSz);
410
0
    }
411
412
0
    return ret;
413
0
}
414
415
416
int wc_AesCmacGenerate(byte* out, word32* outSz,
417
                       const byte* in, word32 inSz,
418
                       const byte* key, word32 keySz)
419
0
{
420
0
    int ret = 0;
421
0
#ifdef WOLFSSL_SMALL_STACK
422
0
    Cmac *cmac;
423
#else
424
    Cmac cmac[1];
425
#endif
426
427
0
    if (out == NULL || (in == NULL && inSz > 0) || key == NULL || keySz == 0) {
428
0
        return BAD_FUNC_ARG;
429
0
    }
430
431
0
#ifdef WOLFSSL_SMALL_STACK
432
0
    if ((cmac = (Cmac *)XMALLOC(sizeof *cmac, NULL,
433
0
                                DYNAMIC_TYPE_CMAC)) == NULL) {
434
0
        return MEMORY_E;
435
0
    }
436
0
#endif
437
438
#ifdef WOLFSSL_CHECK_MEM_ZERO
439
    XMEMSET(((unsigned char *)cmac) + sizeof(Aes), 0xff,
440
        sizeof(Cmac) - sizeof(Aes));
441
    /* Aes part is checked by wc_AesFree. */
442
    wc_MemZero_Add("wc_AesCmacGenerate_ex cmac",
443
        ((unsigned char *)cmac) + sizeof(Aes), sizeof(Cmac) - sizeof(Aes));
444
#endif
445
446
0
    ret = wc_AesCmacGenerate_ex(cmac,
447
0
                                out, outSz,
448
0
                                in, inSz,
449
0
                                key, keySz,
450
0
                                NULL,
451
0
                                INVALID_DEVID);
452
453
454
0
#ifdef WOLFSSL_SMALL_STACK
455
0
    XFREE(cmac, NULL, DYNAMIC_TYPE_CMAC);
456
#elif defined(WOLFSSL_CHECK_MEM_ZERO)
457
    wc_MemZero_Check(cmac, sizeof(Cmac));
458
#endif
459
460
0
    return ret;
461
0
}
462
463
464
int wc_AesCmacVerify_ex(Cmac* cmac,
465
                        const byte* check, word32 checkSz,
466
                        const byte* in, word32 inSz,
467
                        const byte* key, word32 keySz,
468
                        void* heap, int devId)
469
0
{
470
0
    int ret = 0;
471
0
    byte a[WC_AES_BLOCK_SIZE];
472
0
    word32 aSz = sizeof(a);
473
0
    int compareRet;
474
475
0
    if (cmac == NULL || check == NULL || checkSz == 0 ||
476
0
            (in == NULL && inSz != 0)) {
477
0
        return BAD_FUNC_ARG;
478
0
    }
479
480
0
    XMEMSET(a, 0, aSz);
481
0
    ret = wc_AesCmacGenerate_ex(cmac,
482
0
                                a, &aSz,
483
0
                                in, inSz,
484
0
                                key, keySz,
485
0
                                heap,
486
0
                                devId);
487
0
    if (ret == 0) {
488
0
        compareRet = ConstantCompare(check, a, (int)min(checkSz, aSz));
489
0
        ret = compareRet ? 1 : 0;
490
0
    }
491
492
0
    return ret;
493
0
}
494
495
496
int wc_AesCmacVerify(const byte* check, word32 checkSz,
497
                     const byte* in, word32 inSz,
498
                     const byte* key, word32 keySz)
499
0
{
500
0
    int ret = 0;
501
0
#ifdef WOLFSSL_SMALL_STACK
502
0
    Cmac *cmac;
503
#else
504
    Cmac cmac[1];
505
#endif
506
507
0
    if (check == NULL || checkSz == 0 || (in == NULL && inSz > 0) ||
508
0
            key == NULL || keySz == 0) {
509
0
        return BAD_FUNC_ARG;
510
0
    }
511
512
0
#ifdef WOLFSSL_SMALL_STACK
513
0
    if ((cmac = (Cmac *)XMALLOC(sizeof *cmac, NULL,
514
0
                                DYNAMIC_TYPE_CMAC)) == NULL) {
515
0
        return MEMORY_E;
516
0
    }
517
0
#endif
518
519
#ifdef WOLFSSL_CHECK_MEM_ZERO
520
    XMEMSET(((unsigned char *)cmac) + sizeof(Aes), 0xff,
521
        sizeof(Cmac) - sizeof(Aes));
522
    /* Aes part is checked by wc_AesFree. */
523
    wc_MemZero_Add("wc_AesCmacGenerate_ex cmac",
524
        ((unsigned char *)cmac) + sizeof(Aes), sizeof(Cmac) - sizeof(Aes));
525
#endif
526
527
0
    ret = wc_AesCmacVerify_ex(cmac,
528
0
                              check, checkSz,
529
0
                              in, inSz,
530
0
                              key, keySz,
531
0
                              NULL,
532
0
                              INVALID_DEVID);
533
534
0
#ifdef WOLFSSL_SMALL_STACK
535
0
    XFREE(cmac, NULL, DYNAMIC_TYPE_CMAC);
536
#elif defined(WOLFSSL_CHECK_MEM_ZERO)
537
    wc_MemZero_Check(cmac, sizeof(Cmac));
538
#endif
539
540
0
    return ret;
541
0
}
542
#endif /* !NO_AES && WOLFSSL_AES_DIRECT */
543
544
#endif /* WOLFSSL_CMAC */