• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  NIST SP800-38C compliant CCM implementation
3  *
4  *  Copyright The Mbed TLS Contributors
5  *  SPDX-License-Identifier: Apache-2.0
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8  *  not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *  http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  */
19 
20 /*
21  * Definition of CCM:
22  * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
23  * RFC 3610 "Counter with CBC-MAC (CCM)"
24  *
25  * Related:
26  * RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
27  */
28 
29 #include "common.h"
30 
31 #if defined(MBEDTLS_CCM_C)
32 
33 #include "mbedtls/ccm.h"
34 #include "mbedtls/platform_util.h"
35 #include "mbedtls/error.h"
36 
37 #include <string.h>
38 
39 #if defined(MBEDTLS_PLATFORM_C)
40 #include "mbedtls/platform.h"
41 #else
42 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
43 #include <stdio.h>
44 #define mbedtls_printf printf
45 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
46 #endif /* MBEDTLS_PLATFORM_C */
47 
48 #if !defined(MBEDTLS_CCM_ALT)
49 
50 
51 /*
52  * Initialize context
53  */
mbedtls_ccm_init(mbedtls_ccm_context * ctx)54 void mbedtls_ccm_init( mbedtls_ccm_context *ctx )
55 {
56     memset( ctx, 0, sizeof( mbedtls_ccm_context ) );
57 }
58 
mbedtls_ccm_setkey(mbedtls_ccm_context * ctx,mbedtls_cipher_id_t cipher,const unsigned char * key,unsigned int keybits)59 int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx,
60                         mbedtls_cipher_id_t cipher,
61                         const unsigned char *key,
62                         unsigned int keybits )
63 {
64     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
65     const mbedtls_cipher_info_t *cipher_info;
66 
67     cipher_info = mbedtls_cipher_info_from_values( cipher, keybits,
68                                                    MBEDTLS_MODE_ECB );
69     if( cipher_info == NULL )
70         return( MBEDTLS_ERR_CCM_BAD_INPUT );
71 
72     if( cipher_info->block_size != 16 )
73         return( MBEDTLS_ERR_CCM_BAD_INPUT );
74 
75     mbedtls_cipher_free( &ctx->cipher_ctx );
76 
77     if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 )
78         return( ret );
79 
80     if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits,
81                                MBEDTLS_ENCRYPT ) ) != 0 )
82     {
83         return( ret );
84     }
85 
86     return( 0 );
87 }
88 
89 /*
90  * Free context
91  */
mbedtls_ccm_free(mbedtls_ccm_context * ctx)92 void mbedtls_ccm_free( mbedtls_ccm_context *ctx )
93 {
94     if( ctx == NULL )
95         return;
96     mbedtls_cipher_free( &ctx->cipher_ctx );
97     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ccm_context ) );
98 }
99 
100 #define CCM_STATE__CLEAR                0
101 #define CCM_STATE__STARTED              (1 << 0)
102 #define CCM_STATE__LENGHTS_SET          (1 << 1)
103 #define CCM_STATE__AUTH_DATA_STARTED    (1 << 2)
104 #define CCM_STATE__AUTH_DATA_FINISHED   (1 << 3)
105 #define CCM_STATE__ERROR                (1 << 4)
106 
107 /*
108  * Encrypt or decrypt a partial block with CTR
109  */
mbedtls_ccm_crypt(mbedtls_ccm_context * ctx,size_t offset,size_t use_len,const unsigned char * input,unsigned char * output)110 static int mbedtls_ccm_crypt( mbedtls_ccm_context *ctx,
111                               size_t offset, size_t use_len,
112                               const unsigned char *input,
113                               unsigned char *output )
114 {
115     size_t i;
116     size_t olen = 0;
117     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
118     unsigned char tmp_buf[16] = {0};
119 
120     if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->ctr, 16, tmp_buf,
121                                        &olen ) ) != 0 )
122     {
123         ctx->state |= CCM_STATE__ERROR;
124         mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
125         return ret;
126     }
127 
128     for( i = 0; i < use_len; i++ )
129         output[i] = input[i] ^ tmp_buf[offset + i];
130 
131     mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
132     return ret;
133 }
134 
mbedtls_ccm_clear_state(mbedtls_ccm_context * ctx)135 static void mbedtls_ccm_clear_state(mbedtls_ccm_context *ctx) {
136     ctx->state = CCM_STATE__CLEAR;
137     memset( ctx->y, 0, 16);
138     memset( ctx->ctr, 0, 16);
139 }
140 
ccm_calculate_first_block_if_ready(mbedtls_ccm_context * ctx)141 static int ccm_calculate_first_block_if_ready(mbedtls_ccm_context *ctx)
142 {
143     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
144     unsigned char i;
145     size_t len_left, olen;
146 
147     /* length calulcation can be done only after both
148      * mbedtls_ccm_starts() and mbedtls_ccm_set_lengths() have been executed
149      */
150     if( !(ctx->state & CCM_STATE__STARTED) || !(ctx->state & CCM_STATE__LENGHTS_SET) )
151         return 0;
152 
153     /* CCM expects non-empty tag.
154      * CCM* allows empty tag. For CCM* without tag, ignore plaintext length.
155      */
156     if( ctx->tag_len == 0 )
157     {
158         if( ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT || ctx->mode == MBEDTLS_CCM_STAR_DECRYPT )
159         {
160             ctx->plaintext_len = 0;
161         }
162         else
163         {
164             return( MBEDTLS_ERR_CCM_BAD_INPUT );
165         }
166     }
167 
168     /*
169      * First block:
170      * 0        .. 0        flags
171      * 1        .. iv_len   nonce (aka iv)  - set by: mbedtls_ccm_starts()
172      * iv_len+1 .. 15       length
173      *
174      * With flags as (bits):
175      * 7        0
176      * 6        add present?
177      * 5 .. 3   (t - 2) / 2
178      * 2 .. 0   q - 1
179      */
180     ctx->y[0] |= ( ctx->add_len > 0 ) << 6;
181     ctx->y[0] |= ( ( ctx->tag_len - 2 ) / 2 ) << 3;
182     ctx->y[0] |= ctx->q - 1;
183 
184     for( i = 0, len_left = ctx->plaintext_len; i < ctx->q; i++, len_left >>= 8 )
185         ctx->y[15-i] = MBEDTLS_BYTE_0( len_left );
186 
187     if( len_left > 0 )
188     {
189         ctx->state |= CCM_STATE__ERROR;
190         return( MBEDTLS_ERR_CCM_BAD_INPUT );
191     }
192 
193     /* Start CBC-MAC with first block*/
194     if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen ) ) != 0 )
195     {
196         ctx->state |= CCM_STATE__ERROR;
197         return( ret );
198     }
199 
200     return (0);
201 }
202 
mbedtls_ccm_starts(mbedtls_ccm_context * ctx,int mode,const unsigned char * iv,size_t iv_len)203 int mbedtls_ccm_starts( mbedtls_ccm_context *ctx,
204                         int mode,
205                         const unsigned char *iv,
206                         size_t iv_len )
207 {
208     /* Also implies q is within bounds */
209     if( iv_len < 7 || iv_len > 13 )
210         return( MBEDTLS_ERR_CCM_BAD_INPUT );
211 
212     ctx->mode = mode;
213     ctx->q = 16 - 1 - (unsigned char) iv_len;
214 
215     /*
216      * Prepare counter block for encryption:
217      * 0        .. 0        flags
218      * 1        .. iv_len   nonce (aka iv)
219      * iv_len+1 .. 15       counter (initially 1)
220      *
221      * With flags as (bits):
222      * 7 .. 3   0
223      * 2 .. 0   q - 1
224      */
225     memset( ctx->ctr, 0, 16);
226     ctx->ctr[0] = ctx->q - 1;
227     memcpy( ctx->ctr + 1, iv, iv_len );
228     memset( ctx->ctr + 1 + iv_len, 0, ctx->q );
229     ctx->ctr[15] = 1;
230 
231     /*
232      * See ccm_calculate_first_block_if_ready() for block layout description
233      */
234     memcpy( ctx->y + 1, iv, iv_len );
235 
236     ctx->state |= CCM_STATE__STARTED;
237     return ccm_calculate_first_block_if_ready(ctx);
238 }
239 
mbedtls_ccm_set_lengths(mbedtls_ccm_context * ctx,size_t total_ad_len,size_t plaintext_len,size_t tag_len)240 int mbedtls_ccm_set_lengths( mbedtls_ccm_context *ctx,
241                              size_t total_ad_len,
242                              size_t plaintext_len,
243                              size_t tag_len )
244 {
245     /*
246      * Check length requirements: SP800-38C A.1
247      * Additional requirement: a < 2^16 - 2^8 to simplify the code.
248      * 'length' checked later (when writing it to the first block)
249      *
250      * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4).
251      */
252     if( tag_len == 2 || tag_len > 16 || tag_len % 2 != 0 )
253         return( MBEDTLS_ERR_CCM_BAD_INPUT );
254 
255     if( total_ad_len >= 0xFF00 )
256         return( MBEDTLS_ERR_CCM_BAD_INPUT );
257 
258     ctx->plaintext_len = plaintext_len;
259     ctx->add_len = total_ad_len;
260     ctx->tag_len = tag_len;
261     ctx->processed = 0;
262 
263     ctx->state |= CCM_STATE__LENGHTS_SET;
264     return ccm_calculate_first_block_if_ready(ctx);
265 }
266 
mbedtls_ccm_update_ad(mbedtls_ccm_context * ctx,const unsigned char * add,size_t add_len)267 int mbedtls_ccm_update_ad( mbedtls_ccm_context *ctx,
268                            const unsigned char *add,
269                            size_t add_len )
270 {
271     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
272     unsigned char i;
273     size_t olen, use_len, offset;
274 
275     if( ctx->state & CCM_STATE__ERROR )
276     {
277         return MBEDTLS_ERR_CCM_BAD_INPUT;
278     }
279 
280     if( add_len > 0 )
281     {
282         if( ctx->state & CCM_STATE__AUTH_DATA_FINISHED )
283         {
284             return MBEDTLS_ERR_CCM_BAD_INPUT;
285         }
286 
287         if( !(ctx->state & CCM_STATE__AUTH_DATA_STARTED) )
288         {
289             if ( add_len > ctx->add_len )
290             {
291                 return MBEDTLS_ERR_CCM_BAD_INPUT;
292             }
293 
294             ctx->y[0] ^= (unsigned char)( ( ctx->add_len >> 8 ) & 0xFF );
295             ctx->y[1] ^= (unsigned char)( ( ctx->add_len      ) & 0xFF );
296 
297             ctx->state |= CCM_STATE__AUTH_DATA_STARTED;
298         }
299         else if ( ctx->processed + add_len > ctx->add_len )
300         {
301             return MBEDTLS_ERR_CCM_BAD_INPUT;
302         }
303 
304         while( add_len > 0 )
305         {
306             offset = (ctx->processed + 2) % 16; /* account for y[0] and y[1]
307                                                  * holding total auth data length */
308             use_len = 16 - offset;
309 
310             if( use_len > add_len )
311                 use_len = add_len;
312 
313             for( i = 0; i < use_len; i++ )
314                 ctx->y[i + offset] ^= add[i];
315 
316             ctx->processed += use_len;
317             add_len -= use_len;
318             add += use_len;
319 
320             if( use_len + offset == 16 || ctx->processed == ctx->add_len )
321             {
322                 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen ) ) != 0 )
323                 {
324                     ctx->state |= CCM_STATE__ERROR;
325                     return( ret );
326                 }
327             }
328         }
329 
330         if( ctx->processed == ctx->add_len )
331         {
332             ctx->state |= CCM_STATE__AUTH_DATA_FINISHED;
333             ctx->processed = 0; // prepare for mbedtls_ccm_update()
334         }
335     }
336 
337     return (0);
338 }
339 
mbedtls_ccm_update(mbedtls_ccm_context * ctx,const unsigned char * input,size_t input_len,unsigned char * output,size_t output_size,size_t * output_len)340 int mbedtls_ccm_update( mbedtls_ccm_context *ctx,
341                         const unsigned char *input, size_t input_len,
342                         unsigned char *output, size_t output_size,
343                         size_t *output_len )
344 {
345     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
346     unsigned char i;
347     size_t use_len, offset, olen;
348 
349     unsigned char local_output[16];
350 
351     if( ctx->state & CCM_STATE__ERROR )
352     {
353         return MBEDTLS_ERR_CCM_BAD_INPUT;
354     }
355 
356     /* Check against plaintext length only if performing operation with
357      * authentication
358      */
359     if( ctx->tag_len != 0 && ctx->processed + input_len > ctx->plaintext_len )
360     {
361         return MBEDTLS_ERR_CCM_BAD_INPUT;
362     }
363 
364     if( output_size < input_len )
365         return( MBEDTLS_ERR_CCM_BAD_INPUT );
366     *output_len = input_len;
367 
368     ret = 0;
369 
370     while ( input_len > 0 )
371     {
372         offset = ctx->processed % 16;
373 
374         use_len = 16 - offset;
375 
376         if( use_len > input_len )
377             use_len = input_len;
378 
379         ctx->processed += use_len;
380 
381         if( ctx->mode == MBEDTLS_CCM_ENCRYPT || \
382             ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT )
383         {
384             for( i = 0; i < use_len; i++ )
385                 ctx->y[i + offset] ^= input[i];
386 
387             if( use_len + offset == 16 || ctx->processed == ctx->plaintext_len )
388             {
389                 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen ) ) != 0 )
390                 {
391                     ctx->state |= CCM_STATE__ERROR;
392                     goto exit;
393                 }
394             }
395 
396             ret = mbedtls_ccm_crypt( ctx, offset, use_len, input, output );
397             if( ret != 0 )
398                 goto exit;
399         }
400 
401         if( ctx->mode == MBEDTLS_CCM_DECRYPT || \
402             ctx->mode == MBEDTLS_CCM_STAR_DECRYPT )
403         {
404             /* Since output may be in shared memory, we cannot be sure that
405              * it will contain what we wrote to it. Therefore, we should avoid using
406              * it as input to any operations.
407              * Write decrypted data to local_output to avoid using output variable as
408              * input in the XOR operation for Y.
409              */
410             ret = mbedtls_ccm_crypt( ctx, offset, use_len, input, local_output );
411             if( ret != 0 )
412                 goto exit;
413 
414             for( i = 0; i < use_len; i++ )
415                 ctx->y[i + offset] ^= local_output[i];
416 
417             memcpy( output, local_output, use_len );
418             mbedtls_platform_zeroize( local_output, 16 );
419 
420             if( use_len + offset == 16 || ctx->processed == ctx->plaintext_len )
421             {
422                 if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen ) ) != 0 )
423                 {
424                     ctx->state |= CCM_STATE__ERROR;
425                     goto exit;
426                 }
427             }
428         }
429 
430         if( use_len + offset == 16 || ctx->processed == ctx->plaintext_len )
431         {
432             for( i = 0; i < ctx->q; i++ )
433             if( ++(ctx->ctr)[15-i] != 0 )
434                 break;
435         }
436 
437         input_len -= use_len;
438         input += use_len;
439         output += use_len;
440     }
441 
442 exit:
443     mbedtls_platform_zeroize( local_output, 16 );
444 
445     return ret;
446 }
447 
mbedtls_ccm_finish(mbedtls_ccm_context * ctx,unsigned char * tag,size_t tag_len)448 int mbedtls_ccm_finish( mbedtls_ccm_context *ctx,
449                         unsigned char *tag, size_t tag_len )
450 {
451     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
452     unsigned char i;
453 
454     if( ctx->state & CCM_STATE__ERROR )
455     {
456         return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
457     }
458 
459     if( ctx->add_len > 0 && !( ctx->state & CCM_STATE__AUTH_DATA_FINISHED ) )
460     {
461         return MBEDTLS_ERR_CCM_BAD_INPUT;
462     }
463 
464     if( ctx->plaintext_len > 0 && ctx->processed != ctx->plaintext_len )
465     {
466         return MBEDTLS_ERR_CCM_BAD_INPUT;
467     }
468 
469     /*
470      * Authentication: reset counter and crypt/mask internal tag
471      */
472     for( i = 0; i < ctx->q; i++ )
473         ctx->ctr[15-i] = 0;
474 
475     ret = mbedtls_ccm_crypt( ctx, 0, 16, ctx->y, ctx->y );
476     if( ret != 0 )
477         return ret;
478     if( tag != NULL )
479         memcpy( tag, ctx->y, tag_len );
480     mbedtls_ccm_clear_state(ctx);
481 
482     return( 0 );
483 }
484 
485 /*
486  * Authenticated encryption or decryption
487  */
ccm_auth_crypt(mbedtls_ccm_context * ctx,int mode,size_t length,const unsigned char * iv,size_t iv_len,const unsigned char * add,size_t add_len,const unsigned char * input,unsigned char * output,unsigned char * tag,size_t tag_len)488 static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length,
489                            const unsigned char *iv, size_t iv_len,
490                            const unsigned char *add, size_t add_len,
491                            const unsigned char *input, unsigned char *output,
492                            unsigned char *tag, size_t tag_len )
493 {
494     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
495     size_t olen;
496 
497     if( ( ret = mbedtls_ccm_starts( ctx, mode, iv, iv_len ) ) != 0 )
498         return( ret );
499 
500     if( ( ret = mbedtls_ccm_set_lengths( ctx, add_len, length, tag_len ) ) != 0 )
501         return( ret );
502 
503     if( ( ret = mbedtls_ccm_update_ad( ctx, add, add_len ) ) != 0 )
504         return( ret );
505 
506     if( ( ret = mbedtls_ccm_update( ctx, input, length,
507                                     output, length, &olen ) ) != 0 )
508         return( ret );
509 
510     if( ( ret = mbedtls_ccm_finish( ctx, tag, tag_len ) ) != 0 )
511         return( ret );
512 
513     return( 0 );
514 }
515 
516 /*
517  * Authenticated encryption
518  */
mbedtls_ccm_star_encrypt_and_tag(mbedtls_ccm_context * ctx,size_t length,const unsigned char * iv,size_t iv_len,const unsigned char * add,size_t add_len,const unsigned char * input,unsigned char * output,unsigned char * tag,size_t tag_len)519 int mbedtls_ccm_star_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
520                          const unsigned char *iv, size_t iv_len,
521                          const unsigned char *add, size_t add_len,
522                          const unsigned char *input, unsigned char *output,
523                          unsigned char *tag, size_t tag_len )
524 {
525     return( ccm_auth_crypt( ctx, MBEDTLS_CCM_STAR_ENCRYPT, length, iv, iv_len,
526                             add, add_len, input, output, tag, tag_len ) );
527 }
528 
mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context * ctx,size_t length,const unsigned char * iv,size_t iv_len,const unsigned char * add,size_t add_len,const unsigned char * input,unsigned char * output,unsigned char * tag,size_t tag_len)529 int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
530                          const unsigned char *iv, size_t iv_len,
531                          const unsigned char *add, size_t add_len,
532                          const unsigned char *input, unsigned char *output,
533                          unsigned char *tag, size_t tag_len )
534 {
535     return( ccm_auth_crypt( ctx, MBEDTLS_CCM_ENCRYPT, length, iv, iv_len,
536                             add, add_len, input, output, tag, tag_len ) );
537 }
538 
539 /*
540  * Authenticated decryption
541  */
mbedtls_ccm_compare_tags(const unsigned char * tag1,const unsigned char * tag2,size_t tag_len)542 static int mbedtls_ccm_compare_tags(const unsigned char *tag1, const unsigned char *tag2, size_t tag_len)
543 {
544     unsigned char i;
545     int diff;
546 
547     /* Check tag in "constant-time" */
548     for( diff = 0, i = 0; i < tag_len; i++ )
549         diff |= tag1[i] ^ tag2[i];
550 
551     if( diff != 0 )
552     {
553         return( MBEDTLS_ERR_CCM_AUTH_FAILED );
554     }
555 
556     return( 0 );
557 }
558 
ccm_auth_decrypt(mbedtls_ccm_context * ctx,int mode,size_t length,const unsigned char * iv,size_t iv_len,const unsigned char * add,size_t add_len,const unsigned char * input,unsigned char * output,const unsigned char * tag,size_t tag_len)559 static int ccm_auth_decrypt( mbedtls_ccm_context *ctx, int mode, size_t length,
560                              const unsigned char *iv, size_t iv_len,
561                              const unsigned char *add, size_t add_len,
562                              const unsigned char *input, unsigned char *output,
563                              const unsigned char *tag, size_t tag_len )
564 {
565     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
566     unsigned char check_tag[16];
567 
568     if( ( ret = ccm_auth_crypt( ctx, mode, length,
569                                 iv, iv_len, add, add_len,
570                                 input, output, check_tag, tag_len ) ) != 0 )
571     {
572         return( ret );
573     }
574 
575     if( ( ret = mbedtls_ccm_compare_tags( tag, check_tag, tag_len ) ) != 0 )
576     {
577         mbedtls_platform_zeroize( output, length );
578         return( ret );
579     }
580 
581     return( 0 );
582 }
583 
mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context * ctx,size_t length,const unsigned char * iv,size_t iv_len,const unsigned char * add,size_t add_len,const unsigned char * input,unsigned char * output,const unsigned char * tag,size_t tag_len)584 int mbedtls_ccm_star_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
585                       const unsigned char *iv, size_t iv_len,
586                       const unsigned char *add, size_t add_len,
587                       const unsigned char *input, unsigned char *output,
588                       const unsigned char *tag, size_t tag_len )
589 {
590     return ccm_auth_decrypt( ctx, MBEDTLS_CCM_STAR_DECRYPT, length,
591                              iv, iv_len, add, add_len,
592                              input, output, tag, tag_len );
593 }
594 
mbedtls_ccm_auth_decrypt(mbedtls_ccm_context * ctx,size_t length,const unsigned char * iv,size_t iv_len,const unsigned char * add,size_t add_len,const unsigned char * input,unsigned char * output,const unsigned char * tag,size_t tag_len)595 int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
596                       const unsigned char *iv, size_t iv_len,
597                       const unsigned char *add, size_t add_len,
598                       const unsigned char *input, unsigned char *output,
599                       const unsigned char *tag, size_t tag_len )
600 {
601     return ccm_auth_decrypt( ctx, MBEDTLS_CCM_DECRYPT, length,
602                              iv, iv_len, add, add_len,
603                              input, output, tag, tag_len );
604 }
605 #endif /* !MBEDTLS_CCM_ALT */
606 
607 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
608 /*
609  * Examples 1 to 3 from SP800-38C Appendix C
610  */
611 
612 #define NB_TESTS 3
613 #define CCM_SELFTEST_PT_MAX_LEN 24
614 #define CCM_SELFTEST_CT_MAX_LEN 32
615 /*
616  * The data is the same for all tests, only the used length changes
617  */
618 static const unsigned char key_test_data[] = {
619     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
620     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
621 };
622 
623 static const unsigned char iv_test_data[] = {
624     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
625     0x18, 0x19, 0x1a, 0x1b
626 };
627 
628 static const unsigned char ad_test_data[] = {
629     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
630     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
631     0x10, 0x11, 0x12, 0x13
632 };
633 
634 static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = {
635     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
636     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
637     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
638 };
639 
640 static const size_t iv_len_test_data [NB_TESTS] = { 7, 8,  12 };
641 static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 };
642 static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 };
643 static const size_t tag_len_test_data[NB_TESTS] = { 4, 6,  8  };
644 
645 static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = {
646     {   0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
647     {   0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
648         0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
649         0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
650     {   0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
651         0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
652         0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
653         0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
654 };
655 
mbedtls_ccm_self_test(int verbose)656 int mbedtls_ccm_self_test( int verbose )
657 {
658     mbedtls_ccm_context ctx;
659     /*
660      * Some hardware accelerators require the input and output buffers
661      * would be in RAM, because the flash is not accessible.
662      * Use buffers on the stack to hold the test vectors data.
663      */
664     unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN];
665     unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN];
666     size_t i;
667     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
668 
669     mbedtls_ccm_init( &ctx );
670 
671     if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key_test_data,
672                             8 * sizeof key_test_data ) != 0 )
673     {
674         if( verbose != 0 )
675             mbedtls_printf( "  CCM: setup failed" );
676 
677         return( 1 );
678     }
679 
680     for( i = 0; i < NB_TESTS; i++ )
681     {
682         if( verbose != 0 )
683             mbedtls_printf( "  CCM-AES #%u: ", (unsigned int) i + 1 );
684 
685         memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN );
686         memset( ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN );
687         memcpy( plaintext, msg_test_data, msg_len_test_data[i] );
688 
689         ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len_test_data[i],
690                                            iv_test_data, iv_len_test_data[i],
691                                            ad_test_data, add_len_test_data[i],
692                                            plaintext, ciphertext,
693                                            ciphertext + msg_len_test_data[i],
694                                            tag_len_test_data[i] );
695 
696         if( ret != 0 ||
697             memcmp( ciphertext, res_test_data[i],
698                     msg_len_test_data[i] + tag_len_test_data[i] ) != 0 )
699         {
700             if( verbose != 0 )
701                 mbedtls_printf( "failed\n" );
702 
703             return( 1 );
704         }
705         memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN );
706 
707         ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len_test_data[i],
708                                         iv_test_data, iv_len_test_data[i],
709                                         ad_test_data, add_len_test_data[i],
710                                         ciphertext, plaintext,
711                                         ciphertext + msg_len_test_data[i],
712                                         tag_len_test_data[i] );
713 
714         if( ret != 0 ||
715             memcmp( plaintext, msg_test_data, msg_len_test_data[i] ) != 0 )
716         {
717             if( verbose != 0 )
718                 mbedtls_printf( "failed\n" );
719 
720             return( 1 );
721         }
722 
723         if( verbose != 0 )
724             mbedtls_printf( "passed\n" );
725     }
726 
727     mbedtls_ccm_free( &ctx );
728 
729     if( verbose != 0 )
730         mbedtls_printf( "\n" );
731 
732     return( 0 );
733 }
734 
735 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
736 
737 #endif /* MBEDTLS_CCM_C */
738