Merge pull request #8540 from valeriosetti/issue8060

[G2] Make CCM and GCM work with the new block_cipher module
diff --git a/ChangeLog.d/8060.txt b/ChangeLog.d/8060.txt
new file mode 100644
index 0000000..a5fd93c
--- /dev/null
+++ b/ChangeLog.d/8060.txt
@@ -0,0 +1,4 @@
+Features
+    * The CCM and GCM modules no longer depend on MBEDTLS_CIPHER_C. People who
+      use CCM and GCM but don't need the Cipher API can now disable
+      MBEDTLS_CIPHER_C in order to save code size.
diff --git a/include/mbedtls/ccm.h b/include/mbedtls/ccm.h
index a98111b..8bf8c32 100644
--- a/include/mbedtls/ccm.h
+++ b/include/mbedtls/ccm.h
@@ -40,6 +40,10 @@
 
 #include "mbedtls/cipher.h"
 
+#if !defined(MBEDTLS_CIPHER_C)
+#include "mbedtls/block_cipher.h"
+#endif
+
 #define MBEDTLS_CCM_DECRYPT       0
 #define MBEDTLS_CCM_ENCRYPT       1
 #define MBEDTLS_CCM_STAR_DECRYPT  2
@@ -80,7 +84,11 @@
                                               #MBEDTLS_CCM_DECRYPT or
                                               #MBEDTLS_CCM_STAR_ENCRYPT or
                                               #MBEDTLS_CCM_STAR_DECRYPT. */
+#if defined(MBEDTLS_CIPHER_C)
     mbedtls_cipher_context_t MBEDTLS_PRIVATE(cipher_ctx);    /*!< The cipher context used. */
+#else
+    mbedtls_block_cipher_context_t MBEDTLS_PRIVATE(block_cipher_ctx);    /*!< The cipher context used. */
+#endif
     int MBEDTLS_PRIVATE(state);              /*!< Working value holding context's
                                                   state. Used for chunked data input */
 }
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index 7272400..792e7d7 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -336,19 +336,11 @@
 #error "MBEDTLS_CCM_C defined, but not all prerequisites"
 #endif
 
-#if defined(MBEDTLS_CCM_C) && !defined(MBEDTLS_CIPHER_C)
-#error "MBEDTLS_CCM_C defined, but not all prerequisites"
-#endif
-
 #if defined(MBEDTLS_GCM_C) && (                                        \
     !defined(MBEDTLS_AES_C) && !defined(MBEDTLS_CAMELLIA_C) && !defined(MBEDTLS_ARIA_C) )
 #error "MBEDTLS_GCM_C defined, but not all prerequisites"
 #endif
 
-#if defined(MBEDTLS_GCM_C) && !defined(MBEDTLS_CIPHER_C)
-#error "MBEDTLS_GCM_C defined, but not all prerequisites"
-#endif
-
 #if defined(MBEDTLS_CHACHAPOLY_C) && !defined(MBEDTLS_CHACHA20_C)
 #error "MBEDTLS_CHACHAPOLY_C defined, but not all prerequisites"
 #endif
diff --git a/include/mbedtls/config_adjust_legacy_crypto.h b/include/mbedtls/config_adjust_legacy_crypto.h
index c60e1e3..e66d67a 100644
--- a/include/mbedtls/config_adjust_legacy_crypto.h
+++ b/include/mbedtls/config_adjust_legacy_crypto.h
@@ -22,8 +22,8 @@
 #ifndef MBEDTLS_CONFIG_ADJUST_LEGACY_CRYPTO_H
 #define MBEDTLS_CONFIG_ADJUST_LEGACY_CRYPTO_H
 
-/* Temporary hack to pacify check_names.py.
- * (GCM and CCM still hard-depend on CIPHER_C for now.) */
+/* GCM_C and CCM_C can either depend on (in order of preference) CIPHER_C or
+ * BLOCK_CIPHER_C. If the former is not defined, auto-enable the latter. */
 #if (defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C)) && \
     !defined(MBEDTLS_CIPHER_C)
 #define MBEDTLS_BLOCK_CIPHER_C
diff --git a/include/mbedtls/gcm.h b/include/mbedtls/gcm.h
index 837cecc..3925f68 100644
--- a/include/mbedtls/gcm.h
+++ b/include/mbedtls/gcm.h
@@ -24,6 +24,10 @@
 
 #include "mbedtls/cipher.h"
 
+#if !defined(MBEDTLS_CIPHER_C)
+#include "mbedtls/block_cipher.h"
+#endif
+
 #include <stdint.h>
 
 #define MBEDTLS_GCM_ENCRYPT     1
@@ -46,7 +50,11 @@
  * \brief          The GCM context structure.
  */
 typedef struct mbedtls_gcm_context {
+#if defined(MBEDTLS_CIPHER_C)
     mbedtls_cipher_context_t MBEDTLS_PRIVATE(cipher_ctx);  /*!< The cipher context used. */
+#else
+    mbedtls_block_cipher_context_t MBEDTLS_PRIVATE(block_cipher_ctx);  /*!< The cipher context used. */
+#endif
     uint64_t MBEDTLS_PRIVATE(HL)[16];                      /*!< Precalculated HTable low. */
     uint64_t MBEDTLS_PRIVATE(HH)[16];                      /*!< Precalculated HTable high. */
     uint64_t MBEDTLS_PRIVATE(len);                         /*!< The total length of the encrypted data. */
diff --git a/library/ccm.c b/library/ccm.c
index 2cccd28..6700dc7 100644
--- a/library/ccm.c
+++ b/library/ccm.c
@@ -23,6 +23,10 @@
 #include "mbedtls/error.h"
 #include "mbedtls/constant_time.h"
 
+#if !defined(MBEDTLS_CIPHER_C)
+#include "block_cipher_internal.h"
+#endif
+
 #include <string.h>
 
 #if defined(MBEDTLS_PLATFORM_C)
@@ -51,6 +55,8 @@
                        unsigned int keybits)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+#if defined(MBEDTLS_CIPHER_C)
     const mbedtls_cipher_info_t *cipher_info;
 
     cipher_info = mbedtls_cipher_info_from_values(cipher, keybits,
@@ -73,6 +79,17 @@
                                      MBEDTLS_ENCRYPT)) != 0) {
         return ret;
     }
+#else
+    mbedtls_block_cipher_free(&ctx->block_cipher_ctx);
+
+    if ((ret = mbedtls_block_cipher_setup(&ctx->block_cipher_ctx, cipher)) != 0) {
+        return MBEDTLS_ERR_CCM_BAD_INPUT;
+    }
+
+    if ((ret = mbedtls_block_cipher_setkey(&ctx->block_cipher_ctx, key, keybits)) != 0) {
+        return MBEDTLS_ERR_CCM_BAD_INPUT;
+    }
+#endif
 
     return 0;
 }
@@ -85,7 +102,11 @@
     if (ctx == NULL) {
         return;
     }
+#if defined(MBEDTLS_CIPHER_C)
     mbedtls_cipher_free(&ctx->cipher_ctx);
+#else
+    mbedtls_block_cipher_free(&ctx->block_cipher_ctx);
+#endif
     mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ccm_context));
 }
 
@@ -104,12 +125,16 @@
                              const unsigned char *input,
                              unsigned char *output)
 {
-    size_t olen = 0;
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char tmp_buf[16] = { 0 };
 
-    if ((ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->ctr, 16, tmp_buf,
-                                     &olen)) != 0) {
+#if defined(MBEDTLS_CIPHER_C)
+    size_t olen = 0;
+    ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->ctr, 16, tmp_buf, &olen);
+#else
+    ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->ctr, tmp_buf);
+#endif
+    if (ret != 0) {
         ctx->state |= CCM_STATE__ERROR;
         mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
         return ret;
@@ -132,7 +157,10 @@
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char i;
-    size_t len_left, olen;
+    size_t len_left;
+#if defined(MBEDTLS_CIPHER_C)
+    size_t olen;
+#endif
 
     /* length calculation can be done only after both
      * mbedtls_ccm_starts() and mbedtls_ccm_set_lengths() have been executed
@@ -178,7 +206,12 @@
     }
 
     /* Start CBC-MAC with first block*/
-    if ((ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen)) != 0) {
+#if defined(MBEDTLS_CIPHER_C)
+    ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
+#else
+    ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
+#endif
+    if (ret != 0) {
         ctx->state |= CCM_STATE__ERROR;
         return ret;
     }
@@ -258,7 +291,10 @@
                           size_t add_len)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    size_t olen, use_len, offset;
+    size_t use_len, offset;
+#if defined(MBEDTLS_CIPHER_C)
+    size_t olen;
+#endif
 
     if (ctx->state & CCM_STATE__ERROR) {
         return MBEDTLS_ERR_CCM_BAD_INPUT;
@@ -298,8 +334,12 @@
             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) {
+#if defined(MBEDTLS_CIPHER_C)
+                ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
+#else
+                ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
+#endif
+                if (ret != 0) {
                     ctx->state |= CCM_STATE__ERROR;
                     return ret;
                 }
@@ -322,7 +362,10 @@
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char i;
-    size_t use_len, offset, olen;
+    size_t use_len, offset;
+#if defined(MBEDTLS_CIPHER_C)
+    size_t olen;
+#endif
 
     unsigned char local_output[16];
 
@@ -360,8 +403,12 @@
             mbedtls_xor(ctx->y + offset, ctx->y + offset, input, use_len);
 
             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) {
+#if defined(MBEDTLS_CIPHER_C)
+                ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
+#else
+                ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
+#endif
+                if (ret != 0) {
                     ctx->state |= CCM_STATE__ERROR;
                     goto exit;
                 }
@@ -391,8 +438,12 @@
             memcpy(output, local_output, use_len);
 
             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) {
+#if defined(MBEDTLS_CIPHER_C)
+                ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen);
+#else
+                ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->y);
+#endif
+                if (ret != 0) {
                     ctx->state |= CCM_STATE__ERROR;
                     goto exit;
                 }
diff --git a/library/gcm.c b/library/gcm.c
index 42fd020..8181ec8 100644
--- a/library/gcm.c
+++ b/library/gcm.c
@@ -25,6 +25,10 @@
 #include "mbedtls/error.h"
 #include "mbedtls/constant_time.h"
 
+#if !defined(MBEDTLS_CIPHER_C)
+#include "block_cipher_internal.h"
+#endif
+
 #include <string.h>
 
 #if defined(MBEDTLS_AESNI_C)
@@ -59,10 +63,16 @@
     uint64_t hi, lo;
     uint64_t vl, vh;
     unsigned char h[16];
-    size_t olen = 0;
 
     memset(h, 0, 16);
-    if ((ret = mbedtls_cipher_update(&ctx->cipher_ctx, h, 16, h, &olen)) != 0) {
+
+#if defined(MBEDTLS_CIPHER_C)
+    size_t olen = 0;
+    ret = mbedtls_cipher_update(&ctx->cipher_ctx, h, 16, h, &olen);
+#else
+    ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, h, h);
+#endif
+    if (ret != 0) {
         return ret;
     }
 
@@ -124,12 +134,14 @@
                        unsigned int keybits)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    const mbedtls_cipher_info_t *cipher_info;
 
     if (keybits != 128 && keybits != 192 && keybits != 256) {
         return MBEDTLS_ERR_GCM_BAD_INPUT;
     }
 
+#if defined(MBEDTLS_CIPHER_C)
+    const mbedtls_cipher_info_t *cipher_info;
+
     cipher_info = mbedtls_cipher_info_from_values(cipher, keybits,
                                                   MBEDTLS_MODE_ECB);
     if (cipher_info == NULL) {
@@ -150,6 +162,17 @@
                                      MBEDTLS_ENCRYPT)) != 0) {
         return ret;
     }
+#else
+    mbedtls_block_cipher_free(&ctx->block_cipher_ctx);
+
+    if ((ret = mbedtls_block_cipher_setup(&ctx->block_cipher_ctx, cipher)) != 0) {
+        return ret;
+    }
+
+    if ((ret = mbedtls_block_cipher_setkey(&ctx->block_cipher_ctx, key, keybits)) != 0) {
+        return ret;
+    }
+#endif
 
     if ((ret = gcm_gen_table(ctx)) != 0) {
         return ret;
@@ -252,8 +275,11 @@
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char work_buf[16];
     const unsigned char *p;
-    size_t use_len, olen = 0;
+    size_t use_len;
     uint64_t iv_bits;
+#if defined(MBEDTLS_CIPHER_C)
+    size_t olen = 0;
+#endif
 
     /* IV is limited to 2^64 bits, so 2^61 bytes */
     /* IV is not allowed to be zero length */
@@ -293,8 +319,13 @@
         gcm_mult(ctx, ctx->y, ctx->y);
     }
 
-    if ((ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16,
-                                     ctx->base_ectr, &olen)) != 0) {
+
+#if defined(MBEDTLS_CIPHER_C)
+    ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ctx->base_ectr, &olen);
+#else
+    ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ctx->base_ectr);
+#endif
+    if (ret != 0) {
         return ret;
     }
 
@@ -386,11 +417,15 @@
                     const unsigned char *input,
                     unsigned char *output)
 {
-    size_t olen = 0;
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 
-    if ((ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ectr,
-                                     &olen)) != 0) {
+#if defined(MBEDTLS_CIPHER_C)
+    size_t olen = 0;
+    ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctx->y, 16, ectr, &olen);
+#else
+    ret = mbedtls_block_cipher_encrypt(&ctx->block_cipher_ctx, ctx->y, ectr);
+#endif
+    if (ret != 0) {
         mbedtls_platform_zeroize(ectr, 16);
         return ret;
     }
@@ -614,7 +649,11 @@
     if (ctx == NULL) {
         return;
     }
+#if defined(MBEDTLS_CIPHER_C)
     mbedtls_cipher_free(&ctx->cipher_ctx);
+#else
+    mbedtls_block_cipher_free(&ctx->block_cipher_ctx);
+#endif
     mbedtls_platform_zeroize(ctx, sizeof(mbedtls_gcm_context));
 }
 
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 6613426..08136c0 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -1545,9 +1545,7 @@
     # (currently ignored anyway because we completely disable PSA)
     scripts/config.py unset MBEDTLS_PSA_CRYPTO_CONFIG
     # Disable features that depend on CIPHER_C
-    scripts/config.py unset MBEDTLS_CCM_C
     scripts/config.py unset MBEDTLS_CMAC_C
-    scripts/config.py unset MBEDTLS_GCM_C
     scripts/config.py unset MBEDTLS_NIST_KW_C
     scripts/config.py unset MBEDTLS_PKCS12_C
     scripts/config.py unset MBEDTLS_PKCS5_C
@@ -1560,7 +1558,6 @@
     scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
     scripts/config.py unset MBEDTLS_LMS_C
     scripts/config.py unset MBEDTLS_LMS_PRIVATE
-    make CFLAGS='-DMBEDTLS_BLOCK_CIPHER_C'
 
     msg "test: full no CIPHER no PSA_CRYPTO_C"
     make test