xref: /optee_os/lib/libmbedtls/mbedtls/library/ccm.c (revision b0563631928755fe864b97785160fb3088e9efdc)
1817466cbSJens Wiklander /*
2817466cbSJens Wiklander  *  NIST SP800-38C compliant CCM implementation
3817466cbSJens Wiklander  *
47901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
5*b0563631STom Van Eyck  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6817466cbSJens Wiklander  */
7817466cbSJens Wiklander 
8817466cbSJens Wiklander /*
9817466cbSJens Wiklander  * Definition of CCM:
10817466cbSJens Wiklander  * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
11817466cbSJens Wiklander  * RFC 3610 "Counter with CBC-MAC (CCM)"
12817466cbSJens Wiklander  *
13817466cbSJens Wiklander  * Related:
14817466cbSJens Wiklander  * RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
15817466cbSJens Wiklander  */
16817466cbSJens Wiklander 
177901324dSJerome Forissier #include "common.h"
18817466cbSJens Wiklander 
19817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C)
20817466cbSJens Wiklander 
21817466cbSJens Wiklander #include "mbedtls/ccm.h"
223d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
2311fa71b9SJerome Forissier #include "mbedtls/error.h"
24*b0563631STom Van Eyck #include "mbedtls/constant_time.h"
25*b0563631STom Van Eyck 
26*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
27*b0563631STom Van Eyck #include "block_cipher_internal.h"
28*b0563631STom Van Eyck #endif
29817466cbSJens Wiklander 
30817466cbSJens Wiklander #include <string.h>
31817466cbSJens Wiklander 
32817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
33817466cbSJens Wiklander #include "mbedtls/platform.h"
34817466cbSJens Wiklander #else
3532b31808SJens Wiklander #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
36817466cbSJens Wiklander #include <stdio.h>
37817466cbSJens Wiklander #define mbedtls_printf printf
38817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
3932b31808SJens Wiklander #endif /* MBEDTLS_PLATFORM_C */
40817466cbSJens Wiklander 
413d3b0591SJens Wiklander #if !defined(MBEDTLS_CCM_ALT)
423d3b0591SJens Wiklander 
43817466cbSJens Wiklander 
44817466cbSJens Wiklander /*
45817466cbSJens Wiklander  * Initialize context
46817466cbSJens Wiklander  */
47817466cbSJens Wiklander void mbedtls_ccm_init(mbedtls_ccm_context *ctx)
48817466cbSJens Wiklander {
49817466cbSJens Wiklander     memset(ctx, 0, sizeof(mbedtls_ccm_context));
50817466cbSJens Wiklander }
51817466cbSJens Wiklander 
52817466cbSJens Wiklander int mbedtls_ccm_setkey(mbedtls_ccm_context *ctx,
53817466cbSJens Wiklander                        mbedtls_cipher_id_t cipher,
54817466cbSJens Wiklander                        const unsigned char *key,
55817466cbSJens Wiklander                        unsigned int keybits)
56817466cbSJens Wiklander {
5711fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
58*b0563631STom Van Eyck 
59*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
60*b0563631STom Van Eyck     mbedtls_block_cipher_free(&ctx->block_cipher_ctx);
61*b0563631STom Van Eyck 
62*b0563631STom Van Eyck     if ((ret = mbedtls_block_cipher_setup(&ctx->block_cipher_ctx, cipher)) != 0) {
63*b0563631STom Van Eyck         return MBEDTLS_ERR_CCM_BAD_INPUT;
64*b0563631STom Van Eyck     }
65*b0563631STom Van Eyck 
66*b0563631STom Van Eyck     if ((ret = mbedtls_block_cipher_setkey(&ctx->block_cipher_ctx, key, keybits)) != 0) {
67*b0563631STom Van Eyck         return MBEDTLS_ERR_CCM_BAD_INPUT;
68*b0563631STom Van Eyck     }
69*b0563631STom Van Eyck #else
70817466cbSJens Wiklander     const mbedtls_cipher_info_t *cipher_info;
71817466cbSJens Wiklander 
7211fa71b9SJerome Forissier     cipher_info = mbedtls_cipher_info_from_values(cipher, keybits,
7311fa71b9SJerome Forissier                                                   MBEDTLS_MODE_ECB);
7432b31808SJens Wiklander     if (cipher_info == NULL) {
7532b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
7632b31808SJens Wiklander     }
77817466cbSJens Wiklander 
78*b0563631STom Van Eyck     if (mbedtls_cipher_info_get_block_size(cipher_info) != 16) {
7932b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
8032b31808SJens Wiklander     }
81817466cbSJens Wiklander 
82817466cbSJens Wiklander     mbedtls_cipher_free(&ctx->cipher_ctx);
83817466cbSJens Wiklander 
8432b31808SJens Wiklander     if ((ret = mbedtls_cipher_setup(&ctx->cipher_ctx, cipher_info)) != 0) {
8532b31808SJens Wiklander         return ret;
86817466cbSJens Wiklander     }
87817466cbSJens Wiklander 
8832b31808SJens Wiklander     if ((ret = mbedtls_cipher_setkey(&ctx->cipher_ctx, key, keybits,
8932b31808SJens Wiklander                                      MBEDTLS_ENCRYPT)) != 0) {
9032b31808SJens Wiklander         return ret;
9132b31808SJens Wiklander     }
92*b0563631STom Van Eyck #endif
9332b31808SJens Wiklander 
94*b0563631STom Van Eyck     return ret;
95817466cbSJens Wiklander }
96817466cbSJens Wiklander 
97817466cbSJens Wiklander /*
98817466cbSJens Wiklander  * Free context
99817466cbSJens Wiklander  */
100817466cbSJens Wiklander void mbedtls_ccm_free(mbedtls_ccm_context *ctx)
101817466cbSJens Wiklander {
10232b31808SJens Wiklander     if (ctx == NULL) {
1033d3b0591SJens Wiklander         return;
10432b31808SJens Wiklander     }
105*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
106*b0563631STom Van Eyck     mbedtls_block_cipher_free(&ctx->block_cipher_ctx);
107*b0563631STom Van Eyck #else
108817466cbSJens Wiklander     mbedtls_cipher_free(&ctx->cipher_ctx);
109*b0563631STom Van Eyck #endif
1103d3b0591SJens Wiklander     mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ccm_context));
111817466cbSJens Wiklander }
112817466cbSJens Wiklander 
11332b31808SJens Wiklander #define CCM_STATE__CLEAR                0
11432b31808SJens Wiklander #define CCM_STATE__STARTED              (1 << 0)
11532b31808SJens Wiklander #define CCM_STATE__LENGTHS_SET          (1 << 1)
11632b31808SJens Wiklander #define CCM_STATE__AUTH_DATA_STARTED    (1 << 2)
11732b31808SJens Wiklander #define CCM_STATE__AUTH_DATA_FINISHED   (1 << 3)
11832b31808SJens Wiklander #define CCM_STATE__ERROR                (1 << 4)
119817466cbSJens Wiklander 
120817466cbSJens Wiklander /*
121817466cbSJens Wiklander  * Encrypt or decrypt a partial block with CTR
122817466cbSJens Wiklander  */
12332b31808SJens Wiklander static int mbedtls_ccm_crypt(mbedtls_ccm_context *ctx,
12432b31808SJens Wiklander                              size_t offset, size_t use_len,
12532b31808SJens Wiklander                              const unsigned char *input,
12632b31808SJens Wiklander                              unsigned char *output)
12732b31808SJens Wiklander {
12832b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
12932b31808SJens Wiklander     unsigned char tmp_buf[16] = { 0 };
130817466cbSJens Wiklander 
131*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
132*b0563631STom Van Eyck     ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->ctr, tmp_buf);
133*b0563631STom Van Eyck #else
134*b0563631STom Van Eyck     size_t olen = 0;
135*b0563631STom Van Eyck     ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->ctr, 16, tmp_buf, &olen);
136*b0563631STom Van Eyck #endif
137*b0563631STom Van Eyck     if (ret != 0) {
13832b31808SJens Wiklander         ctx->state |= CCM_STATE__ERROR;
13932b31808SJens Wiklander         mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
14032b31808SJens Wiklander         return ret;
14132b31808SJens Wiklander     }
14232b31808SJens Wiklander 
14332b31808SJens Wiklander     mbedtls_xor(output, input, tmp_buf + offset, use_len);
14432b31808SJens Wiklander 
14532b31808SJens Wiklander     mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
14632b31808SJens Wiklander     return ret;
14732b31808SJens Wiklander }
14832b31808SJens Wiklander 
14932b31808SJens Wiklander static void mbedtls_ccm_clear_state(mbedtls_ccm_context *ctx)
15032b31808SJens Wiklander {
15132b31808SJens Wiklander     ctx->state = CCM_STATE__CLEAR;
15232b31808SJens Wiklander     memset(ctx->y, 0, 16);
15332b31808SJens Wiklander     memset(ctx->ctr, 0, 16);
15432b31808SJens Wiklander }
15532b31808SJens Wiklander 
15632b31808SJens Wiklander static int ccm_calculate_first_block_if_ready(mbedtls_ccm_context *ctx)
157817466cbSJens Wiklander {
15811fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
159817466cbSJens Wiklander     unsigned char i;
160*b0563631STom Van Eyck     size_t len_left;
161*b0563631STom Van Eyck #if !defined(MBEDTLS_BLOCK_CIPHER_C)
162*b0563631STom Van Eyck     size_t olen;
163*b0563631STom Van Eyck #endif
164817466cbSJens Wiklander 
16532b31808SJens Wiklander     /* length calculation can be done only after both
16632b31808SJens Wiklander      * mbedtls_ccm_starts() and mbedtls_ccm_set_lengths() have been executed
167817466cbSJens Wiklander      */
16832b31808SJens Wiklander     if (!(ctx->state & CCM_STATE__STARTED) || !(ctx->state & CCM_STATE__LENGTHS_SET)) {
16932b31808SJens Wiklander         return 0;
17032b31808SJens Wiklander     }
171817466cbSJens Wiklander 
17232b31808SJens Wiklander     /* CCM expects non-empty tag.
17332b31808SJens Wiklander      * CCM* allows empty tag. For CCM* without tag, ignore plaintext length.
17432b31808SJens Wiklander      */
17532b31808SJens Wiklander     if (ctx->tag_len == 0) {
17632b31808SJens Wiklander         if (ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT || ctx->mode == MBEDTLS_CCM_STAR_DECRYPT) {
17732b31808SJens Wiklander             ctx->plaintext_len = 0;
17832b31808SJens Wiklander         } else {
17932b31808SJens Wiklander             return MBEDTLS_ERR_CCM_BAD_INPUT;
18032b31808SJens Wiklander         }
18132b31808SJens Wiklander     }
182817466cbSJens Wiklander 
183817466cbSJens Wiklander     /*
18432b31808SJens Wiklander      * First block:
185817466cbSJens Wiklander      * 0        .. 0        flags
18632b31808SJens Wiklander      * 1        .. iv_len   nonce (aka iv)  - set by: mbedtls_ccm_starts()
187817466cbSJens Wiklander      * iv_len+1 .. 15       length
188817466cbSJens Wiklander      *
189817466cbSJens Wiklander      * With flags as (bits):
190817466cbSJens Wiklander      * 7        0
191817466cbSJens Wiklander      * 6        add present?
192817466cbSJens Wiklander      * 5 .. 3   (t - 2) / 2
193817466cbSJens Wiklander      * 2 .. 0   q - 1
194817466cbSJens Wiklander      */
19532b31808SJens Wiklander     ctx->y[0] |= (ctx->add_len > 0) << 6;
19632b31808SJens Wiklander     ctx->y[0] |= ((ctx->tag_len - 2) / 2) << 3;
19732b31808SJens Wiklander     ctx->y[0] |= ctx->q - 1;
198817466cbSJens Wiklander 
19932b31808SJens Wiklander     for (i = 0, len_left = ctx->plaintext_len; i < ctx->q; i++, len_left >>= 8) {
20032b31808SJens Wiklander         ctx->y[15-i] = MBEDTLS_BYTE_0(len_left);
20132b31808SJens Wiklander     }
202817466cbSJens Wiklander 
20332b31808SJens Wiklander     if (len_left > 0) {
20432b31808SJens Wiklander         ctx->state |= CCM_STATE__ERROR;
20532b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
20632b31808SJens Wiklander     }
207817466cbSJens Wiklander 
208817466cbSJens Wiklander     /* Start CBC-MAC with first block*/
209*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
210*b0563631STom Van Eyck     ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
211*b0563631STom Van Eyck #else
212*b0563631STom Van Eyck     ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
213*b0563631STom Van Eyck #endif
214*b0563631STom Van Eyck     if (ret != 0) {
21532b31808SJens Wiklander         ctx->state |= CCM_STATE__ERROR;
21632b31808SJens Wiklander         return ret;
217817466cbSJens Wiklander     }
21832b31808SJens Wiklander 
21932b31808SJens Wiklander     return 0;
220817466cbSJens Wiklander }
221817466cbSJens Wiklander 
22232b31808SJens Wiklander int mbedtls_ccm_starts(mbedtls_ccm_context *ctx,
22332b31808SJens Wiklander                        int mode,
22432b31808SJens Wiklander                        const unsigned char *iv,
22532b31808SJens Wiklander                        size_t iv_len)
22632b31808SJens Wiklander {
22732b31808SJens Wiklander     /* Also implies q is within bounds */
22832b31808SJens Wiklander     if (iv_len < 7 || iv_len > 13) {
22932b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
23032b31808SJens Wiklander     }
23132b31808SJens Wiklander 
23232b31808SJens Wiklander     ctx->mode = mode;
23332b31808SJens Wiklander     ctx->q = 16 - 1 - (unsigned char) iv_len;
23432b31808SJens Wiklander 
235817466cbSJens Wiklander     /*
236817466cbSJens Wiklander      * Prepare counter block for encryption:
237817466cbSJens Wiklander      * 0        .. 0        flags
238817466cbSJens Wiklander      * 1        .. iv_len   nonce (aka iv)
239817466cbSJens Wiklander      * iv_len+1 .. 15       counter (initially 1)
240817466cbSJens Wiklander      *
241817466cbSJens Wiklander      * With flags as (bits):
242817466cbSJens Wiklander      * 7 .. 3   0
243817466cbSJens Wiklander      * 2 .. 0   q - 1
244817466cbSJens Wiklander      */
24532b31808SJens Wiklander     memset(ctx->ctr, 0, 16);
24632b31808SJens Wiklander     ctx->ctr[0] = ctx->q - 1;
24732b31808SJens Wiklander     memcpy(ctx->ctr + 1, iv, iv_len);
24832b31808SJens Wiklander     memset(ctx->ctr + 1 + iv_len, 0, ctx->q);
24932b31808SJens Wiklander     ctx->ctr[15] = 1;
250817466cbSJens Wiklander 
251817466cbSJens Wiklander     /*
25232b31808SJens Wiklander      * See ccm_calculate_first_block_if_ready() for block layout description
25332b31808SJens Wiklander      */
25432b31808SJens Wiklander     memcpy(ctx->y + 1, iv, iv_len);
25532b31808SJens Wiklander 
25632b31808SJens Wiklander     ctx->state |= CCM_STATE__STARTED;
25732b31808SJens Wiklander     return ccm_calculate_first_block_if_ready(ctx);
25832b31808SJens Wiklander }
25932b31808SJens Wiklander 
26032b31808SJens Wiklander int mbedtls_ccm_set_lengths(mbedtls_ccm_context *ctx,
26132b31808SJens Wiklander                             size_t total_ad_len,
26232b31808SJens Wiklander                             size_t plaintext_len,
26332b31808SJens Wiklander                             size_t tag_len)
26432b31808SJens Wiklander {
26532b31808SJens Wiklander     /*
26632b31808SJens Wiklander      * Check length requirements: SP800-38C A.1
26732b31808SJens Wiklander      * Additional requirement: a < 2^16 - 2^8 to simplify the code.
26832b31808SJens Wiklander      * 'length' checked later (when writing it to the first block)
269817466cbSJens Wiklander      *
27032b31808SJens Wiklander      * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4).
271817466cbSJens Wiklander      */
27232b31808SJens Wiklander     if (tag_len == 2 || tag_len > 16 || tag_len % 2 != 0) {
27332b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
274817466cbSJens Wiklander     }
275817466cbSJens Wiklander 
27632b31808SJens Wiklander     if (total_ad_len >= 0xFF00) {
27732b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
278817466cbSJens Wiklander     }
279817466cbSJens Wiklander 
28032b31808SJens Wiklander     ctx->plaintext_len = plaintext_len;
28132b31808SJens Wiklander     ctx->add_len = total_ad_len;
28232b31808SJens Wiklander     ctx->tag_len = tag_len;
28332b31808SJens Wiklander     ctx->processed = 0;
284817466cbSJens Wiklander 
28532b31808SJens Wiklander     ctx->state |= CCM_STATE__LENGTHS_SET;
28632b31808SJens Wiklander     return ccm_calculate_first_block_if_ready(ctx);
28732b31808SJens Wiklander }
28832b31808SJens Wiklander 
28932b31808SJens Wiklander int mbedtls_ccm_update_ad(mbedtls_ccm_context *ctx,
29032b31808SJens Wiklander                           const unsigned char *add,
29132b31808SJens Wiklander                           size_t add_len)
29232b31808SJens Wiklander {
29332b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
294*b0563631STom Van Eyck     size_t use_len, offset;
295*b0563631STom Van Eyck #if !defined(MBEDTLS_BLOCK_CIPHER_C)
296*b0563631STom Van Eyck     size_t olen;
297*b0563631STom Van Eyck #endif
29832b31808SJens Wiklander 
29932b31808SJens Wiklander     if (ctx->state & CCM_STATE__ERROR) {
30032b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
30132b31808SJens Wiklander     }
30232b31808SJens Wiklander 
30332b31808SJens Wiklander     if (add_len > 0) {
30432b31808SJens Wiklander         if (ctx->state & CCM_STATE__AUTH_DATA_FINISHED) {
30532b31808SJens Wiklander             return MBEDTLS_ERR_CCM_BAD_INPUT;
30632b31808SJens Wiklander         }
30732b31808SJens Wiklander 
30832b31808SJens Wiklander         if (!(ctx->state & CCM_STATE__AUTH_DATA_STARTED)) {
30932b31808SJens Wiklander             if (add_len > ctx->add_len) {
31032b31808SJens Wiklander                 return MBEDTLS_ERR_CCM_BAD_INPUT;
31132b31808SJens Wiklander             }
31232b31808SJens Wiklander 
31332b31808SJens Wiklander             ctx->y[0] ^= (unsigned char) ((ctx->add_len >> 8) & 0xFF);
31432b31808SJens Wiklander             ctx->y[1] ^= (unsigned char) ((ctx->add_len) & 0xFF);
31532b31808SJens Wiklander 
31632b31808SJens Wiklander             ctx->state |= CCM_STATE__AUTH_DATA_STARTED;
31732b31808SJens Wiklander         } else if (ctx->processed + add_len > ctx->add_len) {
31832b31808SJens Wiklander             return MBEDTLS_ERR_CCM_BAD_INPUT;
31932b31808SJens Wiklander         }
32032b31808SJens Wiklander 
32132b31808SJens Wiklander         while (add_len > 0) {
32232b31808SJens Wiklander             offset = (ctx->processed + 2) % 16; /* account for y[0] and y[1]
32332b31808SJens Wiklander                                                  * holding total auth data length */
32432b31808SJens Wiklander             use_len = 16 - offset;
32532b31808SJens Wiklander 
32632b31808SJens Wiklander             if (use_len > add_len) {
32732b31808SJens Wiklander                 use_len = add_len;
32832b31808SJens Wiklander             }
32932b31808SJens Wiklander 
33032b31808SJens Wiklander             mbedtls_xor(ctx->y + offset, ctx->y + offset, add, use_len);
33132b31808SJens Wiklander 
33232b31808SJens Wiklander             ctx->processed += use_len;
33332b31808SJens Wiklander             add_len -= use_len;
33432b31808SJens Wiklander             add += use_len;
33532b31808SJens Wiklander 
33632b31808SJens Wiklander             if (use_len + offset == 16 || ctx->processed == ctx->add_len) {
337*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
338*b0563631STom Van Eyck                 ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
339*b0563631STom Van Eyck #else
340*b0563631STom Van Eyck                 ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
341*b0563631STom Van Eyck #endif
342*b0563631STom Van Eyck                 if (ret != 0) {
34332b31808SJens Wiklander                     ctx->state |= CCM_STATE__ERROR;
34432b31808SJens Wiklander                     return ret;
34532b31808SJens Wiklander                 }
34632b31808SJens Wiklander             }
34732b31808SJens Wiklander         }
34832b31808SJens Wiklander 
34932b31808SJens Wiklander         if (ctx->processed == ctx->add_len) {
35032b31808SJens Wiklander             ctx->state |= CCM_STATE__AUTH_DATA_FINISHED;
35132b31808SJens Wiklander             ctx->processed = 0; // prepare for mbedtls_ccm_update()
35232b31808SJens Wiklander         }
35332b31808SJens Wiklander     }
35432b31808SJens Wiklander 
35532b31808SJens Wiklander     return 0;
35632b31808SJens Wiklander }
35732b31808SJens Wiklander 
35832b31808SJens Wiklander int mbedtls_ccm_update(mbedtls_ccm_context *ctx,
35932b31808SJens Wiklander                        const unsigned char *input, size_t input_len,
36032b31808SJens Wiklander                        unsigned char *output, size_t output_size,
36132b31808SJens Wiklander                        size_t *output_len)
36232b31808SJens Wiklander {
36332b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
36432b31808SJens Wiklander     unsigned char i;
365*b0563631STom Van Eyck     size_t use_len, offset;
366*b0563631STom Van Eyck #if !defined(MBEDTLS_BLOCK_CIPHER_C)
367*b0563631STom Van Eyck     size_t olen;
368*b0563631STom Van Eyck #endif
36932b31808SJens Wiklander 
37032b31808SJens Wiklander     unsigned char local_output[16];
37132b31808SJens Wiklander 
37232b31808SJens Wiklander     if (ctx->state & CCM_STATE__ERROR) {
37332b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
37432b31808SJens Wiklander     }
37532b31808SJens Wiklander 
37632b31808SJens Wiklander     /* Check against plaintext length only if performing operation with
37732b31808SJens Wiklander      * authentication
378817466cbSJens Wiklander      */
37932b31808SJens Wiklander     if (ctx->tag_len != 0 && ctx->processed + input_len > ctx->plaintext_len) {
38032b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
38132b31808SJens Wiklander     }
38232b31808SJens Wiklander 
38332b31808SJens Wiklander     if (output_size < input_len) {
38432b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
38532b31808SJens Wiklander     }
38632b31808SJens Wiklander     *output_len = input_len;
38732b31808SJens Wiklander 
38832b31808SJens Wiklander     ret = 0;
38932b31808SJens Wiklander 
39032b31808SJens Wiklander     while (input_len > 0) {
39132b31808SJens Wiklander         offset = ctx->processed % 16;
39232b31808SJens Wiklander 
39332b31808SJens Wiklander         use_len = 16 - offset;
39432b31808SJens Wiklander 
39532b31808SJens Wiklander         if (use_len > input_len) {
39632b31808SJens Wiklander             use_len = input_len;
39732b31808SJens Wiklander         }
39832b31808SJens Wiklander 
39932b31808SJens Wiklander         ctx->processed += use_len;
40032b31808SJens Wiklander 
40132b31808SJens Wiklander         if (ctx->mode == MBEDTLS_CCM_ENCRYPT || \
40232b31808SJens Wiklander             ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT) {
40332b31808SJens Wiklander             mbedtls_xor(ctx->y + offset, ctx->y + offset, input, use_len);
40432b31808SJens Wiklander 
40532b31808SJens Wiklander             if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) {
406*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
407*b0563631STom Van Eyck                 ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
408*b0563631STom Van Eyck #else
409*b0563631STom Van Eyck                 ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
410*b0563631STom Van Eyck #endif
411*b0563631STom Van Eyck                 if (ret != 0) {
41232b31808SJens Wiklander                     ctx->state |= CCM_STATE__ERROR;
41332b31808SJens Wiklander                     goto exit;
41432b31808SJens Wiklander                 }
41532b31808SJens Wiklander             }
41632b31808SJens Wiklander 
41732b31808SJens Wiklander             ret = mbedtls_ccm_crypt(ctx, offset, use_len, input, output);
41832b31808SJens Wiklander             if (ret != 0) {
41932b31808SJens Wiklander                 goto exit;
42032b31808SJens Wiklander             }
42132b31808SJens Wiklander         }
42232b31808SJens Wiklander 
42332b31808SJens Wiklander         if (ctx->mode == MBEDTLS_CCM_DECRYPT || \
42432b31808SJens Wiklander             ctx->mode == MBEDTLS_CCM_STAR_DECRYPT) {
42532b31808SJens Wiklander             /* Since output may be in shared memory, we cannot be sure that
42632b31808SJens Wiklander              * it will contain what we wrote to it. Therefore, we should avoid using
42732b31808SJens Wiklander              * it as input to any operations.
42832b31808SJens Wiklander              * Write decrypted data to local_output to avoid using output variable as
42932b31808SJens Wiklander              * input in the XOR operation for Y.
43032b31808SJens Wiklander              */
43132b31808SJens Wiklander             ret = mbedtls_ccm_crypt(ctx, offset, use_len, input, local_output);
43232b31808SJens Wiklander             if (ret != 0) {
43332b31808SJens Wiklander                 goto exit;
43432b31808SJens Wiklander             }
43532b31808SJens Wiklander 
43632b31808SJens Wiklander             mbedtls_xor(ctx->y + offset, ctx->y + offset, local_output, use_len);
43732b31808SJens Wiklander 
43832b31808SJens Wiklander             memcpy(output, local_output, use_len);
43932b31808SJens Wiklander 
44032b31808SJens Wiklander             if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) {
441*b0563631STom Van Eyck #if defined(MBEDTLS_BLOCK_CIPHER_C)
442*b0563631STom Van Eyck                 ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
443*b0563631STom Van Eyck #else
444*b0563631STom Van Eyck                 ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
445*b0563631STom Van Eyck #endif
446*b0563631STom Van Eyck                 if (ret != 0) {
44732b31808SJens Wiklander                     ctx->state |= CCM_STATE__ERROR;
44832b31808SJens Wiklander                     goto exit;
44932b31808SJens Wiklander                 }
45032b31808SJens Wiklander             }
45132b31808SJens Wiklander         }
45232b31808SJens Wiklander 
45332b31808SJens Wiklander         if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) {
45432b31808SJens Wiklander             for (i = 0; i < ctx->q; i++) {
45532b31808SJens Wiklander                 if (++(ctx->ctr)[15-i] != 0) {
456817466cbSJens Wiklander                     break;
457817466cbSJens Wiklander                 }
45832b31808SJens Wiklander             }
45932b31808SJens Wiklander         }
46032b31808SJens Wiklander 
46132b31808SJens Wiklander         input_len -= use_len;
46232b31808SJens Wiklander         input += use_len;
46332b31808SJens Wiklander         output += use_len;
46432b31808SJens Wiklander     }
46532b31808SJens Wiklander 
46632b31808SJens Wiklander exit:
46732b31808SJens Wiklander     mbedtls_platform_zeroize(local_output, 16);
46832b31808SJens Wiklander 
46932b31808SJens Wiklander     return ret;
47032b31808SJens Wiklander }
47132b31808SJens Wiklander 
47232b31808SJens Wiklander int mbedtls_ccm_finish(mbedtls_ccm_context *ctx,
47332b31808SJens Wiklander                        unsigned char *tag, size_t tag_len)
47432b31808SJens Wiklander {
47532b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
47632b31808SJens Wiklander     unsigned char i;
47732b31808SJens Wiklander 
47832b31808SJens Wiklander     if (ctx->state & CCM_STATE__ERROR) {
47932b31808SJens Wiklander         return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
48032b31808SJens Wiklander     }
48132b31808SJens Wiklander 
48232b31808SJens Wiklander     if (ctx->add_len > 0 && !(ctx->state & CCM_STATE__AUTH_DATA_FINISHED)) {
48332b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
48432b31808SJens Wiklander     }
48532b31808SJens Wiklander 
48632b31808SJens Wiklander     if (ctx->plaintext_len > 0 && ctx->processed != ctx->plaintext_len) {
48732b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
48832b31808SJens Wiklander     }
489817466cbSJens Wiklander 
490817466cbSJens Wiklander     /*
491817466cbSJens Wiklander      * Authentication: reset counter and crypt/mask internal tag
492817466cbSJens Wiklander      */
49332b31808SJens Wiklander     for (i = 0; i < ctx->q; i++) {
49432b31808SJens Wiklander         ctx->ctr[15-i] = 0;
49532b31808SJens Wiklander     }
496817466cbSJens Wiklander 
49732b31808SJens Wiklander     ret = mbedtls_ccm_crypt(ctx, 0, 16, ctx->y, ctx->y);
49832b31808SJens Wiklander     if (ret != 0) {
49932b31808SJens Wiklander         return ret;
50032b31808SJens Wiklander     }
50132b31808SJens Wiklander     if (tag != NULL) {
50232b31808SJens Wiklander         memcpy(tag, ctx->y, tag_len);
50332b31808SJens Wiklander     }
50432b31808SJens Wiklander     mbedtls_ccm_clear_state(ctx);
505817466cbSJens Wiklander 
50632b31808SJens Wiklander     return 0;
50732b31808SJens Wiklander }
50832b31808SJens Wiklander 
50932b31808SJens Wiklander /*
51032b31808SJens Wiklander  * Authenticated encryption or decryption
51132b31808SJens Wiklander  */
51232b31808SJens Wiklander static int ccm_auth_crypt(mbedtls_ccm_context *ctx, int mode, size_t length,
51332b31808SJens Wiklander                           const unsigned char *iv, size_t iv_len,
51432b31808SJens Wiklander                           const unsigned char *add, size_t add_len,
51532b31808SJens Wiklander                           const unsigned char *input, unsigned char *output,
51632b31808SJens Wiklander                           unsigned char *tag, size_t tag_len)
51732b31808SJens Wiklander {
51832b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
51932b31808SJens Wiklander     size_t olen;
52032b31808SJens Wiklander 
52132b31808SJens Wiklander     if ((ret = mbedtls_ccm_starts(ctx, mode, iv, iv_len)) != 0) {
52232b31808SJens Wiklander         return ret;
52332b31808SJens Wiklander     }
52432b31808SJens Wiklander 
52532b31808SJens Wiklander     if ((ret = mbedtls_ccm_set_lengths(ctx, add_len, length, tag_len)) != 0) {
52632b31808SJens Wiklander         return ret;
52732b31808SJens Wiklander     }
52832b31808SJens Wiklander 
52932b31808SJens Wiklander     if ((ret = mbedtls_ccm_update_ad(ctx, add, add_len)) != 0) {
53032b31808SJens Wiklander         return ret;
53132b31808SJens Wiklander     }
53232b31808SJens Wiklander 
53332b31808SJens Wiklander     if ((ret = mbedtls_ccm_update(ctx, input, length,
53432b31808SJens Wiklander                                   output, length, &olen)) != 0) {
53532b31808SJens Wiklander         return ret;
53632b31808SJens Wiklander     }
53732b31808SJens Wiklander 
53832b31808SJens Wiklander     if ((ret = mbedtls_ccm_finish(ctx, tag, tag_len)) != 0) {
53932b31808SJens Wiklander         return ret;
54032b31808SJens Wiklander     }
54132b31808SJens Wiklander 
54232b31808SJens Wiklander     return 0;
543817466cbSJens Wiklander }
544817466cbSJens Wiklander 
545817466cbSJens Wiklander /*
546817466cbSJens Wiklander  * Authenticated encryption
547817466cbSJens Wiklander  */
5483d3b0591SJens Wiklander int mbedtls_ccm_star_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length,
5493d3b0591SJens Wiklander                                      const unsigned char *iv, size_t iv_len,
5503d3b0591SJens Wiklander                                      const unsigned char *add, size_t add_len,
5513d3b0591SJens Wiklander                                      const unsigned char *input, unsigned char *output,
5523d3b0591SJens Wiklander                                      unsigned char *tag, size_t tag_len)
5533d3b0591SJens Wiklander {
55432b31808SJens Wiklander     return ccm_auth_crypt(ctx, MBEDTLS_CCM_STAR_ENCRYPT, length, iv, iv_len,
55532b31808SJens Wiklander                           add, add_len, input, output, tag, tag_len);
5563d3b0591SJens Wiklander }
5573d3b0591SJens Wiklander 
558817466cbSJens Wiklander int mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length,
559817466cbSJens Wiklander                                 const unsigned char *iv, size_t iv_len,
560817466cbSJens Wiklander                                 const unsigned char *add, size_t add_len,
561817466cbSJens Wiklander                                 const unsigned char *input, unsigned char *output,
562817466cbSJens Wiklander                                 unsigned char *tag, size_t tag_len)
563817466cbSJens Wiklander {
56432b31808SJens Wiklander     return ccm_auth_crypt(ctx, MBEDTLS_CCM_ENCRYPT, length, iv, iv_len,
56532b31808SJens Wiklander                           add, add_len, input, output, tag, tag_len);
566817466cbSJens Wiklander }
567817466cbSJens Wiklander 
568817466cbSJens Wiklander /*
569817466cbSJens Wiklander  * Authenticated decryption
570817466cbSJens Wiklander  */
57132b31808SJens Wiklander static int mbedtls_ccm_compare_tags(const unsigned char *tag1,
57232b31808SJens Wiklander                                     const unsigned char *tag2,
57332b31808SJens Wiklander                                     size_t tag_len)
57432b31808SJens Wiklander {
57532b31808SJens Wiklander     /* Check tag in "constant-time" */
576*b0563631STom Van Eyck     int diff = mbedtls_ct_memcmp(tag1, tag2, tag_len);
57732b31808SJens Wiklander 
57832b31808SJens Wiklander     if (diff != 0) {
57932b31808SJens Wiklander         return MBEDTLS_ERR_CCM_AUTH_FAILED;
58032b31808SJens Wiklander     }
58132b31808SJens Wiklander 
58232b31808SJens Wiklander     return 0;
58332b31808SJens Wiklander }
58432b31808SJens Wiklander 
58532b31808SJens Wiklander static int ccm_auth_decrypt(mbedtls_ccm_context *ctx, int mode, size_t length,
586817466cbSJens Wiklander                             const unsigned char *iv, size_t iv_len,
587817466cbSJens Wiklander                             const unsigned char *add, size_t add_len,
588817466cbSJens Wiklander                             const unsigned char *input, unsigned char *output,
589817466cbSJens Wiklander                             const unsigned char *tag, size_t tag_len)
590817466cbSJens Wiklander {
59111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
592817466cbSJens Wiklander     unsigned char check_tag[16];
593817466cbSJens Wiklander 
59432b31808SJens Wiklander     if ((ret = ccm_auth_crypt(ctx, mode, length,
595817466cbSJens Wiklander                               iv, iv_len, add, add_len,
59632b31808SJens Wiklander                               input, output, check_tag, tag_len)) != 0) {
59732b31808SJens Wiklander         return ret;
598817466cbSJens Wiklander     }
599817466cbSJens Wiklander 
60032b31808SJens Wiklander     if ((ret = mbedtls_ccm_compare_tags(tag, check_tag, tag_len)) != 0) {
6013d3b0591SJens Wiklander         mbedtls_platform_zeroize(output, length);
60232b31808SJens Wiklander         return ret;
603817466cbSJens Wiklander     }
604817466cbSJens Wiklander 
60532b31808SJens Wiklander     return 0;
60632b31808SJens Wiklander }
60732b31808SJens Wiklander 
60832b31808SJens Wiklander int mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context *ctx, size_t length,
60932b31808SJens Wiklander                                   const unsigned char *iv, size_t iv_len,
61032b31808SJens Wiklander                                   const unsigned char *add, size_t add_len,
61132b31808SJens Wiklander                                   const unsigned char *input, unsigned char *output,
61232b31808SJens Wiklander                                   const unsigned char *tag, size_t tag_len)
61332b31808SJens Wiklander {
61432b31808SJens Wiklander     return ccm_auth_decrypt(ctx, MBEDTLS_CCM_STAR_DECRYPT, length,
61532b31808SJens Wiklander                             iv, iv_len, add, add_len,
61632b31808SJens Wiklander                             input, output, tag, tag_len);
617817466cbSJens Wiklander }
618817466cbSJens Wiklander 
6193d3b0591SJens Wiklander int mbedtls_ccm_auth_decrypt(mbedtls_ccm_context *ctx, size_t length,
6203d3b0591SJens Wiklander                              const unsigned char *iv, size_t iv_len,
6213d3b0591SJens Wiklander                              const unsigned char *add, size_t add_len,
6223d3b0591SJens Wiklander                              const unsigned char *input, unsigned char *output,
6233d3b0591SJens Wiklander                              const unsigned char *tag, size_t tag_len)
6243d3b0591SJens Wiklander {
62532b31808SJens Wiklander     return ccm_auth_decrypt(ctx, MBEDTLS_CCM_DECRYPT, length,
62632b31808SJens Wiklander                             iv, iv_len, add, add_len,
62732b31808SJens Wiklander                             input, output, tag, tag_len);
6283d3b0591SJens Wiklander }
6293d3b0591SJens Wiklander #endif /* !MBEDTLS_CCM_ALT */
630817466cbSJens Wiklander 
631*b0563631STom Van Eyck #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_CCM_GCM_CAN_AES)
632817466cbSJens Wiklander /*
633817466cbSJens Wiklander  * Examples 1 to 3 from SP800-38C Appendix C
634817466cbSJens Wiklander  */
635817466cbSJens Wiklander 
636817466cbSJens Wiklander #define NB_TESTS 3
6373d3b0591SJens Wiklander #define CCM_SELFTEST_PT_MAX_LEN 24
6383d3b0591SJens Wiklander #define CCM_SELFTEST_CT_MAX_LEN 32
639817466cbSJens Wiklander /*
640817466cbSJens Wiklander  * The data is the same for all tests, only the used length changes
641817466cbSJens Wiklander  */
64211fa71b9SJerome Forissier static const unsigned char key_test_data[] = {
643817466cbSJens Wiklander     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
644817466cbSJens Wiklander     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
645817466cbSJens Wiklander };
646817466cbSJens Wiklander 
64711fa71b9SJerome Forissier static const unsigned char iv_test_data[] = {
648817466cbSJens Wiklander     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
649817466cbSJens Wiklander     0x18, 0x19, 0x1a, 0x1b
650817466cbSJens Wiklander };
651817466cbSJens Wiklander 
65211fa71b9SJerome Forissier static const unsigned char ad_test_data[] = {
653817466cbSJens Wiklander     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
654817466cbSJens Wiklander     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
655817466cbSJens Wiklander     0x10, 0x11, 0x12, 0x13
656817466cbSJens Wiklander };
657817466cbSJens Wiklander 
65811fa71b9SJerome Forissier static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = {
659817466cbSJens Wiklander     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
660817466cbSJens Wiklander     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
661817466cbSJens Wiklander     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
662817466cbSJens Wiklander };
663817466cbSJens Wiklander 
66411fa71b9SJerome Forissier static const size_t iv_len_test_data[NB_TESTS] = { 7, 8,  12 };
66511fa71b9SJerome Forissier static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 };
66611fa71b9SJerome Forissier static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 };
66711fa71b9SJerome Forissier static const size_t tag_len_test_data[NB_TESTS] = { 4, 6,  8  };
668817466cbSJens Wiklander 
66911fa71b9SJerome Forissier static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = {
670817466cbSJens Wiklander     {   0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
671817466cbSJens Wiklander     {   0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
672817466cbSJens Wiklander         0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
673817466cbSJens Wiklander         0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
674817466cbSJens Wiklander     {   0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
675817466cbSJens Wiklander         0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
676817466cbSJens Wiklander         0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
677817466cbSJens Wiklander         0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
678817466cbSJens Wiklander };
679817466cbSJens Wiklander 
680817466cbSJens Wiklander int mbedtls_ccm_self_test(int verbose)
681817466cbSJens Wiklander {
682817466cbSJens Wiklander     mbedtls_ccm_context ctx;
6833d3b0591SJens Wiklander     /*
6843d3b0591SJens Wiklander      * Some hardware accelerators require the input and output buffers
6853d3b0591SJens Wiklander      * would be in RAM, because the flash is not accessible.
6863d3b0591SJens Wiklander      * Use buffers on the stack to hold the test vectors data.
6873d3b0591SJens Wiklander      */
6883d3b0591SJens Wiklander     unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN];
6893d3b0591SJens Wiklander     unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN];
690817466cbSJens Wiklander     size_t i;
69111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
692817466cbSJens Wiklander 
693817466cbSJens Wiklander     mbedtls_ccm_init(&ctx);
694817466cbSJens Wiklander 
69511fa71b9SJerome Forissier     if (mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key_test_data,
69632b31808SJens Wiklander                            8 * sizeof(key_test_data)) != 0) {
69732b31808SJens Wiklander         if (verbose != 0) {
698817466cbSJens Wiklander             mbedtls_printf("  CCM: setup failed");
699817466cbSJens Wiklander         }
700817466cbSJens Wiklander 
70132b31808SJens Wiklander         return 1;
70232b31808SJens Wiklander     }
70332b31808SJens Wiklander 
70432b31808SJens Wiklander     for (i = 0; i < NB_TESTS; i++) {
70532b31808SJens Wiklander         if (verbose != 0) {
706817466cbSJens Wiklander             mbedtls_printf("  CCM-AES #%u: ", (unsigned int) i + 1);
70732b31808SJens Wiklander         }
708817466cbSJens Wiklander 
7093d3b0591SJens Wiklander         memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN);
7103d3b0591SJens Wiklander         memset(ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN);
71111fa71b9SJerome Forissier         memcpy(plaintext, msg_test_data, msg_len_test_data[i]);
7123d3b0591SJens Wiklander 
71311fa71b9SJerome Forissier         ret = mbedtls_ccm_encrypt_and_tag(&ctx, msg_len_test_data[i],
71411fa71b9SJerome Forissier                                           iv_test_data, iv_len_test_data[i],
71511fa71b9SJerome Forissier                                           ad_test_data, add_len_test_data[i],
7163d3b0591SJens Wiklander                                           plaintext, ciphertext,
71711fa71b9SJerome Forissier                                           ciphertext + msg_len_test_data[i],
71811fa71b9SJerome Forissier                                           tag_len_test_data[i]);
719817466cbSJens Wiklander 
720817466cbSJens Wiklander         if (ret != 0 ||
72111fa71b9SJerome Forissier             memcmp(ciphertext, res_test_data[i],
72232b31808SJens Wiklander                    msg_len_test_data[i] + tag_len_test_data[i]) != 0) {
72332b31808SJens Wiklander             if (verbose != 0) {
724817466cbSJens Wiklander                 mbedtls_printf("failed\n");
72532b31808SJens Wiklander             }
726817466cbSJens Wiklander 
72732b31808SJens Wiklander             return 1;
728817466cbSJens Wiklander         }
7293d3b0591SJens Wiklander         memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN);
730817466cbSJens Wiklander 
73111fa71b9SJerome Forissier         ret = mbedtls_ccm_auth_decrypt(&ctx, msg_len_test_data[i],
73211fa71b9SJerome Forissier                                        iv_test_data, iv_len_test_data[i],
73311fa71b9SJerome Forissier                                        ad_test_data, add_len_test_data[i],
7343d3b0591SJens Wiklander                                        ciphertext, plaintext,
73511fa71b9SJerome Forissier                                        ciphertext + msg_len_test_data[i],
73611fa71b9SJerome Forissier                                        tag_len_test_data[i]);
737817466cbSJens Wiklander 
738817466cbSJens Wiklander         if (ret != 0 ||
73932b31808SJens Wiklander             memcmp(plaintext, msg_test_data, msg_len_test_data[i]) != 0) {
74032b31808SJens Wiklander             if (verbose != 0) {
741817466cbSJens Wiklander                 mbedtls_printf("failed\n");
742817466cbSJens Wiklander             }
743817466cbSJens Wiklander 
74432b31808SJens Wiklander             return 1;
74532b31808SJens Wiklander         }
74632b31808SJens Wiklander 
74732b31808SJens Wiklander         if (verbose != 0) {
748817466cbSJens Wiklander             mbedtls_printf("passed\n");
749817466cbSJens Wiklander         }
75032b31808SJens Wiklander     }
751817466cbSJens Wiklander 
752817466cbSJens Wiklander     mbedtls_ccm_free(&ctx);
753817466cbSJens Wiklander 
75432b31808SJens Wiklander     if (verbose != 0) {
755817466cbSJens Wiklander         mbedtls_printf("\n");
75632b31808SJens Wiklander     }
757817466cbSJens Wiklander 
75832b31808SJens Wiklander     return 0;
759817466cbSJens Wiklander }
760817466cbSJens Wiklander 
761817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
762817466cbSJens Wiklander 
763817466cbSJens Wiklander #endif /* MBEDTLS_CCM_C */
764