Return an error if asking for decrypt under BLOCK_CIPHER_NO_DECRYPT

If MBEDTLS_BLOCK_CIPHER_NO_DECRYPT is enabled, but decryption is
still requested in some incompatible modes, we return an error of
FEATURE_UNAVAILABLE as additional indication.

Signed-off-by: Yanray Wang <yanray.wang@arm.com>
diff --git a/include/mbedtls/aes.h b/include/mbedtls/aes.h
index c53f817..c43134d 100644
--- a/include/mbedtls/aes.h
+++ b/include/mbedtls/aes.h
@@ -60,6 +60,8 @@
 /* Error codes in range 0x0021-0x0025 */
 /** Invalid input data. */
 #define MBEDTLS_ERR_AES_BAD_INPUT_DATA                    -0x0021
+/** The requested feature is not available. */
+#define MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE               -0x0023
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/library/aes.c b/library/aes.c
index 940ea02..29a193e 100644
--- a/library/aes.c
+++ b/library/aes.c
@@ -1061,15 +1061,16 @@
 #endif
 
 #if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
-#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT)
     if (mode == MBEDTLS_AES_ENCRYPT) {
         return mbedtls_internal_aes_encrypt(ctx, input, output);
     } else {
+#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT)
         return mbedtls_internal_aes_decrypt(ctx, input, output);
-    }
 #else
-    return mbedtls_internal_aes_encrypt(ctx, input, output);
+        return MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE;
 #endif
+    }
+    return mbedtls_internal_aes_encrypt(ctx, input, output);
 #endif /* !MBEDTLS_AES_USE_HARDWARE_ONLY */
 }
 
diff --git a/library/aesce.c b/library/aesce.c
index 79c02e3..5883e6a 100644
--- a/library/aesce.c
+++ b/library/aesce.c
@@ -244,16 +244,15 @@
     uint8x16_t block = vld1q_u8(&input[0]);
     unsigned char *keys = (unsigned char *) (ctx->buf + ctx->rk_offset);
 
-#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT)
     if (mode == MBEDTLS_AES_ENCRYPT) {
         block = aesce_encrypt_block(block, keys, ctx->nr);
     } else {
+#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT)
         block = aesce_decrypt_block(block, keys, ctx->nr);
-    }
 #else
-    (void) mode;
-    block = aesce_encrypt_block(block, keys, ctx->nr);
-#endif /* !MBEDTLS_BLOCK_CIPHER_NO_DECRYPT */
+        return MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE;
+#endif
+    }
     vst1q_u8(&output[0], block);
 
     return 0;
diff --git a/library/aesni.c b/library/aesni.c
index 0c509ac..6c917da 100644
--- a/library/aesni.c
+++ b/library/aesni.c
@@ -93,7 +93,6 @@
     ++rk;
     --nr;
 
-#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT)
     if (mode == MBEDTLS_AES_ENCRYPT) {
         while (nr != 0) {
             state = _mm_aesenc_si128(state, *rk);
@@ -102,23 +101,17 @@
         }
         state = _mm_aesenclast_si128(state, *rk);
     } else {
+#if !defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT)
         while (nr != 0) {
             state = _mm_aesdec_si128(state, *rk);
             ++rk;
             --nr;
         }
         state = _mm_aesdeclast_si128(state, *rk);
-    }
 #else
-    (void) mode;
-    while (nr != 0) {
-
-        state = _mm_aesenc_si128(state, *rk);
-        ++rk;
-        --nr;
+        return MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE;
+#endif
     }
-    state = _mm_aesenclast_si128(state, *rk);
-#endif /* !MBEDTLS_BLOCK_CIPHER_NO_DECRYPT */
 
     memcpy(output, &state, 16);
     return 0;
@@ -452,6 +445,12 @@
                             const unsigned char input[16],
                             unsigned char output[16])
 {
+#if defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT)
+    if (mode == MBEDTLS_AES_DECRYPT) {
+        return MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE;
+    }
+#endif
+
     asm ("movdqu    (%3), %%xmm0    \n\t" // load input
          "movdqu    (%1), %%xmm1    \n\t" // load round key 0
          "pxor      %%xmm1, %%xmm0  \n\t" // round 0
diff --git a/library/cipher.c b/library/cipher.c
index 60c13a9..de55efa 100644
--- a/library/cipher.c
+++ b/library/cipher.c
@@ -319,6 +319,17 @@
     if (ctx->cipher_info == NULL) {
         return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
     }
+#if defined(MBEDTLS_BLOCK_CIPHER_NO_DECRYPT)
+    /* CBC, XTS, KW and KWP mode always need decryption, return an error to
+     * indicate those modes are not available under
+     * MBEDTLS_BLOCK_CIPHER_NO_DECRYPT. */
+    if (MBEDTLS_MODE_CBC == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode) ||
+        MBEDTLS_MODE_XTS == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode) ||
+        MBEDTLS_MODE_KW == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode) ||
+        MBEDTLS_MODE_KWP == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) {
+        return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
+    }
+#endif
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO) && !defined(MBEDTLS_DEPRECATED_REMOVED)
     if (ctx->psa_enabled == 1) {
@@ -402,12 +413,14 @@
         return mbedtls_cipher_get_base(ctx->cipher_info)->setkey_dec_func(ctx->cipher_ctx, key,
                                                                           ctx->key_bitlen);
     }
+#else
+    if (operation == MBEDTLS_ENCRYPT || operation == MBEDTLS_DECRYPT) {
+        return mbedtls_cipher_get_base(ctx->cipher_info)->setkey_enc_func(ctx->cipher_ctx, key,
+                                                                          ctx->key_bitlen);
+    }
+#endif
 
     return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
-#else
-    return mbedtls_cipher_get_base(ctx->cipher_info)->setkey_enc_func(ctx->cipher_ctx, key,
-                                                                      ctx->key_bitlen);
-#endif
 }
 
 int mbedtls_cipher_set_iv(mbedtls_cipher_context_t *ctx,
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 1faf1dd..2ada2eb 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -157,6 +157,7 @@
 #if defined(MBEDTLS_AES_C)
         case MBEDTLS_ERR_AES_INVALID_KEY_LENGTH:
         case MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH:
+        case MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE:
             return PSA_ERROR_NOT_SUPPORTED;
         case MBEDTLS_ERR_AES_BAD_INPUT_DATA:
             return PSA_ERROR_INVALID_ARGUMENT;