Merge branch 'development' into ccm_chunked

Conflicts:
	library/ccm.c

Conflict resolved by re-applying the MBEDTLS_BYTE_0 macro.
Conflict resolved by ignoring the MBEDTLS_PUT_UINT16_BE macro
used in development branch on the 'b' buffer, because the 'b'
buffer is removed in current branch.
diff --git a/ChangeLog.d/chunked_ccm.txt b/ChangeLog.d/chunked_ccm.txt
new file mode 100644
index 0000000..67faecc
--- /dev/null
+++ b/ChangeLog.d/chunked_ccm.txt
@@ -0,0 +1,8 @@
+Changes
+   * Implement multi-part CCM API.
+     The multi-part functions: mbedtls_ccm_starts(), mbedtls_ccm_set_lengths(),
+     mbedtls_ccm_update_ad(), mbedtls_ccm_update(), mbedtls_ccm_finish()
+     were introduced in mbedTLS 3.0 release, however their implementation was
+     postponed until now.
+     Implemented functions support chunked data input for both CCM and CCM*
+     algorithms.
diff --git a/include/mbedtls/ccm.h b/include/mbedtls/ccm.h
index b3adecc..8aacfce 100644
--- a/include/mbedtls/ccm.h
+++ b/include/mbedtls/ccm.h
@@ -61,6 +61,8 @@
 #define MBEDTLS_ERR_CCM_BAD_INPUT       -0x000D
 /** Authenticated decryption failed. */
 #define MBEDTLS_ERR_CCM_AUTH_FAILED     -0x000F
+/** CCM functions called in the wrong sequence. */
+#define MBEDTLS_ERR_CCM_BAD_SEQUENCE    -0x0011
 
 #ifdef __cplusplus
 extern "C" {
@@ -76,7 +78,27 @@
  */
 typedef struct mbedtls_ccm_context
 {
+    unsigned char MBEDTLS_PRIVATE(y)[16];    /*!< The Y working buffer */
+    unsigned char MBEDTLS_PRIVATE(ctr)[16];  /*!< The counter buffer */
     mbedtls_cipher_context_t MBEDTLS_PRIVATE(cipher_ctx);    /*!< The cipher context used. */
+    size_t MBEDTLS_PRIVATE(plaintext_len);   /*!< Total plaintext length */
+    size_t MBEDTLS_PRIVATE(add_len);         /*!< Total authentication data length */
+    size_t MBEDTLS_PRIVATE(tag_len);         /*!< Total tag length */
+    size_t MBEDTLS_PRIVATE(processed);       /*!< Track how many bytes of input data
+                                                  were processed (chunked input).
+                                                  Used indepenedantly for both auth data
+                                                  and plaintext/ciphertext.
+                                                  This variable is set to zero after
+                                                  auth data input is finished. */
+    unsigned char MBEDTLS_PRIVATE(q);        /*!< The Q working value */
+    unsigned char MBEDTLS_PRIVATE(mode);     /*!< The operation to perform:
+                                                  #MBEDTLS_CCM_ENCRYPT or
+                                                  #MBEDTLS_CCM_DECRYPT or
+                                                  #MBEDTLS_CCM_STAR_ENCRYPT or
+                                                  #MBEDTLS_CCM_STAR_DECRYPT. */
+    int MBEDTLS_PRIVATE(state);              /*!< Working value holding context's
+                                                  state. Used for chunked data
+                                                  input */
 }
 mbedtls_ccm_context;
 
diff --git a/library/ccm.c b/library/ccm.c
index a21a37f..0a90461 100644
--- a/library/ccm.c
+++ b/library/ccm.c
@@ -36,31 +36,23 @@
 
 #include <string.h>
 
-#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
 #if defined(MBEDTLS_PLATFORM_C)
 #include "mbedtls/platform.h"
 #else
+#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
 #include <stdio.h>
 #define mbedtls_printf printf
-#endif /* MBEDTLS_PLATFORM_C */
 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
+#endif /* MBEDTLS_PLATFORM_C */
 
 #if !defined(MBEDTLS_CCM_ALT)
 
-#define CCM_VALIDATE_RET( cond ) \
-    MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CCM_BAD_INPUT )
-#define CCM_VALIDATE( cond ) \
-    MBEDTLS_INTERNAL_VALIDATE( cond )
-
-#define CCM_ENCRYPT 0
-#define CCM_DECRYPT 1
 
 /*
  * Initialize context
  */
 void mbedtls_ccm_init( mbedtls_ccm_context *ctx )
 {
-    CCM_VALIDATE( ctx != NULL );
     memset( ctx, 0, sizeof( mbedtls_ccm_context ) );
 }
 
@@ -72,9 +64,6 @@
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     const mbedtls_cipher_info_t *cipher_info;
 
-    CCM_VALIDATE_RET( ctx != NULL );
-    CCM_VALIDATE_RET( key != NULL );
-
     cipher_info = mbedtls_cipher_info_from_values( cipher, keybits,
                                                    MBEDTLS_MODE_ECB );
     if( cipher_info == NULL )
@@ -108,82 +97,67 @@
     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ccm_context ) );
 }
 
-/*
- * Macros for common operations.
- * Results in smaller compiled code than static inline functions.
- */
-
-/*
- * Update the CBC-MAC state in y using a block in b
- * (Always using b as the source helps the compiler optimise a bit better.)
- */
-#define UPDATE_CBC_MAC                                                      \
-    for( i = 0; i < 16; i++ )                                               \
-        y[i] ^= b[i];                                                       \
-                                                                            \
-    if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \
-        return( ret );
+#define CCM_STATE__CLEAR                0
+#define CCM_STATE__STARTED              (1 << 0)
+#define CCM_STATE__LENGHTS_SET          (1 << 1)
+#define CCM_STATE__AUTH_DATA_STARTED    (1 << 2)
+#define CCM_STATE__AUTH_DATA_FINISHED   (1 << 3)
+#define CCM_STATE__ERROR                (1 << 4)
 
 /*
  * Encrypt or decrypt a partial block with CTR
- * Warning: using b for temporary storage! src and dst must not be b!
- * This avoids allocating one more 16 bytes buffer while allowing src == dst.
  */
-#define CTR_CRYPT( dst, src, len  )                                            \
-    do                                                                  \
-    {                                                                   \
-        if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr,       \
-                                           16, b, &olen ) ) != 0 )      \
-        {                                                               \
-            return( ret );                                              \
-        }                                                               \
-                                                                        \
-        for( i = 0; i < (len); i++ )                                    \
-            (dst)[i] = (src)[i] ^ b[i];                                 \
-    } while( 0 )
+static int mbedtls_ccm_crypt( mbedtls_ccm_context *ctx,
+                              size_t offset, size_t use_len,
+                              const unsigned char *input,
+                              unsigned char *output )
+{
+    size_t i;
+    size_t olen = 0;
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    unsigned char tmp_buf[16] = {0};
 
-/*
- * Authenticated encryption or decryption
- */
-static int 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 )
+    if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->ctr, 16, tmp_buf,
+                                       &olen ) ) != 0 )
+    {
+        ctx->state |= CCM_STATE__ERROR;
+        mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
+        return ret;
+    }
+
+    for( i = 0; i < use_len; i++ )
+        output[i] = input[i] ^ tmp_buf[offset + i];
+
+    mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
+    return ret;
+}
+
+static void mbedtls_ccm_clear_state(mbedtls_ccm_context *ctx) {
+    ctx->state = CCM_STATE__CLEAR;
+    memset( ctx->y, 0, 16);
+    memset( ctx->ctr, 0, 16);
+}
+
+static int ccm_calculate_first_block_if_ready(mbedtls_ccm_context *ctx)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char i;
-    unsigned char q;
     size_t len_left, olen;
-    unsigned char b[16];
-    unsigned char y[16];
-    unsigned char ctr[16];
-    const unsigned char *src;
-    unsigned char *dst;
 
-    /*
-     * Check length requirements: SP800-38C A.1
-     * Additional requirement: a < 2^16 - 2^8 to simplify the code.
-     * 'length' checked later (when writing it to the first block)
-     *
-     * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4).
+    /* length calulcation can be done only after both
+     * mbedtls_ccm_starts() and mbedtls_ccm_set_lengths() have been executed
      */
-    if( tag_len == 2 || tag_len > 16 || tag_len % 2 != 0 )
-        return( MBEDTLS_ERR_CCM_BAD_INPUT );
+    if( !(ctx->state & CCM_STATE__STARTED) || !(ctx->state & CCM_STATE__LENGHTS_SET) )
+        return 0;
 
-    /* Also implies q is within bounds */
-    if( iv_len < 7 || iv_len > 13 )
+    if( ctx->tag_len == 0 && \
+        ( ctx->mode == MBEDTLS_CCM_ENCRYPT || ctx->mode == MBEDTLS_CCM_DECRYPT ) )
         return( MBEDTLS_ERR_CCM_BAD_INPUT );
 
-    if( add_len >= 0xFF00 )
-        return( MBEDTLS_ERR_CCM_BAD_INPUT );
-
-    q = 16 - 1 - (unsigned char) iv_len;
-
     /*
-     * First block B_0:
+     * First block:
      * 0        .. 0        flags
-     * 1        .. iv_len   nonce (aka iv)
+     * 1        .. iv_len   nonce (aka iv)  - set by: mbedtls_ccm_starts()
      * iv_len+1 .. 15       length
      *
      * With flags as (bits):
@@ -192,56 +166,40 @@
      * 5 .. 3   (t - 2) / 2
      * 2 .. 0   q - 1
      */
-    b[0] = 0;
-    b[0] |= ( add_len > 0 ) << 6;
-    b[0] |= ( ( tag_len - 2 ) / 2 ) << 3;
-    b[0] |= q - 1;
+    ctx->y[0] |= ( ctx->add_len > 0 ) << 6;
+    ctx->y[0] |= ( ( ctx->tag_len - 2 ) / 2 ) << 3;
+    ctx->y[0] |= ctx->q - 1;
 
-    memcpy( b + 1, iv, iv_len );
-
-    for( i = 0, len_left = length; i < q; i++, len_left >>= 8 )
-        b[15-i] = MBEDTLS_BYTE_0( len_left );
+    for( i = 0, len_left = ctx->plaintext_len; i < ctx->q; i++, len_left >>= 8 )
+        ctx->y[15-i] = MBEDTLS_BYTE_0( len_left );
 
     if( len_left > 0 )
+    {
+        ctx->state |= CCM_STATE__ERROR;
+        return( MBEDTLS_ERR_CCM_BAD_INPUT );
+    }
+
+    /* Start CBC-MAC with first block*/
+    if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen ) ) != 0 )
+    {
+        ctx->state |= CCM_STATE__ERROR;
+        return( ret );
+    }
+
+    return (0);
+}
+
+int mbedtls_ccm_starts( mbedtls_ccm_context *ctx,
+                        int mode,
+                        const unsigned char *iv,
+                        size_t iv_len )
+{
+    /* Also implies q is within bounds */
+    if( iv_len < 7 || iv_len > 13 )
         return( MBEDTLS_ERR_CCM_BAD_INPUT );
 
-
-    /* Start CBC-MAC with first block */
-    memset( y, 0, 16 );
-    UPDATE_CBC_MAC;
-
-    /*
-     * If there is additional data, update CBC-MAC with
-     * add_len, add, 0 (padding to a block boundary)
-     */
-    if( add_len > 0 )
-    {
-        size_t use_len;
-        len_left = add_len;
-        src = add;
-
-        memset( b, 0, 16 );
-        MBEDTLS_PUT_UINT16_BE( add_len, b, 0 );
-
-        use_len = len_left < 16 - 2 ? len_left : 16 - 2;
-        memcpy( b + 2, src, use_len );
-        len_left -= use_len;
-        src += use_len;
-
-        UPDATE_CBC_MAC;
-
-        while( len_left > 0 )
-        {
-            use_len = len_left > 16 ? 16 : len_left;
-
-            memset( b, 0, 16 );
-            memcpy( b, src, use_len );
-            UPDATE_CBC_MAC;
-
-            len_left -= use_len;
-            src += use_len;
-        }
-    }
+    ctx->mode = mode;
+    ctx->q = 16 - 1 - (unsigned char) iv_len;
 
     /*
      * Prepare counter block for encryption:
@@ -253,62 +211,290 @@
      * 7 .. 3   0
      * 2 .. 0   q - 1
      */
-    ctr[0] = q - 1;
-    memcpy( ctr + 1, iv, iv_len );
-    memset( ctr + 1 + iv_len, 0, q );
-    ctr[15] = 1;
+    memset( ctx->ctr, 0, 16);
+    ctx->ctr[0] = ctx->q - 1;
+    memcpy( ctx->ctr + 1, iv, iv_len );
+    memset( ctx->ctr + 1 + iv_len, 0, ctx->q );
+    ctx->ctr[15] = 1;
 
     /*
-     * Authenticate and {en,de}crypt the message.
-     *
-     * The only difference between encryption and decryption is
-     * the respective order of authentication and {en,de}cryption.
+     * See ccm_calculate_first_block_if_ready() for block layout description
      */
-    len_left = length;
-    src = input;
-    dst = output;
+    memcpy( ctx->y + 1, iv, iv_len );
 
-    while( len_left > 0 )
+    ctx->state |= CCM_STATE__STARTED;
+    return ccm_calculate_first_block_if_ready(ctx);
+}
+
+int mbedtls_ccm_set_lengths( mbedtls_ccm_context *ctx,
+                             size_t total_ad_len,
+                             size_t plaintext_len,
+                             size_t tag_len )
+{
+    /*
+     * Check length requirements: SP800-38C A.1
+     * Additional requirement: a < 2^16 - 2^8 to simplify the code.
+     * 'length' checked later (when writing it to the first block)
+     *
+     * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4).
+     */
+    if( tag_len == 2 || tag_len > 16 || tag_len % 2 != 0 )
+        return( MBEDTLS_ERR_CCM_BAD_INPUT );
+
+    if( total_ad_len >= 0xFF00 )
+        return( MBEDTLS_ERR_CCM_BAD_INPUT );
+
+    ctx->plaintext_len = plaintext_len;
+    ctx->add_len = total_ad_len;
+    ctx->tag_len = tag_len;
+    ctx->processed = 0;
+
+    ctx->state |= CCM_STATE__LENGHTS_SET;
+    return ccm_calculate_first_block_if_ready(ctx);
+}
+
+int mbedtls_ccm_update_ad( mbedtls_ccm_context *ctx,
+                           const unsigned char *add,
+                           size_t add_len )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    unsigned char i;
+    size_t olen, use_len, offset;
+
+    if( ctx->state & CCM_STATE__ERROR )
     {
-        size_t use_len = len_left > 16 ? 16 : len_left;
+        return ret;
+    }
 
-        if( mode == CCM_ENCRYPT )
+    if( ctx->add_len > 0 && add_len > 0 )
+    {
+        if( ctx->state & CCM_STATE__AUTH_DATA_FINISHED )
         {
-            memset( b, 0, 16 );
-            memcpy( b, src, use_len );
-            UPDATE_CBC_MAC;
+            return MBEDTLS_ERR_CCM_BAD_SEQUENCE;
         }
 
-        CTR_CRYPT( dst, src, use_len );
-
-        if( mode == CCM_DECRYPT )
+        if( !(ctx->state & CCM_STATE__AUTH_DATA_STARTED) )
         {
-            memset( b, 0, 16 );
-            memcpy( b, dst, use_len );
-            UPDATE_CBC_MAC;
+            if ( add_len > ctx->add_len )
+            {
+                return MBEDTLS_ERR_CCM_BAD_INPUT;
+            }
+
+            ctx->y[0] ^= (unsigned char)( ( ctx->add_len >> 8 ) & 0xFF );
+            ctx->y[1] ^= (unsigned char)( ( ctx->add_len      ) & 0xFF );
+
+            ctx->state |= CCM_STATE__AUTH_DATA_STARTED;
+        }
+        else if ( ctx->processed + add_len > ctx->add_len )
+        {
+            return MBEDTLS_ERR_CCM_BAD_INPUT;
         }
 
-        dst += use_len;
-        src += use_len;
-        len_left -= use_len;
+        while( add_len > 0 )
+        {
+            offset = (ctx->processed + 2) % 16; /* account for y[0] and y[1]
+                                                 * holding total auth data length */
+            use_len = 16 - offset;
 
-        /*
-         * Increment counter.
-         * No need to check for overflow thanks to the length check above.
-         */
-        for( i = 0; i < q; i++ )
-            if( ++ctr[15-i] != 0 )
+            if( use_len > add_len )
+                use_len = add_len;
+
+            for( i = 0; i < use_len; i++ )
+                ctx->y[i + offset] ^= add[i];
+
+            ctx->processed += use_len;
+            add_len -= use_len;
+            add += use_len;
+
+            if( use_len + offset == 16 || ctx->processed == ctx->add_len )
+            {
+                if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen ) ) != 0 )
+                {
+                    ctx->state |= CCM_STATE__ERROR;
+                    return( ret );
+                }
+            }
+        }
+
+        if( ctx->processed == ctx->add_len )
+        {
+            ctx->state |= CCM_STATE__AUTH_DATA_FINISHED;
+            ctx->processed = 0; // prepare for mbedtls_ccm_update()
+        }
+    }
+
+    return (0);
+}
+
+int 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 )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    unsigned char i;
+    size_t use_len, offset, olen;
+
+    unsigned char local_output[16];
+
+    if( ctx->state & CCM_STATE__ERROR )
+    {
+        return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    }
+
+    if( ctx->processed + input_len > ctx->plaintext_len )
+    {
+        return MBEDTLS_ERR_CCM_BAD_INPUT;
+    }
+
+    if( output_size < input_len )
+        return( MBEDTLS_ERR_CCM_BAD_INPUT );
+    *output_len = input_len;
+
+    ret = 0;
+
+    while ( input_len > 0 )
+    {
+        offset = ctx->processed % 16;
+
+        use_len = 16 - offset;
+
+        if( use_len > input_len )
+            use_len = input_len;
+
+        ctx->processed += use_len;
+
+        if( ctx->mode == MBEDTLS_CCM_ENCRYPT || \
+            ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT )
+        {
+            for( i = 0; i < use_len; i++ )
+                ctx->y[i + offset] ^= input[i];
+
+            if( use_len + offset == 16 || ctx->processed == ctx->plaintext_len )
+            {
+                if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen ) ) != 0 )
+                {
+                    ctx->state |= CCM_STATE__ERROR;
+                    goto exit;
+                }
+            }
+
+            ret = mbedtls_ccm_crypt( ctx, offset, use_len, input, output );
+            if( ret != 0 )
+                goto exit;
+        }
+
+        if( ctx->mode == MBEDTLS_CCM_DECRYPT || \
+            ctx->mode == MBEDTLS_CCM_STAR_DECRYPT )
+        {
+            /* Since output may be in shared memory, we cannot be sure that
+             * it will contain what we wrote to it. Therefore, we should avoid using
+             * it as input to any operations.
+             * Write decrypted data to local_output to avoid using output variable as
+             * input in the XOR operation for Y.
+             */
+            ret = mbedtls_ccm_crypt( ctx, offset, use_len, input, local_output );
+            if( ret != 0 )
+                goto exit;
+
+            for( i = 0; i < use_len; i++ )
+                ctx->y[i + offset] ^= local_output[i];
+
+            memcpy( output, local_output, use_len );
+            mbedtls_platform_zeroize( local_output, 16 );
+
+            if( use_len + offset == 16 || ctx->processed == ctx->plaintext_len )
+            {
+                if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen ) ) != 0 )
+                {
+                    ctx->state |= CCM_STATE__ERROR;
+                    goto exit;
+                }
+            }
+        }
+
+        if( use_len + offset == 16 || ctx->processed == ctx->plaintext_len )
+        {
+            for( i = 0; i < ctx->q; i++ )
+            if( ++(ctx->ctr)[15-i] != 0 )
                 break;
+        }
+
+        input_len -= use_len;
+        input += use_len;
+        output += use_len;
+    }
+
+exit:
+    mbedtls_platform_zeroize( local_output, 16 );
+
+    return ret;
+}
+
+int mbedtls_ccm_finish( mbedtls_ccm_context *ctx,
+                        unsigned char *tag, size_t tag_len )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    unsigned char i;
+
+    if( ctx->state & CCM_STATE__ERROR )
+    {
+        return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    }
+
+    if( ctx->add_len > 0 && !( ctx->state & CCM_STATE__AUTH_DATA_FINISHED ) )
+    {
+        return MBEDTLS_ERR_CCM_BAD_SEQUENCE;
+    }
+
+    if( ctx->plaintext_len > 0 && ctx->processed != ctx->plaintext_len )
+    {
+        return MBEDTLS_ERR_CCM_BAD_SEQUENCE;
     }
 
     /*
      * Authentication: reset counter and crypt/mask internal tag
      */
-    for( i = 0; i < q; i++ )
-        ctr[15-i] = 0;
+    for( i = 0; i < ctx->q; i++ )
+        ctx->ctr[15-i] = 0;
 
-    CTR_CRYPT( y, y, 16 );
-    memcpy( tag, y, tag_len );
+    ret = mbedtls_ccm_crypt( ctx, 0, 16, ctx->y, ctx->y );
+    if( ret != 0 )
+        return ret;
+    if( tag != NULL )
+        memcpy( tag, ctx->y, tag_len );
+    mbedtls_ccm_clear_state(ctx);
+
+    return( 0 );
+}
+
+/*
+ * Authenticated encryption or decryption
+ */
+static int 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 )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    size_t olen;
+
+    if( ( ret = mbedtls_ccm_starts( ctx, mode, iv, iv_len ) ) != 0 )
+        return( ret );
+
+    if( ( ret = mbedtls_ccm_set_lengths( ctx, add_len, length, tag_len ) ) != 0 )
+        return( ret );
+
+    if( ( ret = mbedtls_ccm_update_ad( ctx, add, add_len ) ) != 0 )
+        return( ret );
+
+    if( ( ret = mbedtls_ccm_update( ctx, input, length,
+                                    output, length, &olen ) ) != 0 )
+        return( ret );
+
+    if( ( ret = mbedtls_ccm_finish( ctx, tag, tag_len ) ) != 0 )
+        return( ret );
 
     return( 0 );
 }
@@ -322,13 +508,7 @@
                          const unsigned char *input, unsigned char *output,
                          unsigned char *tag, size_t tag_len )
 {
-    CCM_VALIDATE_RET( ctx != NULL );
-    CCM_VALIDATE_RET( iv != NULL );
-    CCM_VALIDATE_RET( add_len == 0 || add != NULL );
-    CCM_VALIDATE_RET( length == 0 || input != NULL );
-    CCM_VALIDATE_RET( length == 0 || output != NULL );
-    CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
-    return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len,
+    return( ccm_auth_crypt( ctx, MBEDTLS_CCM_STAR_ENCRYPT, length, iv, iv_len,
                             add, add_len, input, output, tag, tag_len ) );
 }
 
@@ -338,78 +518,75 @@
                          const unsigned char *input, unsigned char *output,
                          unsigned char *tag, size_t tag_len )
 {
-    CCM_VALIDATE_RET( ctx != NULL );
-    CCM_VALIDATE_RET( iv != NULL );
-    CCM_VALIDATE_RET( add_len == 0 || add != NULL );
-    CCM_VALIDATE_RET( length == 0 || input != NULL );
-    CCM_VALIDATE_RET( length == 0 || output != NULL );
-    CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
-    if( tag_len == 0 )
-        return( MBEDTLS_ERR_CCM_BAD_INPUT );
-
-    return( mbedtls_ccm_star_encrypt_and_tag( ctx, length, iv, iv_len, add,
-                add_len, input, output, tag, tag_len ) );
+    return( ccm_auth_crypt( ctx, MBEDTLS_CCM_ENCRYPT, length, iv, iv_len,
+                            add, add_len, input, output, tag, tag_len ) );
 }
 
 /*
  * Authenticated decryption
  */
-int 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 )
+static int mbedtls_ccm_compare_tags(const unsigned char *tag1, const unsigned char *tag2, size_t tag_len)
 {
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    unsigned char check_tag[16];
     unsigned char i;
     int diff;
 
-    CCM_VALIDATE_RET( ctx != NULL );
-    CCM_VALIDATE_RET( iv != NULL );
-    CCM_VALIDATE_RET( add_len == 0 || add != NULL );
-    CCM_VALIDATE_RET( length == 0 || input != NULL );
-    CCM_VALIDATE_RET( length == 0 || output != NULL );
-    CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
+    /* Check tag in "constant-time" */
+    for( diff = 0, i = 0; i < tag_len; i++ )
+        diff |= tag1[i] ^ tag2[i];
 
-    if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length,
+    if( diff != 0 )
+    {
+        return( MBEDTLS_ERR_CCM_AUTH_FAILED );
+    }
+
+    return( 0 );
+}
+
+static int 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 )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    unsigned char check_tag[16];
+
+    if( ( ret = ccm_auth_crypt( ctx, mode, length,
                                 iv, iv_len, add, add_len,
                                 input, output, check_tag, tag_len ) ) != 0 )
     {
         return( ret );
     }
 
-    /* Check tag in "constant-time" */
-    for( diff = 0, i = 0; i < tag_len; i++ )
-        diff |= tag[i] ^ check_tag[i];
-
-    if( diff != 0 )
+    if( ( ret = mbedtls_ccm_compare_tags( tag, check_tag, tag_len ) ) != 0 )
     {
         mbedtls_platform_zeroize( output, length );
-        return( MBEDTLS_ERR_CCM_AUTH_FAILED );
+        return( ret );
     }
 
     return( 0 );
 }
 
+int 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 )
+{
+    return ccm_auth_decrypt( ctx, MBEDTLS_CCM_STAR_DECRYPT, length,
+                             iv, iv_len, add, add_len,
+                             input, output, tag, tag_len );
+}
+
 int 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 )
 {
-    CCM_VALIDATE_RET( ctx != NULL );
-    CCM_VALIDATE_RET( iv != NULL );
-    CCM_VALIDATE_RET( add_len == 0 || add != NULL );
-    CCM_VALIDATE_RET( length == 0 || input != NULL );
-    CCM_VALIDATE_RET( length == 0 || output != NULL );
-    CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
-
-    if( tag_len == 0 )
-        return( MBEDTLS_ERR_CCM_BAD_INPUT );
-
-    return( mbedtls_ccm_star_auth_decrypt( ctx, length, iv, iv_len, add,
-                add_len, input, output, tag, tag_len ) );
+    return ccm_auth_decrypt( ctx, MBEDTLS_CCM_DECRYPT, length,
+                             iv, iv_len, add, add_len,
+                             input, output, tag, tag_len );
 }
 #endif /* !MBEDTLS_CCM_ALT */
 
diff --git a/tests/suites/test_suite_ccm.data b/tests/suites/test_suite_ccm.data
index a14d4be..91aa98b 100644
--- a/tests/suites/test_suite_ccm.data
+++ b/tests/suites/test_suite_ccm.data
@@ -1517,3 +1517,143 @@
 CCM-Camellia encrypt and tag RFC 5528 #24
 depends_on:MBEDTLS_CAMELLIA_C
 mbedtls_ccm_encrypt_and_tag:MBEDTLS_CIPHER_ID_CAMELLIA:"D75C2778078CA93D971F96FDE720F4CD":"9DC9EDAE2FF5DF8636E8C6DE0EED55F7867E33337D":"003B8FD8D3A937B160B6A31C1C":"A4D499F78419728C19178B0C":"4B198156393B0F7796086AAFB454F8C3F034CCA966945F1FCEA7E11BEE6A2F"
+
+CCM encrypt, skip ad NIST VADT AES-128 (P=24, N=13, A=0, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_skip_ad:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:"d24a3d3dde8c84830280cb87abad0bb3":"7c86135ed9c2a515aaae0e9a208133897269220f30870006":"f1100035bb24a8d26004e0e24b":"1faeb0ee2ca2cd52f0aa3966578344f24e69b742c4ab37ab":"1123301219c70599b7c373ad4b3ad67b"
+
+CCM* encrypt, skip ad NIST VADT AES-128 (P=24, N=13, A=0, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_skip_ad:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_ENCRYPT:"d24a3d3dde8c84830280cb87abad0bb3":"7c86135ed9c2a515aaae0e9a208133897269220f30870006":"f1100035bb24a8d26004e0e24b":"1faeb0ee2ca2cd52f0aa3966578344f24e69b742c4ab37ab":"1123301219c70599b7c373ad4b3ad67b"
+
+CCM decrypt, skip ad NIST DVPT AES-192 (P=24, N=7, A=0, T=4)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_skip_ad:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:"19ebfde2d5468ba0a3031bde629b11fd4094afcb205393fa":"411986d04d6463100bff03f7d0bde7ea2c3488784378138c":"5a8aa485c316e9":"3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22":"ddc93a54"
+
+CCM* decrypt, skip ad NIST DVPT AES-192 (P=24, N=7, A=0, T=4)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_skip_ad:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_DECRYPT:"19ebfde2d5468ba0a3031bde629b11fd4094afcb205393fa":"411986d04d6463100bff03f7d0bde7ea2c3488784378138c":"5a8aa485c316e9":"3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22":"ddc93a54"
+
+CCM encrypt, skip update NIST VPT AES-128 #1 (P=0, N=13, A=32, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_skip_update:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:"2ebf60f0969013a54a3dedb19d20f6c8":"1de8c5e21f9db33123ff870add":"e1de6c6119d7db471136285d10b47a450221b16978569190ef6a22b055295603":"0ead29ef205fbb86d11abe5ed704b880"
+
+CCM* encrypt, skip update NIST VPT AES-128 #1 (P=0, N=13, A=32, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_skip_update:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_ENCRYPT:"2ebf60f0969013a54a3dedb19d20f6c8":"1de8c5e21f9db33123ff870add":"e1de6c6119d7db471136285d10b47a450221b16978569190ef6a22b055295603":"0ead29ef205fbb86d11abe5ed704b880"
+
+CCM decrypt, skip update NIST DVPT AES-256 #23 (P=0, N=13, A=32, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_skip_update:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:"8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a":"a544218dadd3c10583db49cf39":"3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907":"867b0d87cf6e0f718200a97b4f6d5ad5"
+
+CCM* decrypt, skip update NIST DVPT AES-256 #23 (P=0, N=13, A=32, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_skip_update:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_DECRYPT:"8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a":"a544218dadd3c10583db49cf39":"3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907":"867b0d87cf6e0f718200a97b4f6d5ad5"
+
+CCM encrypt, overflow ad NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_overflow_ad:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM encrypt, incomplete ad NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_incomplete_ad:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM encrypt, full ad and overflow NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_full_ad_and_overflow:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM encrypt, overflow update NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_overflow_update:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM encrypt, incomplete update NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_incomplete_update:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM encrypt, full update and overflow NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_full_update_and_overflow:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM decrypt, overflow ad NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_overflow_ad:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM decrypt, incomplete ad NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_incomplete_ad:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM decrypt, full ad and overflow NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_full_ad_and_overflow:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM decrypt, overflow update NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_overflow_update:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM decrypt, incomplete update NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_incomplete_update:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM decrypt, full update and overflow NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_full_update_and_overflow:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM* encrypt, overflow ad NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_overflow_ad:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_ENCRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM* encrypt, incomplete ad NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_incomplete_ad:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_ENCRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM* encrypt, full ad and overflow NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_full_ad_and_overflow:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_ENCRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM* encrypt, overflow update NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_overflow_update:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_ENCRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM* encrypt, incomplete update NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_incomplete_update:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_ENCRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM* encrypt, full update and overflow NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_full_update_and_overflow:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_ENCRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM* decrypt, overflow ad NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_overflow_ad:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_DECRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM* decrypt, incomplete ad NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_incomplete_ad:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_DECRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM* decrypt, full ad and overflow NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_full_ad_and_overflow:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_DECRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM* decrypt, overflow update NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_overflow_update:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_DECRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM* decrypt, incomplete update NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_incomplete_update:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_DECRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM* decrypt, full update and overflow NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+depends_on:MBEDTLS_AES_C
+mbedtls_ccm_full_update_and_overflow:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_DECRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34":"13501aebda19a9bf1b5ffaa42a":"ead4c45ff9db54f9902a6de181"
+
+CCM encrypt, instant finish NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+mbedtls_ccm_instant_finish:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a"
+
+CCM decrypt, instant finish NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+mbedtls_ccm_instant_finish:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a"
+
+CCM* encrypt, instant finish NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+mbedtls_ccm_instant_finish:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_ENCRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a"
+
+CCM* decrypt, instant finish NIST VADT AES-192 #14 (P=24, N=13, A=13, T=16)
+mbedtls_ccm_instant_finish:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_DECRYPT:"b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731":"13501aebda19a9bf1b5ffaa42a"
diff --git a/tests/suites/test_suite_ccm.function b/tests/suites/test_suite_ccm.function
index 840583c..48c4fe9 100644
--- a/tests/suites/test_suite_ccm.function
+++ b/tests/suites/test_suite_ccm.function
@@ -1,5 +1,64 @@
 /* BEGIN_HEADER */
 #include "mbedtls/ccm.h"
+
+/* Use the multipart interface to process the encrypted data in two parts
+ * and check that the output matches the expected output.
+ * The context must have been set up with the key. */
+static int check_multipart( mbedtls_ccm_context *ctx,
+                            int mode,
+                            const data_t *iv,
+                            const data_t *add,
+                            const data_t *input,
+                            const data_t *expected_output,
+                            const data_t *tag,
+                            size_t n1,
+                            size_t n1_add)
+{
+    int ok = 0;
+    uint8_t *output = NULL;
+    size_t n2 = input->len - n1;
+    size_t n2_add = add->len - n1_add;
+    size_t olen;
+
+    /* Sanity checks on the test data */
+    TEST_ASSERT( n1 <= input->len );
+    TEST_ASSERT( n1_add <= add->len );
+    TEST_EQUAL( input->len, expected_output->len );
+    TEST_EQUAL( 0, mbedtls_ccm_starts( ctx, mode, iv->x, iv->len ) );
+    TEST_EQUAL( 0, mbedtls_ccm_set_lengths( ctx, add->len, input->len, tag->len ) );
+    TEST_EQUAL( 0, mbedtls_ccm_update_ad( ctx, add->x, n1_add) );
+    TEST_EQUAL( 0, mbedtls_ccm_update_ad( ctx, add->x + n1_add, n2_add ) );
+
+    /* Allocate a tight buffer for each update call. This way, if the function
+     * tries to write beyond the advertised required buffer size, this will
+     * count as an overflow for memory sanitizers and static checkers. */
+    ASSERT_ALLOC( output, n1 );
+    olen = 0xdeadbeef;
+    TEST_EQUAL( 0, mbedtls_ccm_update( ctx, input->x, n1, output, n1, &olen ) );
+    TEST_EQUAL( n1, olen );
+    ASSERT_COMPARE( output, olen, expected_output->x, n1 );
+    mbedtls_free( output );
+    output = NULL;
+
+    ASSERT_ALLOC( output, n2 );
+    olen = 0xdeadbeef;
+    TEST_EQUAL( 0, mbedtls_ccm_update( ctx, input->x + n1, n2, output, n2, &olen ) );
+    TEST_EQUAL( n2, olen );
+    ASSERT_COMPARE( output, olen, expected_output->x + n1, n2 );
+    mbedtls_free( output );
+    output = NULL;
+
+    ASSERT_ALLOC( output, tag->len );
+    TEST_EQUAL( 0, mbedtls_ccm_finish( ctx, output, tag->len ) );
+    ASSERT_COMPARE( output, tag->len, tag->x, tag->len );
+    mbedtls_free( output );
+    output = NULL;
+
+    ok = 1;
+exit:
+    mbedtls_free( output );
+    return( ok );
+}
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -122,71 +181,115 @@
                                   data_t * add, data_t * result )
 {
     mbedtls_ccm_context ctx;
-    size_t tag_len;
-    uint8_t * msg_n_tag = (uint8_t *)malloc( result->len + 2 );
+    size_t n1, n1_add;
+    uint8_t* io_msg_buf = NULL;
+    uint8_t* tag_buf = NULL;
+    const size_t expected_tag_len = result->len - msg->len;
+    const uint8_t* expected_tag = result->x + msg->len;
+
+    /* Prepare input/output message buffer */
+    ASSERT_ALLOC( io_msg_buf, msg->len );
+    if( msg->len != 0 )
+        memcpy( io_msg_buf, msg->x, msg->len );
+
+    /* Prepare tag buffer */
+    ASSERT_ALLOC( tag_buf, expected_tag_len );
 
     mbedtls_ccm_init( &ctx );
-
-    memset( msg_n_tag, 0, result->len + 2 );
-    memcpy( msg_n_tag, msg->x, msg->len );
-
-    tag_len = result->len - msg->len;
-
-    TEST_ASSERT( mbedtls_ccm_setkey( &ctx, cipher_id, key->x, key->len * 8 ) == 0 );
-
+    TEST_EQUAL( mbedtls_ccm_setkey( &ctx, cipher_id, key->x, key->len * 8 ), 0 );
     /* Test with input == output */
-    TEST_ASSERT( mbedtls_ccm_encrypt_and_tag( &ctx, msg->len, iv->x, iv->len, add->x, add->len,
-                 msg_n_tag, msg_n_tag, msg_n_tag + msg->len, tag_len ) == 0 );
+    TEST_EQUAL( mbedtls_ccm_encrypt_and_tag( &ctx, msg->len, iv->x, iv->len, add->x, add->len,
+                io_msg_buf, io_msg_buf, tag_buf, expected_tag_len ), 0);
 
-    TEST_ASSERT( memcmp( msg_n_tag, result->x, result->len ) == 0 );
+    ASSERT_COMPARE( io_msg_buf, msg->len, result->x, msg->len );
+    ASSERT_COMPARE( tag_buf, expected_tag_len, expected_tag, expected_tag_len );
 
-    /* Check we didn't write past the end */
-    TEST_ASSERT( msg_n_tag[result->len] == 0 && msg_n_tag[result->len + 1] == 0 );
+    /* Prepare data_t structures for multipart testing */
+    const data_t encrypted_expected = { .x = result->x,
+                                        .len = msg->len };
+    const data_t tag_expected = { .x = (uint8_t*) expected_tag, /* cast to conform with data_t x type */
+                                  .len = expected_tag_len };
+
+    for( n1 = 0; n1 <= msg->len; n1 += 1 )
+    {
+        for( n1_add = 0; n1_add <= add->len; n1_add += 1 )
+        {
+            mbedtls_test_set_step( n1 * 10000 + n1_add );
+            if( !check_multipart( &ctx, MBEDTLS_CCM_ENCRYPT,
+                                  iv, add, msg,
+                                  &encrypted_expected,
+                                  &tag_expected,
+                                  n1, n1_add ) )
+                goto exit;
+        }
+    }
 
 exit:
     mbedtls_ccm_free( &ctx );
-    free( msg_n_tag );
+    mbedtls_free( io_msg_buf );
+    mbedtls_free( tag_buf );
 }
 /* END_CASE */
 
 /* BEGIN_CASE */
 void mbedtls_ccm_auth_decrypt( int cipher_id, data_t * key,
                                data_t * msg, data_t * iv,
-                               data_t * add, int tag_len, int result,
+                               data_t * add, int expected_tag_len, int result,
                                data_t * expected_msg )
 {
-    unsigned char tag[16];
     mbedtls_ccm_context ctx;
+    size_t n1, n1_add;
+
+    const size_t expected_msg_len = msg->len - expected_tag_len;
+    const uint8_t* expected_tag = msg->x + expected_msg_len;
+
+    /* Prepare input/output message buffer */
+    uint8_t* io_msg_buf = NULL;
+    ASSERT_ALLOC( io_msg_buf, expected_msg_len );
+    if( expected_msg_len )
+        memcpy( io_msg_buf, msg->x, expected_msg_len );
 
     mbedtls_ccm_init( &ctx );
-
-    memset( tag, 0x00, sizeof( tag ) );
-
-    msg->len -= tag_len;
-    memcpy( tag, msg->x + msg->len, tag_len );
-
-    TEST_ASSERT( mbedtls_ccm_setkey( &ctx, cipher_id, key->x, key->len * 8 ) == 0 );
-
+    TEST_EQUAL( mbedtls_ccm_setkey( &ctx, cipher_id, key->x, key->len * 8 ), 0 );
     /* Test with input == output */
-    TEST_ASSERT( mbedtls_ccm_auth_decrypt( &ctx, msg->len, iv->x, iv->len, add->x, add->len,
-                 msg->x, msg->x, msg->x + msg->len, tag_len ) == result );
+    TEST_EQUAL( mbedtls_ccm_auth_decrypt( &ctx, expected_msg_len, iv->x, iv->len, add->x, add->len,
+                io_msg_buf, io_msg_buf, expected_tag, expected_tag_len ), result );
 
     if( result == 0 )
     {
-        TEST_ASSERT( memcmp( msg->x, expected_msg->x, expected_msg->len ) == 0 );
+        ASSERT_COMPARE( io_msg_buf, expected_msg_len, expected_msg->x, expected_msg_len );
+
+         /* Prepare data_t structures for multipart testing */
+        const data_t encrypted = { .x = msg->x,
+                                   .len = expected_msg_len };
+
+        const data_t tag_expected = { .x = (uint8_t*) expected_tag,
+                                      .len = expected_tag_len };
+
+        for( n1 = 0; n1 <= expected_msg_len; n1 += 1 )
+        {
+            for( n1_add = 0; n1_add <= add->len; n1_add += 1 )
+            {
+                mbedtls_test_set_step( n1 * 10000 + n1_add );
+                if( !check_multipart( &ctx, MBEDTLS_CCM_DECRYPT,
+                                iv, add, &encrypted,
+                                expected_msg,
+                                &tag_expected,
+                                n1, n1_add ) )
+                    goto exit;
+           }
+        }
     }
     else
     {
         size_t i;
 
-        for( i = 0; i < msg->len; i++ )
-            TEST_ASSERT( msg->x[i] == 0 );
+        for( i = 0; i < expected_msg_len; i++ )
+            TEST_EQUAL( io_msg_buf[i], 0 );
     }
 
-    /* Check we didn't write past the end (where the original tag is) */
-    TEST_ASSERT( memcmp( msg->x + msg->len, tag, tag_len ) == 0 );
-
 exit:
+    mbedtls_free(io_msg_buf);
     mbedtls_ccm_free( &ctx );
 }
 /* END_CASE */
@@ -199,20 +302,32 @@
                             data_t *expected_result, int output_ret )
 {
     unsigned char iv[13];
-    unsigned char result[50];
     mbedtls_ccm_context ctx;
-    size_t iv_len, tag_len;
-    int ret;
+    size_t iv_len, expected_tag_len;
+    size_t n1, n1_add;
+    uint8_t* io_msg_buf = NULL;
+    uint8_t* tag_buf = NULL;
 
-    mbedtls_ccm_init( &ctx );
+    const uint8_t* expected_tag = expected_result->x + msg->len;
 
-    memset( result, 0x00, sizeof( result ) );
-
+    /* Calculate tag length */
     if( sec_level % 4 == 0)
-        tag_len = 0;
+        expected_tag_len = 0;
     else
-        tag_len = 1 << ( sec_level % 4 + 1);
+        expected_tag_len = 1 << ( sec_level % 4 + 1);
 
+    /* Prepare input/output message buffer */
+    ASSERT_ALLOC( io_msg_buf, msg->len );
+    if( msg->len )
+        memcpy( io_msg_buf, msg->x, msg->len );
+
+    /* Prepare tag buffer */
+    if( expected_tag_len == 0 )
+        ASSERT_ALLOC( tag_buf, 16 );
+    else
+        ASSERT_ALLOC( tag_buf, expected_tag_len );
+
+    /* Calculate iv */
     TEST_ASSERT( source_address->len == 8 );
     TEST_ASSERT( frame_counter->len == 4 );
     memcpy( iv, source_address->x, source_address->len );
@@ -220,24 +335,46 @@
     iv[source_address->len + frame_counter->len] = sec_level;
     iv_len = sizeof( iv );
 
-    TEST_ASSERT( mbedtls_ccm_setkey( &ctx, cipher_id,
-                                     key->x, key->len * 8 ) == 0 );
+    mbedtls_ccm_init( &ctx );
+    TEST_EQUAL( mbedtls_ccm_setkey( &ctx, cipher_id,
+                                     key->x, key->len * 8 ), 0 );
+    /* Test with input == output */
+    TEST_EQUAL( mbedtls_ccm_star_encrypt_and_tag( &ctx, msg->len, iv, iv_len,
+                                            add->x, add->len, io_msg_buf,
+                                            io_msg_buf, tag_buf, expected_tag_len), output_ret );
 
-    ret = mbedtls_ccm_star_encrypt_and_tag( &ctx, msg->len, iv, iv_len,
-                                            add->x, add->len, msg->x,
-                                            result, result + msg->len, tag_len );
+    ASSERT_COMPARE( io_msg_buf, msg->len, expected_result->x, msg->len );
+    ASSERT_COMPARE( tag_buf, expected_tag_len, expected_tag, expected_tag_len );
 
-    TEST_ASSERT( ret == output_ret );
+    if( output_ret == 0 )
+    {
+        const data_t iv_data = { .x = iv,
+                                 .len = iv_len };
 
-    TEST_ASSERT( memcmp( result,
-                         expected_result->x, expected_result->len ) == 0 );
+        const data_t encrypted_expected = { .x = expected_result->x,
+                                            .len = msg->len };
+        const data_t tag_expected = { .x = (uint8_t*)expected_tag,
+                                      .len = expected_tag_len };
 
-    /* Check we didn't write past the end */
-    TEST_ASSERT( result[expected_result->len] == 0 &&
-                 result[expected_result->len + 1] == 0 );
+        for( n1 = 0; n1 <= msg->len; n1 += 1 )
+        {
+            for( n1_add = 0; n1_add <= add->len; n1_add += 1 )
+            {
+                mbedtls_test_set_step( n1 * 10000 + n1_add );
+                if( !check_multipart( &ctx, MBEDTLS_CCM_STAR_ENCRYPT,
+                                      &iv_data, add, msg,
+                                      &encrypted_expected,
+                                      &tag_expected,
+                                      n1, n1_add ) )
+                    goto exit;
+            }
+        }
+    }
 
 exit:
     mbedtls_ccm_free( &ctx );
+    mbedtls_free( io_msg_buf );
+    mbedtls_free( tag_buf );
 }
 /* END_CASE */
 
@@ -249,21 +386,27 @@
                             data_t *expected_result, int output_ret )
 {
     unsigned char iv[13];
-    unsigned char result[50];
     mbedtls_ccm_context ctx;
-    size_t iv_len, tag_len;
-    int ret;
+    size_t iv_len, expected_tag_len;
+    size_t n1, n1_add;
 
-    mbedtls_ccm_init( &ctx );
-
-    memset( iv, 0x00, sizeof( iv ) );
-    memset( result, '+', sizeof( result ) );
-
+    /* Calculate tag length */
     if( sec_level % 4 == 0)
-        tag_len = 0;
+        expected_tag_len = 0;
     else
-        tag_len = 1 << ( sec_level % 4 + 1);
+        expected_tag_len = 1 << ( sec_level % 4 + 1);
 
+    const size_t expected_msg_len = msg->len - expected_tag_len;
+    const uint8_t* expected_tag = msg->x + expected_msg_len;
+
+    /* Prepare input/output message buffer */
+    uint8_t* io_msg_buf = NULL;
+    ASSERT_ALLOC( io_msg_buf, expected_msg_len );
+    if( expected_msg_len )
+        memcpy( io_msg_buf, msg->x, expected_msg_len );
+
+    /* Calculate iv */
+    memset( iv, 0x00, sizeof( iv ) );
     TEST_ASSERT( source_address->len == 8 );
     TEST_ASSERT( frame_counter->len == 4 );
     memcpy( iv, source_address->x, source_address->len );
@@ -271,23 +414,295 @@
     iv[source_address->len + frame_counter->len] = sec_level;
     iv_len = sizeof( iv );
 
+    mbedtls_ccm_init( &ctx );
     TEST_ASSERT( mbedtls_ccm_setkey( &ctx, cipher_id, key->x, key->len * 8 ) == 0 );
+    /* Test with input == output */
+    TEST_EQUAL( mbedtls_ccm_star_auth_decrypt( &ctx, expected_msg_len, iv, iv_len,
+                                         add->x, add->len, io_msg_buf, io_msg_buf,
+                                         expected_tag, expected_tag_len ), output_ret );
 
-    ret = mbedtls_ccm_star_auth_decrypt( &ctx, msg->len - tag_len, iv, iv_len,
-                                         add->x, add->len, msg->x, result,
-                                         msg->x + msg->len - tag_len, tag_len );
+    ASSERT_COMPARE( io_msg_buf, expected_msg_len, expected_result->x, expected_msg_len );
 
-    TEST_ASSERT( ret == output_ret );
+    if( output_ret == 0 )
+    {
+        const data_t iv_data = { .x = iv,
+                                 .len = iv_len };
 
-    TEST_ASSERT( memcmp( result, expected_result->x,
-                                 expected_result->len ) == 0 );
+        const data_t encrypted = { .x = msg->x,
+                                   .len = expected_msg_len} ;
 
-    /* Check we didn't write past the end (where the original tag is) */
-    TEST_ASSERT( ( msg->len + 2 ) <= sizeof( result ) );
-    TEST_EQUAL( result[msg->len], '+' );
-    TEST_EQUAL( result[msg->len + 1], '+' );
+        const data_t tag_expected = { .x = (uint8_t*) expected_tag,
+                                      .len = expected_tag_len };
+
+        for( n1 = 0; n1 <= expected_msg_len; n1 += 1 )
+        {
+            for( n1_add = 0; n1_add <= add->len; n1_add += 1 )
+            {
+                mbedtls_test_set_step( n1 * 10000 + n1_add );
+                if( !check_multipart( &ctx, MBEDTLS_CCM_STAR_DECRYPT,
+                                &iv_data, add, &encrypted,
+                                expected_result,
+                                &tag_expected,
+                                n1, n1_add ) )
+                    goto exit;
+           }
+        }
+    }
 
 exit:
     mbedtls_ccm_free( &ctx );
+    mbedtls_free( io_msg_buf );
+}
+/* END_CASE */
+
+/* Skip auth data, provide full text */
+/* BEGIN_CASE */
+void mbedtls_ccm_skip_ad( int cipher_id, int mode,
+                            data_t * key, data_t * msg, data_t * iv,
+                            data_t * result, data_t * tag )
+{
+    mbedtls_ccm_context ctx;
+    uint8_t *output = NULL;
+    size_t olen;
+
+    /* Sanity checks on the test data */
+    TEST_EQUAL( msg->len, result->len );
+
+    mbedtls_ccm_init( &ctx );
+    TEST_EQUAL( mbedtls_ccm_setkey( &ctx, cipher_id, key->x, key->len * 8 ), 0 );
+    TEST_EQUAL( 0, mbedtls_ccm_starts( &ctx, mode, iv->x, iv->len ) );
+    TEST_EQUAL( 0, mbedtls_ccm_set_lengths( &ctx, 0, msg->len, tag->len ) );
+
+    ASSERT_ALLOC( output, result->len );
+    olen = 0xdeadbeef;
+    TEST_EQUAL( 0, mbedtls_ccm_update( &ctx, msg->x, msg->len, output, result->len, &olen ) );
+    TEST_EQUAL( result->len, olen );
+    ASSERT_COMPARE( output, olen, result->x, result->len );
+    mbedtls_free( output );
+    output = NULL;
+
+    ASSERT_ALLOC( output, tag->len );
+    TEST_EQUAL( 0, mbedtls_ccm_finish( &ctx, output, tag->len ) );
+    ASSERT_COMPARE( output, tag->len, tag->x, tag->len );
+    mbedtls_free( output );
+    output = NULL;
+
+exit:
+    mbedtls_free( output );
+    mbedtls_ccm_free( &ctx );
+}
+/* END_CASE */
+
+/* Provide auth data, skip full text */
+/* BEGIN_CASE */
+void mbedtls_ccm_skip_update( int cipher_id, int mode,
+                              data_t * key, data_t * iv, data_t* add,
+                              data_t * tag )
+{
+    mbedtls_ccm_context ctx;
+    uint8_t *output = NULL;
+
+    mbedtls_ccm_init( &ctx );
+    TEST_EQUAL( mbedtls_ccm_setkey( &ctx, cipher_id, key->x, key->len * 8 ), 0 );
+    TEST_EQUAL( 0, mbedtls_ccm_starts( &ctx, mode, iv->x, iv->len ) );
+    TEST_EQUAL( 0, mbedtls_ccm_set_lengths( &ctx, add->len, 0, tag->len ) );
+
+    TEST_EQUAL( 0, mbedtls_ccm_update_ad( &ctx, add->x, add->len) );
+
+    ASSERT_ALLOC( output, tag->len );
+    TEST_EQUAL( 0, mbedtls_ccm_finish( &ctx, output, tag->len ) );
+    ASSERT_COMPARE( output, tag->len, tag->x, tag->len );
+    mbedtls_free( output );
+    output = NULL;
+
+exit:
+    mbedtls_free( output );
+    mbedtls_ccm_free( &ctx );
+}
+/* END_CASE */
+
+/* Provide too much auth data */
+/* BEGIN_CASE */
+void mbedtls_ccm_overflow_ad( int cipher_id, int mode,
+                                 data_t * key, data_t * iv,
+                                 data_t * add )
+{
+    mbedtls_ccm_context ctx;
+
+    mbedtls_ccm_init( &ctx );
+    TEST_EQUAL( mbedtls_ccm_setkey( &ctx, cipher_id, key->x, key->len * 8 ), 0 );
+    TEST_EQUAL( 0, mbedtls_ccm_starts( &ctx, mode, iv->x, iv->len ) );
+    // use hardcoded values for msg length and tag length. They are not a part of this test
+    // set half of auth data length to provoke an overflow
+    TEST_EQUAL( 0, mbedtls_ccm_set_lengths( &ctx, add->len / 2, 16, 16 ) );
+
+    TEST_EQUAL( MBEDTLS_ERR_CCM_BAD_INPUT, mbedtls_ccm_update_ad( &ctx, add->x, add->len) );
+exit:
+    mbedtls_ccm_free( &ctx );
+}
+/* END_CASE */
+
+/* Provide incomplete auth data and finish */
+/* BEGIN_CASE */
+void mbedtls_ccm_incomplete_ad( int cipher_id, int mode,
+                                data_t * key, data_t * iv, data_t* add )
+{
+    mbedtls_ccm_context ctx;
+    uint8_t *output = NULL;
+
+    mbedtls_ccm_init( &ctx );
+    TEST_EQUAL( mbedtls_ccm_setkey( &ctx, cipher_id, key->x, key->len * 8 ), 0 );
+    TEST_EQUAL( 0, mbedtls_ccm_starts( &ctx, mode, iv->x, iv->len ) );
+    // use hardcoded values for msg length and tag length. They are not a part of this test
+    TEST_EQUAL( 0, mbedtls_ccm_set_lengths( &ctx, add->len, 0, 16 ) );
+
+    TEST_EQUAL( 0, mbedtls_ccm_update_ad( &ctx, add->x, add->len/2) );
+
+    ASSERT_ALLOC( output, 16 );
+    TEST_EQUAL( MBEDTLS_ERR_CCM_BAD_SEQUENCE, mbedtls_ccm_finish( &ctx, output, 16 ) );
+
+exit:
+    mbedtls_free( output );
+    mbedtls_ccm_free( &ctx );
+}
+/* END_CASE */
+
+/* Provide complete auth data on first update_ad.
+ * Provide unexpected auth data on second update_ad */
+/* BEGIN_CASE */
+void mbedtls_ccm_full_ad_and_overflow( int cipher_id, int mode,
+                                       data_t * key, data_t * iv,
+                                       data_t * add )
+{
+    mbedtls_ccm_context ctx;
+
+    mbedtls_ccm_init( &ctx );
+    TEST_EQUAL( mbedtls_ccm_setkey( &ctx, cipher_id, key->x, key->len * 8 ), 0 );
+    TEST_EQUAL( 0, mbedtls_ccm_starts( &ctx, mode, iv->x, iv->len ) );
+    // use hardcoded values for msg length and tag length. They are not a part of this test
+    TEST_EQUAL( 0, mbedtls_ccm_set_lengths( &ctx, add->len, 16, 16 ) );
+
+    // pass full auth data
+    TEST_EQUAL( 0, mbedtls_ccm_update_ad( &ctx, add->x, add->len) );
+    // pass 1 extra byte
+    TEST_EQUAL( MBEDTLS_ERR_CCM_BAD_SEQUENCE, mbedtls_ccm_update_ad( &ctx, add->x, 1) );
+exit:
+    mbedtls_ccm_free( &ctx );
+}
+/* END_CASE */
+
+/* Provide too much plaintext/ciphertext */
+/* BEGIN_CASE */
+void mbedtls_ccm_overflow_update( int cipher_id, int mode,
+                                  data_t * key, data_t * msg, data_t * iv,
+                                  data_t * add )
+{
+    mbedtls_ccm_context ctx;
+    uint8_t *output = NULL;
+    size_t olen;
+
+    mbedtls_ccm_init( &ctx );
+    TEST_EQUAL( mbedtls_ccm_setkey( &ctx, cipher_id, key->x, key->len * 8 ), 0 );
+    TEST_EQUAL( 0, mbedtls_ccm_starts( &ctx, mode, iv->x, iv->len ) );
+    // use hardcoded value for tag length. It is a not a part of this test
+    // set half of msg length to provoke an overflow
+    TEST_EQUAL( 0, mbedtls_ccm_set_lengths( &ctx, add->len, msg->len / 2, 16 ) );
+
+    TEST_EQUAL( 0, mbedtls_ccm_update_ad( &ctx, add->x, add->len) );
+
+    ASSERT_ALLOC( output, msg->len );
+    TEST_EQUAL( MBEDTLS_ERR_CCM_BAD_INPUT, \
+                mbedtls_ccm_update( &ctx, msg->x, msg->len, output, msg->len, &olen ) );
+exit:
+    mbedtls_free( output );
+    mbedtls_ccm_free( &ctx );
+}
+/* END_CASE */
+
+/* Provide incomplete plaintext/ciphertext and finish */
+/* BEGIN_CASE */
+void mbedtls_ccm_incomplete_update( int cipher_id, int mode,
+                                    data_t * key, data_t * msg, data_t * iv,
+                                    data_t * add )
+{
+    mbedtls_ccm_context ctx;
+    uint8_t *output = NULL;
+    size_t olen;
+
+    mbedtls_ccm_init( &ctx );
+    TEST_EQUAL( mbedtls_ccm_setkey( &ctx, cipher_id, key->x, key->len * 8 ), 0 );
+    TEST_EQUAL( 0, mbedtls_ccm_starts( &ctx, mode, iv->x, iv->len ) );
+    // use hardcoded value for tag length. It is not a part of this test
+    TEST_EQUAL( 0, mbedtls_ccm_set_lengths( &ctx, add->len, msg->len, 16 ) );
+
+    TEST_EQUAL( 0, mbedtls_ccm_update_ad( &ctx, add->x, add->len) );
+
+    ASSERT_ALLOC( output, msg->len );
+    olen = 0xdeadbeef;
+    TEST_EQUAL( 0, mbedtls_ccm_update( &ctx, msg->x, msg->len/2, output, msg->len, &olen ) );
+    mbedtls_free( output );
+    output = NULL;
+
+    ASSERT_ALLOC( output, 16 );
+    TEST_EQUAL( MBEDTLS_ERR_CCM_BAD_SEQUENCE, mbedtls_ccm_finish( &ctx, output, 16 ) );
+
+exit:
+    mbedtls_free( output );
+    mbedtls_ccm_free( &ctx );
+}
+/* END_CASE */
+
+/* Provide full plaintext/ciphertext of first update
+ * Provide unexpected plaintext/ciphertext on second update */
+/* BEGIN_CASE */
+void mbedtls_ccm_full_update_and_overflow( int cipher_id, int mode,
+                                           data_t * key, data_t * msg, data_t * iv,
+                                           data_t * add )
+{
+    mbedtls_ccm_context ctx;
+    uint8_t *output = NULL;
+    size_t olen;
+
+    mbedtls_ccm_init( &ctx );
+    TEST_EQUAL( mbedtls_ccm_setkey( &ctx, cipher_id, key->x, key->len * 8 ), 0 );
+    TEST_EQUAL( 0, mbedtls_ccm_starts( &ctx, mode, iv->x, iv->len ) );
+    // use hardcoded value for tag length. It is a not a part of this test
+    TEST_EQUAL( 0, mbedtls_ccm_set_lengths( &ctx, add->len, msg->len, 16 ) );
+
+    TEST_EQUAL( 0, mbedtls_ccm_update_ad( &ctx, add->x, add->len) );
+
+    ASSERT_ALLOC( output, msg->len );
+    // pass full text
+    TEST_EQUAL( 0, mbedtls_ccm_update( &ctx, msg->x, msg->len, output, msg->len, &olen ) );
+    // pass 1 extra byte
+    TEST_EQUAL( MBEDTLS_ERR_CCM_BAD_INPUT, \
+                mbedtls_ccm_update( &ctx, msg->x, 1, output, 1, &olen ) );
+exit:
+    mbedtls_free( output );
+    mbedtls_ccm_free( &ctx );
+}
+/* END_CASE */
+
+/* Finish without passing any auth data or plaintext/ciphertext input */
+/* BEGIN_CASE */
+void mbedtls_ccm_instant_finish( int cipher_id, int mode,
+                                 data_t * key, data_t * iv )
+{
+    mbedtls_ccm_context ctx;
+    uint8_t *output = NULL;
+
+    mbedtls_ccm_init( &ctx );
+    TEST_EQUAL( mbedtls_ccm_setkey( &ctx, cipher_id, key->x, key->len * 8 ), 0 );
+    TEST_EQUAL( 0, mbedtls_ccm_starts( &ctx, mode, iv->x, iv->len ) );
+    // use hardcoded values for add length, msg length and tag length.
+    // They are not a part of this test
+    TEST_EQUAL( 0, mbedtls_ccm_set_lengths( &ctx, 16, 16, 16 ) );
+
+    ASSERT_ALLOC( output, 16 );
+    TEST_EQUAL( MBEDTLS_ERR_CCM_BAD_SEQUENCE, mbedtls_ccm_finish( &ctx, output, 16 ) );
+
+exit:
+    mbedtls_free( output );
+    mbedtls_ccm_free( &ctx );
 }
 /* END_CASE */