xref: /optee_os/lib/libmbedtls/mbedtls/library/ccm.c (revision 32b3180828fa15a49ccc86ecb4be9d274c140c89)
1817466cbSJens Wiklander /*
2817466cbSJens Wiklander  *  NIST SP800-38C compliant CCM implementation
3817466cbSJens Wiklander  *
47901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
57901324dSJerome Forissier  *  SPDX-License-Identifier: Apache-2.0
6817466cbSJens Wiklander  *
7817466cbSJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8817466cbSJens Wiklander  *  not use this file except in compliance with the License.
9817466cbSJens Wiklander  *  You may obtain a copy of the License at
10817466cbSJens Wiklander  *
11817466cbSJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
12817466cbSJens Wiklander  *
13817466cbSJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
14817466cbSJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15817466cbSJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16817466cbSJens Wiklander  *  See the License for the specific language governing permissions and
17817466cbSJens Wiklander  *  limitations under the License.
18817466cbSJens Wiklander  */
19817466cbSJens Wiklander 
20817466cbSJens Wiklander /*
21817466cbSJens Wiklander  * Definition of CCM:
22817466cbSJens Wiklander  * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
23817466cbSJens Wiklander  * RFC 3610 "Counter with CBC-MAC (CCM)"
24817466cbSJens Wiklander  *
25817466cbSJens Wiklander  * Related:
26817466cbSJens Wiklander  * RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
27817466cbSJens Wiklander  */
28817466cbSJens Wiklander 
297901324dSJerome Forissier #include "common.h"
30817466cbSJens Wiklander 
31817466cbSJens Wiklander #if defined(MBEDTLS_CCM_C)
32817466cbSJens Wiklander 
33817466cbSJens Wiklander #include "mbedtls/ccm.h"
343d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
3511fa71b9SJerome Forissier #include "mbedtls/error.h"
36817466cbSJens Wiklander 
37817466cbSJens Wiklander #include <string.h>
38817466cbSJens Wiklander 
39817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
40817466cbSJens Wiklander #include "mbedtls/platform.h"
41817466cbSJens Wiklander #else
42*32b31808SJens Wiklander #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
43817466cbSJens Wiklander #include <stdio.h>
44817466cbSJens Wiklander #define mbedtls_printf printf
45817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
46*32b31808SJens Wiklander #endif /* MBEDTLS_PLATFORM_C */
47817466cbSJens Wiklander 
483d3b0591SJens Wiklander #if !defined(MBEDTLS_CCM_ALT)
493d3b0591SJens Wiklander 
50817466cbSJens Wiklander 
51817466cbSJens Wiklander /*
52817466cbSJens Wiklander  * Initialize context
53817466cbSJens Wiklander  */
54817466cbSJens Wiklander void mbedtls_ccm_init(mbedtls_ccm_context *ctx)
55817466cbSJens Wiklander {
56817466cbSJens Wiklander     memset(ctx, 0, sizeof(mbedtls_ccm_context));
57817466cbSJens Wiklander }
58817466cbSJens Wiklander 
59817466cbSJens Wiklander int mbedtls_ccm_setkey(mbedtls_ccm_context *ctx,
60817466cbSJens Wiklander                        mbedtls_cipher_id_t cipher,
61817466cbSJens Wiklander                        const unsigned char *key,
62817466cbSJens Wiklander                        unsigned int keybits)
63817466cbSJens Wiklander {
6411fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
65817466cbSJens Wiklander     const mbedtls_cipher_info_t *cipher_info;
66817466cbSJens Wiklander 
6711fa71b9SJerome Forissier     cipher_info = mbedtls_cipher_info_from_values(cipher, keybits,
6811fa71b9SJerome Forissier                                                   MBEDTLS_MODE_ECB);
69*32b31808SJens Wiklander     if (cipher_info == NULL) {
70*32b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
71*32b31808SJens Wiklander     }
72817466cbSJens Wiklander 
73*32b31808SJens Wiklander     if (cipher_info->block_size != 16) {
74*32b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
75*32b31808SJens Wiklander     }
76817466cbSJens Wiklander 
77817466cbSJens Wiklander     mbedtls_cipher_free(&ctx->cipher_ctx);
78817466cbSJens Wiklander 
79*32b31808SJens Wiklander     if ((ret = mbedtls_cipher_setup(&ctx->cipher_ctx, cipher_info)) != 0) {
80*32b31808SJens Wiklander         return ret;
81817466cbSJens Wiklander     }
82817466cbSJens Wiklander 
83*32b31808SJens Wiklander     if ((ret = mbedtls_cipher_setkey(&ctx->cipher_ctx, key, keybits,
84*32b31808SJens Wiklander                                      MBEDTLS_ENCRYPT)) != 0) {
85*32b31808SJens Wiklander         return ret;
86*32b31808SJens Wiklander     }
87*32b31808SJens Wiklander 
88*32b31808SJens Wiklander     return 0;
89817466cbSJens Wiklander }
90817466cbSJens Wiklander 
91817466cbSJens Wiklander /*
92817466cbSJens Wiklander  * Free context
93817466cbSJens Wiklander  */
94817466cbSJens Wiklander void mbedtls_ccm_free(mbedtls_ccm_context *ctx)
95817466cbSJens Wiklander {
96*32b31808SJens Wiklander     if (ctx == NULL) {
973d3b0591SJens Wiklander         return;
98*32b31808SJens Wiklander     }
99817466cbSJens Wiklander     mbedtls_cipher_free(&ctx->cipher_ctx);
1003d3b0591SJens Wiklander     mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ccm_context));
101817466cbSJens Wiklander }
102817466cbSJens Wiklander 
103*32b31808SJens Wiklander #define CCM_STATE__CLEAR                0
104*32b31808SJens Wiklander #define CCM_STATE__STARTED              (1 << 0)
105*32b31808SJens Wiklander #define CCM_STATE__LENGTHS_SET          (1 << 1)
106*32b31808SJens Wiklander #define CCM_STATE__AUTH_DATA_STARTED    (1 << 2)
107*32b31808SJens Wiklander #define CCM_STATE__AUTH_DATA_FINISHED   (1 << 3)
108*32b31808SJens Wiklander #define CCM_STATE__ERROR                (1 << 4)
109817466cbSJens Wiklander 
110817466cbSJens Wiklander /*
111817466cbSJens Wiklander  * Encrypt or decrypt a partial block with CTR
112817466cbSJens Wiklander  */
113*32b31808SJens Wiklander static int mbedtls_ccm_crypt(mbedtls_ccm_context *ctx,
114*32b31808SJens Wiklander                              size_t offset, size_t use_len,
115*32b31808SJens Wiklander                              const unsigned char *input,
116*32b31808SJens Wiklander                              unsigned char *output)
117*32b31808SJens Wiklander {
118*32b31808SJens Wiklander     size_t olen = 0;
119*32b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
120*32b31808SJens Wiklander     unsigned char tmp_buf[16] = { 0 };
121817466cbSJens Wiklander 
122*32b31808SJens Wiklander     if ((ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->ctr, 16, tmp_buf,
123*32b31808SJens Wiklander                                      &olen)) != 0) {
124*32b31808SJens Wiklander         ctx->state |= CCM_STATE__ERROR;
125*32b31808SJens Wiklander         mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
126*32b31808SJens Wiklander         return ret;
127*32b31808SJens Wiklander     }
128*32b31808SJens Wiklander 
129*32b31808SJens Wiklander     mbedtls_xor(output, input, tmp_buf + offset, use_len);
130*32b31808SJens Wiklander 
131*32b31808SJens Wiklander     mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
132*32b31808SJens Wiklander     return ret;
133*32b31808SJens Wiklander }
134*32b31808SJens Wiklander 
135*32b31808SJens Wiklander static void mbedtls_ccm_clear_state(mbedtls_ccm_context *ctx)
136*32b31808SJens Wiklander {
137*32b31808SJens Wiklander     ctx->state = CCM_STATE__CLEAR;
138*32b31808SJens Wiklander     memset(ctx->y, 0, 16);
139*32b31808SJens Wiklander     memset(ctx->ctr, 0, 16);
140*32b31808SJens Wiklander }
141*32b31808SJens Wiklander 
142*32b31808SJens Wiklander static int ccm_calculate_first_block_if_ready(mbedtls_ccm_context *ctx)
143817466cbSJens Wiklander {
14411fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
145817466cbSJens Wiklander     unsigned char i;
146817466cbSJens Wiklander     size_t len_left, olen;
147817466cbSJens Wiklander 
148*32b31808SJens Wiklander     /* length calculation can be done only after both
149*32b31808SJens Wiklander      * mbedtls_ccm_starts() and mbedtls_ccm_set_lengths() have been executed
150817466cbSJens Wiklander      */
151*32b31808SJens Wiklander     if (!(ctx->state & CCM_STATE__STARTED) || !(ctx->state & CCM_STATE__LENGTHS_SET)) {
152*32b31808SJens Wiklander         return 0;
153*32b31808SJens Wiklander     }
154817466cbSJens Wiklander 
155*32b31808SJens Wiklander     /* CCM expects non-empty tag.
156*32b31808SJens Wiklander      * CCM* allows empty tag. For CCM* without tag, ignore plaintext length.
157*32b31808SJens Wiklander      */
158*32b31808SJens Wiklander     if (ctx->tag_len == 0) {
159*32b31808SJens Wiklander         if (ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT || ctx->mode == MBEDTLS_CCM_STAR_DECRYPT) {
160*32b31808SJens Wiklander             ctx->plaintext_len = 0;
161*32b31808SJens Wiklander         } else {
162*32b31808SJens Wiklander             return MBEDTLS_ERR_CCM_BAD_INPUT;
163*32b31808SJens Wiklander         }
164*32b31808SJens Wiklander     }
165817466cbSJens Wiklander 
166817466cbSJens Wiklander     /*
167*32b31808SJens Wiklander      * First block:
168817466cbSJens Wiklander      * 0        .. 0        flags
169*32b31808SJens Wiklander      * 1        .. iv_len   nonce (aka iv)  - set by: mbedtls_ccm_starts()
170817466cbSJens Wiklander      * iv_len+1 .. 15       length
171817466cbSJens Wiklander      *
172817466cbSJens Wiklander      * With flags as (bits):
173817466cbSJens Wiklander      * 7        0
174817466cbSJens Wiklander      * 6        add present?
175817466cbSJens Wiklander      * 5 .. 3   (t - 2) / 2
176817466cbSJens Wiklander      * 2 .. 0   q - 1
177817466cbSJens Wiklander      */
178*32b31808SJens Wiklander     ctx->y[0] |= (ctx->add_len > 0) << 6;
179*32b31808SJens Wiklander     ctx->y[0] |= ((ctx->tag_len - 2) / 2) << 3;
180*32b31808SJens Wiklander     ctx->y[0] |= ctx->q - 1;
181817466cbSJens Wiklander 
182*32b31808SJens Wiklander     for (i = 0, len_left = ctx->plaintext_len; i < ctx->q; i++, len_left >>= 8) {
183*32b31808SJens Wiklander         ctx->y[15-i] = MBEDTLS_BYTE_0(len_left);
184*32b31808SJens Wiklander     }
185817466cbSJens Wiklander 
186*32b31808SJens Wiklander     if (len_left > 0) {
187*32b31808SJens Wiklander         ctx->state |= CCM_STATE__ERROR;
188*32b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
189*32b31808SJens Wiklander     }
190817466cbSJens Wiklander 
191817466cbSJens Wiklander     /* Start CBC-MAC with first block*/
192*32b31808SJens Wiklander     if ((ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen)) != 0) {
193*32b31808SJens Wiklander         ctx->state |= CCM_STATE__ERROR;
194*32b31808SJens Wiklander         return ret;
195817466cbSJens Wiklander     }
196*32b31808SJens Wiklander 
197*32b31808SJens Wiklander     return 0;
198817466cbSJens Wiklander }
199817466cbSJens Wiklander 
200*32b31808SJens Wiklander int mbedtls_ccm_starts(mbedtls_ccm_context *ctx,
201*32b31808SJens Wiklander                        int mode,
202*32b31808SJens Wiklander                        const unsigned char *iv,
203*32b31808SJens Wiklander                        size_t iv_len)
204*32b31808SJens Wiklander {
205*32b31808SJens Wiklander     /* Also implies q is within bounds */
206*32b31808SJens Wiklander     if (iv_len < 7 || iv_len > 13) {
207*32b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
208*32b31808SJens Wiklander     }
209*32b31808SJens Wiklander 
210*32b31808SJens Wiklander     ctx->mode = mode;
211*32b31808SJens Wiklander     ctx->q = 16 - 1 - (unsigned char) iv_len;
212*32b31808SJens Wiklander 
213817466cbSJens Wiklander     /*
214817466cbSJens Wiklander      * Prepare counter block for encryption:
215817466cbSJens Wiklander      * 0        .. 0        flags
216817466cbSJens Wiklander      * 1        .. iv_len   nonce (aka iv)
217817466cbSJens Wiklander      * iv_len+1 .. 15       counter (initially 1)
218817466cbSJens Wiklander      *
219817466cbSJens Wiklander      * With flags as (bits):
220817466cbSJens Wiklander      * 7 .. 3   0
221817466cbSJens Wiklander      * 2 .. 0   q - 1
222817466cbSJens Wiklander      */
223*32b31808SJens Wiklander     memset(ctx->ctr, 0, 16);
224*32b31808SJens Wiklander     ctx->ctr[0] = ctx->q - 1;
225*32b31808SJens Wiklander     memcpy(ctx->ctr + 1, iv, iv_len);
226*32b31808SJens Wiklander     memset(ctx->ctr + 1 + iv_len, 0, ctx->q);
227*32b31808SJens Wiklander     ctx->ctr[15] = 1;
228817466cbSJens Wiklander 
229817466cbSJens Wiklander     /*
230*32b31808SJens Wiklander      * See ccm_calculate_first_block_if_ready() for block layout description
231*32b31808SJens Wiklander      */
232*32b31808SJens Wiklander     memcpy(ctx->y + 1, iv, iv_len);
233*32b31808SJens Wiklander 
234*32b31808SJens Wiklander     ctx->state |= CCM_STATE__STARTED;
235*32b31808SJens Wiklander     return ccm_calculate_first_block_if_ready(ctx);
236*32b31808SJens Wiklander }
237*32b31808SJens Wiklander 
238*32b31808SJens Wiklander int mbedtls_ccm_set_lengths(mbedtls_ccm_context *ctx,
239*32b31808SJens Wiklander                             size_t total_ad_len,
240*32b31808SJens Wiklander                             size_t plaintext_len,
241*32b31808SJens Wiklander                             size_t tag_len)
242*32b31808SJens Wiklander {
243*32b31808SJens Wiklander     /*
244*32b31808SJens Wiklander      * Check length requirements: SP800-38C A.1
245*32b31808SJens Wiklander      * Additional requirement: a < 2^16 - 2^8 to simplify the code.
246*32b31808SJens Wiklander      * 'length' checked later (when writing it to the first block)
247817466cbSJens Wiklander      *
248*32b31808SJens Wiklander      * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4).
249817466cbSJens Wiklander      */
250*32b31808SJens Wiklander     if (tag_len == 2 || tag_len > 16 || tag_len % 2 != 0) {
251*32b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
252817466cbSJens Wiklander     }
253817466cbSJens Wiklander 
254*32b31808SJens Wiklander     if (total_ad_len >= 0xFF00) {
255*32b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
256817466cbSJens Wiklander     }
257817466cbSJens Wiklander 
258*32b31808SJens Wiklander     ctx->plaintext_len = plaintext_len;
259*32b31808SJens Wiklander     ctx->add_len = total_ad_len;
260*32b31808SJens Wiklander     ctx->tag_len = tag_len;
261*32b31808SJens Wiklander     ctx->processed = 0;
262817466cbSJens Wiklander 
263*32b31808SJens Wiklander     ctx->state |= CCM_STATE__LENGTHS_SET;
264*32b31808SJens Wiklander     return ccm_calculate_first_block_if_ready(ctx);
265*32b31808SJens Wiklander }
266*32b31808SJens Wiklander 
267*32b31808SJens Wiklander int mbedtls_ccm_update_ad(mbedtls_ccm_context *ctx,
268*32b31808SJens Wiklander                           const unsigned char *add,
269*32b31808SJens Wiklander                           size_t add_len)
270*32b31808SJens Wiklander {
271*32b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
272*32b31808SJens Wiklander     size_t olen, use_len, offset;
273*32b31808SJens Wiklander 
274*32b31808SJens Wiklander     if (ctx->state & CCM_STATE__ERROR) {
275*32b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
276*32b31808SJens Wiklander     }
277*32b31808SJens Wiklander 
278*32b31808SJens Wiklander     if (add_len > 0) {
279*32b31808SJens Wiklander         if (ctx->state & CCM_STATE__AUTH_DATA_FINISHED) {
280*32b31808SJens Wiklander             return MBEDTLS_ERR_CCM_BAD_INPUT;
281*32b31808SJens Wiklander         }
282*32b31808SJens Wiklander 
283*32b31808SJens Wiklander         if (!(ctx->state & CCM_STATE__AUTH_DATA_STARTED)) {
284*32b31808SJens Wiklander             if (add_len > ctx->add_len) {
285*32b31808SJens Wiklander                 return MBEDTLS_ERR_CCM_BAD_INPUT;
286*32b31808SJens Wiklander             }
287*32b31808SJens Wiklander 
288*32b31808SJens Wiklander             ctx->y[0] ^= (unsigned char) ((ctx->add_len >> 8) & 0xFF);
289*32b31808SJens Wiklander             ctx->y[1] ^= (unsigned char) ((ctx->add_len) & 0xFF);
290*32b31808SJens Wiklander 
291*32b31808SJens Wiklander             ctx->state |= CCM_STATE__AUTH_DATA_STARTED;
292*32b31808SJens Wiklander         } else if (ctx->processed + add_len > ctx->add_len) {
293*32b31808SJens Wiklander             return MBEDTLS_ERR_CCM_BAD_INPUT;
294*32b31808SJens Wiklander         }
295*32b31808SJens Wiklander 
296*32b31808SJens Wiklander         while (add_len > 0) {
297*32b31808SJens Wiklander             offset = (ctx->processed + 2) % 16; /* account for y[0] and y[1]
298*32b31808SJens Wiklander                                                  * holding total auth data length */
299*32b31808SJens Wiklander             use_len = 16 - offset;
300*32b31808SJens Wiklander 
301*32b31808SJens Wiklander             if (use_len > add_len) {
302*32b31808SJens Wiklander                 use_len = add_len;
303*32b31808SJens Wiklander             }
304*32b31808SJens Wiklander 
305*32b31808SJens Wiklander             mbedtls_xor(ctx->y + offset, ctx->y + offset, add, use_len);
306*32b31808SJens Wiklander 
307*32b31808SJens Wiklander             ctx->processed += use_len;
308*32b31808SJens Wiklander             add_len -= use_len;
309*32b31808SJens Wiklander             add += use_len;
310*32b31808SJens Wiklander 
311*32b31808SJens Wiklander             if (use_len + offset == 16 || ctx->processed == ctx->add_len) {
312*32b31808SJens Wiklander                 if ((ret =
313*32b31808SJens Wiklander                          mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen)) != 0) {
314*32b31808SJens Wiklander                     ctx->state |= CCM_STATE__ERROR;
315*32b31808SJens Wiklander                     return ret;
316*32b31808SJens Wiklander                 }
317*32b31808SJens Wiklander             }
318*32b31808SJens Wiklander         }
319*32b31808SJens Wiklander 
320*32b31808SJens Wiklander         if (ctx->processed == ctx->add_len) {
321*32b31808SJens Wiklander             ctx->state |= CCM_STATE__AUTH_DATA_FINISHED;
322*32b31808SJens Wiklander             ctx->processed = 0; // prepare for mbedtls_ccm_update()
323*32b31808SJens Wiklander         }
324*32b31808SJens Wiklander     }
325*32b31808SJens Wiklander 
326*32b31808SJens Wiklander     return 0;
327*32b31808SJens Wiklander }
328*32b31808SJens Wiklander 
329*32b31808SJens Wiklander int mbedtls_ccm_update(mbedtls_ccm_context *ctx,
330*32b31808SJens Wiklander                        const unsigned char *input, size_t input_len,
331*32b31808SJens Wiklander                        unsigned char *output, size_t output_size,
332*32b31808SJens Wiklander                        size_t *output_len)
333*32b31808SJens Wiklander {
334*32b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
335*32b31808SJens Wiklander     unsigned char i;
336*32b31808SJens Wiklander     size_t use_len, offset, olen;
337*32b31808SJens Wiklander 
338*32b31808SJens Wiklander     unsigned char local_output[16];
339*32b31808SJens Wiklander 
340*32b31808SJens Wiklander     if (ctx->state & CCM_STATE__ERROR) {
341*32b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
342*32b31808SJens Wiklander     }
343*32b31808SJens Wiklander 
344*32b31808SJens Wiklander     /* Check against plaintext length only if performing operation with
345*32b31808SJens Wiklander      * authentication
346817466cbSJens Wiklander      */
347*32b31808SJens Wiklander     if (ctx->tag_len != 0 && ctx->processed + input_len > ctx->plaintext_len) {
348*32b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
349*32b31808SJens Wiklander     }
350*32b31808SJens Wiklander 
351*32b31808SJens Wiklander     if (output_size < input_len) {
352*32b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
353*32b31808SJens Wiklander     }
354*32b31808SJens Wiklander     *output_len = input_len;
355*32b31808SJens Wiklander 
356*32b31808SJens Wiklander     ret = 0;
357*32b31808SJens Wiklander 
358*32b31808SJens Wiklander     while (input_len > 0) {
359*32b31808SJens Wiklander         offset = ctx->processed % 16;
360*32b31808SJens Wiklander 
361*32b31808SJens Wiklander         use_len = 16 - offset;
362*32b31808SJens Wiklander 
363*32b31808SJens Wiklander         if (use_len > input_len) {
364*32b31808SJens Wiklander             use_len = input_len;
365*32b31808SJens Wiklander         }
366*32b31808SJens Wiklander 
367*32b31808SJens Wiklander         ctx->processed += use_len;
368*32b31808SJens Wiklander 
369*32b31808SJens Wiklander         if (ctx->mode == MBEDTLS_CCM_ENCRYPT || \
370*32b31808SJens Wiklander             ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT) {
371*32b31808SJens Wiklander             mbedtls_xor(ctx->y + offset, ctx->y + offset, input, use_len);
372*32b31808SJens Wiklander 
373*32b31808SJens Wiklander             if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) {
374*32b31808SJens Wiklander                 if ((ret =
375*32b31808SJens Wiklander                          mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen)) != 0) {
376*32b31808SJens Wiklander                     ctx->state |= CCM_STATE__ERROR;
377*32b31808SJens Wiklander                     goto exit;
378*32b31808SJens Wiklander                 }
379*32b31808SJens Wiklander             }
380*32b31808SJens Wiklander 
381*32b31808SJens Wiklander             ret = mbedtls_ccm_crypt(ctx, offset, use_len, input, output);
382*32b31808SJens Wiklander             if (ret != 0) {
383*32b31808SJens Wiklander                 goto exit;
384*32b31808SJens Wiklander             }
385*32b31808SJens Wiklander         }
386*32b31808SJens Wiklander 
387*32b31808SJens Wiklander         if (ctx->mode == MBEDTLS_CCM_DECRYPT || \
388*32b31808SJens Wiklander             ctx->mode == MBEDTLS_CCM_STAR_DECRYPT) {
389*32b31808SJens Wiklander             /* Since output may be in shared memory, we cannot be sure that
390*32b31808SJens Wiklander              * it will contain what we wrote to it. Therefore, we should avoid using
391*32b31808SJens Wiklander              * it as input to any operations.
392*32b31808SJens Wiklander              * Write decrypted data to local_output to avoid using output variable as
393*32b31808SJens Wiklander              * input in the XOR operation for Y.
394*32b31808SJens Wiklander              */
395*32b31808SJens Wiklander             ret = mbedtls_ccm_crypt(ctx, offset, use_len, input, local_output);
396*32b31808SJens Wiklander             if (ret != 0) {
397*32b31808SJens Wiklander                 goto exit;
398*32b31808SJens Wiklander             }
399*32b31808SJens Wiklander 
400*32b31808SJens Wiklander             mbedtls_xor(ctx->y + offset, ctx->y + offset, local_output, use_len);
401*32b31808SJens Wiklander 
402*32b31808SJens Wiklander             memcpy(output, local_output, use_len);
403*32b31808SJens Wiklander             mbedtls_platform_zeroize(local_output, 16);
404*32b31808SJens Wiklander 
405*32b31808SJens Wiklander             if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) {
406*32b31808SJens Wiklander                 if ((ret =
407*32b31808SJens Wiklander                          mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen)) != 0) {
408*32b31808SJens Wiklander                     ctx->state |= CCM_STATE__ERROR;
409*32b31808SJens Wiklander                     goto exit;
410*32b31808SJens Wiklander                 }
411*32b31808SJens Wiklander             }
412*32b31808SJens Wiklander         }
413*32b31808SJens Wiklander 
414*32b31808SJens Wiklander         if (use_len + offset == 16 || ctx->processed == ctx->plaintext_len) {
415*32b31808SJens Wiklander             for (i = 0; i < ctx->q; i++) {
416*32b31808SJens Wiklander                 if (++(ctx->ctr)[15-i] != 0) {
417817466cbSJens Wiklander                     break;
418817466cbSJens Wiklander                 }
419*32b31808SJens Wiklander             }
420*32b31808SJens Wiklander         }
421*32b31808SJens Wiklander 
422*32b31808SJens Wiklander         input_len -= use_len;
423*32b31808SJens Wiklander         input += use_len;
424*32b31808SJens Wiklander         output += use_len;
425*32b31808SJens Wiklander     }
426*32b31808SJens Wiklander 
427*32b31808SJens Wiklander exit:
428*32b31808SJens Wiklander     mbedtls_platform_zeroize(local_output, 16);
429*32b31808SJens Wiklander 
430*32b31808SJens Wiklander     return ret;
431*32b31808SJens Wiklander }
432*32b31808SJens Wiklander 
433*32b31808SJens Wiklander int mbedtls_ccm_finish(mbedtls_ccm_context *ctx,
434*32b31808SJens Wiklander                        unsigned char *tag, size_t tag_len)
435*32b31808SJens Wiklander {
436*32b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
437*32b31808SJens Wiklander     unsigned char i;
438*32b31808SJens Wiklander 
439*32b31808SJens Wiklander     if (ctx->state & CCM_STATE__ERROR) {
440*32b31808SJens Wiklander         return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
441*32b31808SJens Wiklander     }
442*32b31808SJens Wiklander 
443*32b31808SJens Wiklander     if (ctx->add_len > 0 && !(ctx->state & CCM_STATE__AUTH_DATA_FINISHED)) {
444*32b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
445*32b31808SJens Wiklander     }
446*32b31808SJens Wiklander 
447*32b31808SJens Wiklander     if (ctx->plaintext_len > 0 && ctx->processed != ctx->plaintext_len) {
448*32b31808SJens Wiklander         return MBEDTLS_ERR_CCM_BAD_INPUT;
449*32b31808SJens Wiklander     }
450817466cbSJens Wiklander 
451817466cbSJens Wiklander     /*
452817466cbSJens Wiklander      * Authentication: reset counter and crypt/mask internal tag
453817466cbSJens Wiklander      */
454*32b31808SJens Wiklander     for (i = 0; i < ctx->q; i++) {
455*32b31808SJens Wiklander         ctx->ctr[15-i] = 0;
456*32b31808SJens Wiklander     }
457817466cbSJens Wiklander 
458*32b31808SJens Wiklander     ret = mbedtls_ccm_crypt(ctx, 0, 16, ctx->y, ctx->y);
459*32b31808SJens Wiklander     if (ret != 0) {
460*32b31808SJens Wiklander         return ret;
461*32b31808SJens Wiklander     }
462*32b31808SJens Wiklander     if (tag != NULL) {
463*32b31808SJens Wiklander         memcpy(tag, ctx->y, tag_len);
464*32b31808SJens Wiklander     }
465*32b31808SJens Wiklander     mbedtls_ccm_clear_state(ctx);
466817466cbSJens Wiklander 
467*32b31808SJens Wiklander     return 0;
468*32b31808SJens Wiklander }
469*32b31808SJens Wiklander 
470*32b31808SJens Wiklander /*
471*32b31808SJens Wiklander  * Authenticated encryption or decryption
472*32b31808SJens Wiklander  */
473*32b31808SJens Wiklander static int ccm_auth_crypt(mbedtls_ccm_context *ctx, int mode, size_t length,
474*32b31808SJens Wiklander                           const unsigned char *iv, size_t iv_len,
475*32b31808SJens Wiklander                           const unsigned char *add, size_t add_len,
476*32b31808SJens Wiklander                           const unsigned char *input, unsigned char *output,
477*32b31808SJens Wiklander                           unsigned char *tag, size_t tag_len)
478*32b31808SJens Wiklander {
479*32b31808SJens Wiklander     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
480*32b31808SJens Wiklander     size_t olen;
481*32b31808SJens Wiklander 
482*32b31808SJens Wiklander     if ((ret = mbedtls_ccm_starts(ctx, mode, iv, iv_len)) != 0) {
483*32b31808SJens Wiklander         return ret;
484*32b31808SJens Wiklander     }
485*32b31808SJens Wiklander 
486*32b31808SJens Wiklander     if ((ret = mbedtls_ccm_set_lengths(ctx, add_len, length, tag_len)) != 0) {
487*32b31808SJens Wiklander         return ret;
488*32b31808SJens Wiklander     }
489*32b31808SJens Wiklander 
490*32b31808SJens Wiklander     if ((ret = mbedtls_ccm_update_ad(ctx, add, add_len)) != 0) {
491*32b31808SJens Wiklander         return ret;
492*32b31808SJens Wiklander     }
493*32b31808SJens Wiklander 
494*32b31808SJens Wiklander     if ((ret = mbedtls_ccm_update(ctx, input, length,
495*32b31808SJens Wiklander                                   output, length, &olen)) != 0) {
496*32b31808SJens Wiklander         return ret;
497*32b31808SJens Wiklander     }
498*32b31808SJens Wiklander 
499*32b31808SJens Wiklander     if ((ret = mbedtls_ccm_finish(ctx, tag, tag_len)) != 0) {
500*32b31808SJens Wiklander         return ret;
501*32b31808SJens Wiklander     }
502*32b31808SJens Wiklander 
503*32b31808SJens Wiklander     return 0;
504817466cbSJens Wiklander }
505817466cbSJens Wiklander 
506817466cbSJens Wiklander /*
507817466cbSJens Wiklander  * Authenticated encryption
508817466cbSJens Wiklander  */
5093d3b0591SJens Wiklander int mbedtls_ccm_star_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length,
5103d3b0591SJens Wiklander                                      const unsigned char *iv, size_t iv_len,
5113d3b0591SJens Wiklander                                      const unsigned char *add, size_t add_len,
5123d3b0591SJens Wiklander                                      const unsigned char *input, unsigned char *output,
5133d3b0591SJens Wiklander                                      unsigned char *tag, size_t tag_len)
5143d3b0591SJens Wiklander {
515*32b31808SJens Wiklander     return ccm_auth_crypt(ctx, MBEDTLS_CCM_STAR_ENCRYPT, length, iv, iv_len,
516*32b31808SJens Wiklander                           add, add_len, input, output, tag, tag_len);
5173d3b0591SJens Wiklander }
5183d3b0591SJens Wiklander 
519817466cbSJens Wiklander int mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length,
520817466cbSJens Wiklander                                 const unsigned char *iv, size_t iv_len,
521817466cbSJens Wiklander                                 const unsigned char *add, size_t add_len,
522817466cbSJens Wiklander                                 const unsigned char *input, unsigned char *output,
523817466cbSJens Wiklander                                 unsigned char *tag, size_t tag_len)
524817466cbSJens Wiklander {
525*32b31808SJens Wiklander     return ccm_auth_crypt(ctx, MBEDTLS_CCM_ENCRYPT, length, iv, iv_len,
526*32b31808SJens Wiklander                           add, add_len, input, output, tag, tag_len);
527817466cbSJens Wiklander }
528817466cbSJens Wiklander 
529817466cbSJens Wiklander /*
530817466cbSJens Wiklander  * Authenticated decryption
531817466cbSJens Wiklander  */
532*32b31808SJens Wiklander static int mbedtls_ccm_compare_tags(const unsigned char *tag1,
533*32b31808SJens Wiklander                                     const unsigned char *tag2,
534*32b31808SJens Wiklander                                     size_t tag_len)
535*32b31808SJens Wiklander {
536*32b31808SJens Wiklander     unsigned char i;
537*32b31808SJens Wiklander     int diff;
538*32b31808SJens Wiklander 
539*32b31808SJens Wiklander     /* Check tag in "constant-time" */
540*32b31808SJens Wiklander     for (diff = 0, i = 0; i < tag_len; i++) {
541*32b31808SJens Wiklander         diff |= tag1[i] ^ tag2[i];
542*32b31808SJens Wiklander     }
543*32b31808SJens Wiklander 
544*32b31808SJens Wiklander     if (diff != 0) {
545*32b31808SJens Wiklander         return MBEDTLS_ERR_CCM_AUTH_FAILED;
546*32b31808SJens Wiklander     }
547*32b31808SJens Wiklander 
548*32b31808SJens Wiklander     return 0;
549*32b31808SJens Wiklander }
550*32b31808SJens Wiklander 
551*32b31808SJens Wiklander static int ccm_auth_decrypt(mbedtls_ccm_context *ctx, int mode, size_t length,
552817466cbSJens Wiklander                             const unsigned char *iv, size_t iv_len,
553817466cbSJens Wiklander                             const unsigned char *add, size_t add_len,
554817466cbSJens Wiklander                             const unsigned char *input, unsigned char *output,
555817466cbSJens Wiklander                             const unsigned char *tag, size_t tag_len)
556817466cbSJens Wiklander {
55711fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
558817466cbSJens Wiklander     unsigned char check_tag[16];
559817466cbSJens Wiklander 
560*32b31808SJens Wiklander     if ((ret = ccm_auth_crypt(ctx, mode, length,
561817466cbSJens Wiklander                               iv, iv_len, add, add_len,
562*32b31808SJens Wiklander                               input, output, check_tag, tag_len)) != 0) {
563*32b31808SJens Wiklander         return ret;
564817466cbSJens Wiklander     }
565817466cbSJens Wiklander 
566*32b31808SJens Wiklander     if ((ret = mbedtls_ccm_compare_tags(tag, check_tag, tag_len)) != 0) {
5673d3b0591SJens Wiklander         mbedtls_platform_zeroize(output, length);
568*32b31808SJens Wiklander         return ret;
569817466cbSJens Wiklander     }
570817466cbSJens Wiklander 
571*32b31808SJens Wiklander     return 0;
572*32b31808SJens Wiklander }
573*32b31808SJens Wiklander 
574*32b31808SJens Wiklander int mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context *ctx, size_t length,
575*32b31808SJens Wiklander                                   const unsigned char *iv, size_t iv_len,
576*32b31808SJens Wiklander                                   const unsigned char *add, size_t add_len,
577*32b31808SJens Wiklander                                   const unsigned char *input, unsigned char *output,
578*32b31808SJens Wiklander                                   const unsigned char *tag, size_t tag_len)
579*32b31808SJens Wiklander {
580*32b31808SJens Wiklander     return ccm_auth_decrypt(ctx, MBEDTLS_CCM_STAR_DECRYPT, length,
581*32b31808SJens Wiklander                             iv, iv_len, add, add_len,
582*32b31808SJens Wiklander                             input, output, tag, tag_len);
583817466cbSJens Wiklander }
584817466cbSJens Wiklander 
5853d3b0591SJens Wiklander int mbedtls_ccm_auth_decrypt(mbedtls_ccm_context *ctx, size_t length,
5863d3b0591SJens Wiklander                              const unsigned char *iv, size_t iv_len,
5873d3b0591SJens Wiklander                              const unsigned char *add, size_t add_len,
5883d3b0591SJens Wiklander                              const unsigned char *input, unsigned char *output,
5893d3b0591SJens Wiklander                              const unsigned char *tag, size_t tag_len)
5903d3b0591SJens Wiklander {
591*32b31808SJens Wiklander     return ccm_auth_decrypt(ctx, MBEDTLS_CCM_DECRYPT, length,
592*32b31808SJens Wiklander                             iv, iv_len, add, add_len,
593*32b31808SJens Wiklander                             input, output, tag, tag_len);
5943d3b0591SJens Wiklander }
5953d3b0591SJens Wiklander #endif /* !MBEDTLS_CCM_ALT */
596817466cbSJens Wiklander 
597817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
598817466cbSJens Wiklander /*
599817466cbSJens Wiklander  * Examples 1 to 3 from SP800-38C Appendix C
600817466cbSJens Wiklander  */
601817466cbSJens Wiklander 
602817466cbSJens Wiklander #define NB_TESTS 3
6033d3b0591SJens Wiklander #define CCM_SELFTEST_PT_MAX_LEN 24
6043d3b0591SJens Wiklander #define CCM_SELFTEST_CT_MAX_LEN 32
605817466cbSJens Wiklander /*
606817466cbSJens Wiklander  * The data is the same for all tests, only the used length changes
607817466cbSJens Wiklander  */
60811fa71b9SJerome Forissier static const unsigned char key_test_data[] = {
609817466cbSJens Wiklander     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
610817466cbSJens Wiklander     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
611817466cbSJens Wiklander };
612817466cbSJens Wiklander 
61311fa71b9SJerome Forissier static const unsigned char iv_test_data[] = {
614817466cbSJens Wiklander     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
615817466cbSJens Wiklander     0x18, 0x19, 0x1a, 0x1b
616817466cbSJens Wiklander };
617817466cbSJens Wiklander 
61811fa71b9SJerome Forissier static const unsigned char ad_test_data[] = {
619817466cbSJens Wiklander     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
620817466cbSJens Wiklander     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
621817466cbSJens Wiklander     0x10, 0x11, 0x12, 0x13
622817466cbSJens Wiklander };
623817466cbSJens Wiklander 
62411fa71b9SJerome Forissier static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = {
625817466cbSJens Wiklander     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
626817466cbSJens Wiklander     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
627817466cbSJens Wiklander     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
628817466cbSJens Wiklander };
629817466cbSJens Wiklander 
63011fa71b9SJerome Forissier static const size_t iv_len_test_data[NB_TESTS] = { 7, 8,  12 };
63111fa71b9SJerome Forissier static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 };
63211fa71b9SJerome Forissier static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 };
63311fa71b9SJerome Forissier static const size_t tag_len_test_data[NB_TESTS] = { 4, 6,  8  };
634817466cbSJens Wiklander 
63511fa71b9SJerome Forissier static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = {
636817466cbSJens Wiklander     {   0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
637817466cbSJens Wiklander     {   0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
638817466cbSJens Wiklander         0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
639817466cbSJens Wiklander         0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
640817466cbSJens Wiklander     {   0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
641817466cbSJens Wiklander         0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
642817466cbSJens Wiklander         0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
643817466cbSJens Wiklander         0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
644817466cbSJens Wiklander };
645817466cbSJens Wiklander 
646817466cbSJens Wiklander int mbedtls_ccm_self_test(int verbose)
647817466cbSJens Wiklander {
648817466cbSJens Wiklander     mbedtls_ccm_context ctx;
6493d3b0591SJens Wiklander     /*
6503d3b0591SJens Wiklander      * Some hardware accelerators require the input and output buffers
6513d3b0591SJens Wiklander      * would be in RAM, because the flash is not accessible.
6523d3b0591SJens Wiklander      * Use buffers on the stack to hold the test vectors data.
6533d3b0591SJens Wiklander      */
6543d3b0591SJens Wiklander     unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN];
6553d3b0591SJens Wiklander     unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN];
656817466cbSJens Wiklander     size_t i;
65711fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
658817466cbSJens Wiklander 
659817466cbSJens Wiklander     mbedtls_ccm_init(&ctx);
660817466cbSJens Wiklander 
66111fa71b9SJerome Forissier     if (mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key_test_data,
662*32b31808SJens Wiklander                            8 * sizeof(key_test_data)) != 0) {
663*32b31808SJens Wiklander         if (verbose != 0) {
664817466cbSJens Wiklander             mbedtls_printf("  CCM: setup failed");
665817466cbSJens Wiklander         }
666817466cbSJens Wiklander 
667*32b31808SJens Wiklander         return 1;
668*32b31808SJens Wiklander     }
669*32b31808SJens Wiklander 
670*32b31808SJens Wiklander     for (i = 0; i < NB_TESTS; i++) {
671*32b31808SJens Wiklander         if (verbose != 0) {
672817466cbSJens Wiklander             mbedtls_printf("  CCM-AES #%u: ", (unsigned int) i + 1);
673*32b31808SJens Wiklander         }
674817466cbSJens Wiklander 
6753d3b0591SJens Wiklander         memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN);
6763d3b0591SJens Wiklander         memset(ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN);
67711fa71b9SJerome Forissier         memcpy(plaintext, msg_test_data, msg_len_test_data[i]);
6783d3b0591SJens Wiklander 
67911fa71b9SJerome Forissier         ret = mbedtls_ccm_encrypt_and_tag(&ctx, msg_len_test_data[i],
68011fa71b9SJerome Forissier                                           iv_test_data, iv_len_test_data[i],
68111fa71b9SJerome Forissier                                           ad_test_data, add_len_test_data[i],
6823d3b0591SJens Wiklander                                           plaintext, ciphertext,
68311fa71b9SJerome Forissier                                           ciphertext + msg_len_test_data[i],
68411fa71b9SJerome Forissier                                           tag_len_test_data[i]);
685817466cbSJens Wiklander 
686817466cbSJens Wiklander         if (ret != 0 ||
68711fa71b9SJerome Forissier             memcmp(ciphertext, res_test_data[i],
688*32b31808SJens Wiklander                    msg_len_test_data[i] + tag_len_test_data[i]) != 0) {
689*32b31808SJens Wiklander             if (verbose != 0) {
690817466cbSJens Wiklander                 mbedtls_printf("failed\n");
691*32b31808SJens Wiklander             }
692817466cbSJens Wiklander 
693*32b31808SJens Wiklander             return 1;
694817466cbSJens Wiklander         }
6953d3b0591SJens Wiklander         memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN);
696817466cbSJens Wiklander 
69711fa71b9SJerome Forissier         ret = mbedtls_ccm_auth_decrypt(&ctx, msg_len_test_data[i],
69811fa71b9SJerome Forissier                                        iv_test_data, iv_len_test_data[i],
69911fa71b9SJerome Forissier                                        ad_test_data, add_len_test_data[i],
7003d3b0591SJens Wiklander                                        ciphertext, plaintext,
70111fa71b9SJerome Forissier                                        ciphertext + msg_len_test_data[i],
70211fa71b9SJerome Forissier                                        tag_len_test_data[i]);
703817466cbSJens Wiklander 
704817466cbSJens Wiklander         if (ret != 0 ||
705*32b31808SJens Wiklander             memcmp(plaintext, msg_test_data, msg_len_test_data[i]) != 0) {
706*32b31808SJens Wiklander             if (verbose != 0) {
707817466cbSJens Wiklander                 mbedtls_printf("failed\n");
708817466cbSJens Wiklander             }
709817466cbSJens Wiklander 
710*32b31808SJens Wiklander             return 1;
711*32b31808SJens Wiklander         }
712*32b31808SJens Wiklander 
713*32b31808SJens Wiklander         if (verbose != 0) {
714817466cbSJens Wiklander             mbedtls_printf("passed\n");
715817466cbSJens Wiklander         }
716*32b31808SJens Wiklander     }
717817466cbSJens Wiklander 
718817466cbSJens Wiklander     mbedtls_ccm_free(&ctx);
719817466cbSJens Wiklander 
720*32b31808SJens Wiklander     if (verbose != 0) {
721817466cbSJens Wiklander         mbedtls_printf("\n");
722*32b31808SJens Wiklander     }
723817466cbSJens Wiklander 
724*32b31808SJens Wiklander     return 0;
725817466cbSJens Wiklander }
726817466cbSJens Wiklander 
727817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
728817466cbSJens Wiklander 
729817466cbSJens Wiklander #endif /* MBEDTLS_CCM_C */
730