CVE-2020-11684 (published 2020-09-14T14:15Z)

AT91bootstrap before 3.9.2 does not properly wipe encryption and authentication keys from memory before passing control to a less privileged software component. This can be exploited to disclose these keys and subsequently encrypt and sign the next boot stage (such as the bootloader).

Severity: MEDIUM
CVSS v2 base score: 6.4 (AV:N/AC:L/Au:N/C:P/I:P/A:N)
CVSS v3 base score: 9.1, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N)

Weakness information:
cwe_id: CWE-212
cwe_name: Improper Removal of Sensitive Information Before Storage or Transfer
description: The product stores, transfers, or shares a resource that contains sensitive information, but it does not properly remove that information before the product makes the resource available to unauthorized actors.
extended_description: 
            Resources that may contain sensitive data include documents, packets, messages, databases, etc. While this data may be useful to an individual user or small set of users who share the resource, it may need to be removed before the resource can be shared outside of the trusted group. The process of removal is sometimes called cleansing or scrubbing.
            For example, a product for editing documents might not remove sensitive data such as reviewer comments or the local pathname where the document is stored. Or, a proxy might not remove an internal IP address from headers before making an outgoing request to an Internet site.
         
         

Fix information:
repo_url: https://github.com/linux4sam/at91bootstrap
commit_details: repo_url: https://github.com/linux4sam/at91bootstrap
author: Eugen Hristev
author_date: 2020-03-17 16:44:00+02:00
msg: driver: secure: move keys into static arrays

Move the keys into static arrays. This will avoid copying the keys
from the code section to the stack on the previous init_keys implementation.
Like this, the keys are hardcoded into data section at compile time,
and can be completely wiped after use.

Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
Tested-by: Nicolas Ferre <nicolas.ferre@microchip.com>
repository: repo_url: https://github.com/linux4sam/at91bootstrap
repo_name: linux4sam/at91bootstrap
description: Second level bootloader for Microchip SoC (aka AT91) 
repo_language: C
owner: linux4sam
file_changes: filename: secure.c
change_type: ModificationType.MODIFY
diff: @@ -32,63 +32,60 @@
 #include "string.h"
 #include "autoconf.h"
 
-
-static inline void init_keys(at91_aes_key_size_t *key_size,
-			     unsigned int *cipher_key,
-			     unsigned int *cmac_key,
-			     unsigned int *iv)
-{
-#if defined(CONFIG_AES_KEY_SIZE_128)
-	*key_size = AT91_AES_KEY_SIZE_128;
-#elif defined(CONFIG_AES_KEY_SIZE_192)
-	*key_size = AT91_AES_KEY_SIZE_192;
-#elif defined(CONFIG_AES_KEY_SIZE_256)
-	*key_size = AT91_AES_KEY_SIZE_256;
-#else
-#error "bad AES key size"
+static unsigned int cipher_key[8] = {
+	CONFIG_AES_CIPHER_KEY_WORD0,
+	CONFIG_AES_CIPHER_KEY_WORD1,
+	CONFIG_AES_CIPHER_KEY_WORD2,
+	CONFIG_AES_CIPHER_KEY_WORD3,
+#if defined(CONFIG_AES_KEY_SIZE_192) || defined(CONFIG_AES_KEY_SIZE_256)
+	CONFIG_AES_CIPHER_KEY_WORD4,
+	CONFIG_AES_CIPHER_KEY_WORD5,
 #endif
+#if defined(CONFIG_AES_KEY_SIZE_256)
+	CONFIG_AES_CIPHER_KEY_WORD6,
+	CONFIG_AES_CIPHER_KEY_WORD7,
+#endif
+};
 
-	iv[0]		= CONFIG_AES_IV_WORD0;
-	iv[1]		= CONFIG_AES_IV_WORD1;
-	iv[2]		= CONFIG_AES_IV_WORD2;
-	iv[3]		= CONFIG_AES_IV_WORD3;
-
-	cipher_key[0]	= CONFIG_AES_CIPHER_KEY_WORD0;
-	cmac_key[0]	= CONFIG_AES_CMAC_KEY_WORD0;
-	cipher_key[1]	= CONFIG_AES_CIPHER_KEY_WORD1;
-	cmac_key[1]	= CONFIG_AES_CMAC_KEY_WORD1;
-	cipher_key[2]	= CONFIG_AES_CIPHER_KEY_WORD2;
-	cmac_key[2]	= CONFIG_AES_CMAC_KEY_WORD2;
-	cipher_key[3]	= CONFIG_AES_CIPHER_KEY_WORD3;
-	cmac_key[3]	= CONFIG_AES_CMAC_KEY_WORD3;
-
+static unsigned int cmac_key[8] = {
+	CONFIG_AES_CMAC_KEY_WORD0,
+	CONFIG_AES_CMAC_KEY_WORD1,
+	CONFIG_AES_CMAC_KEY_WORD2,
+	CONFIG_AES_CMAC_KEY_WORD3,
 #if defined(CONFIG_AES_KEY_SIZE_192) || defined(CONFIG_AES_KEY_SIZE_256)
-	cipher_key[4]	= CONFIG_AES_CIPHER_KEY_WORD4;
-	cmac_key[4]	= CONFIG_AES_CMAC_KEY_WORD4;
-	cipher_key[5]	= CONFIG_AES_CIPHER_KEY_WORD5;
-	cmac_key[5]	= CONFIG_AES_CMAC_KEY_WORD5;
+	CONFIG_AES_CMAC_KEY_WORD4,
+	CONFIG_AES_CMAC_KEY_WORD5,
 #endif
-
 #if defined(CONFIG_AES_KEY_SIZE_256)
-	cipher_key[6]	= CONFIG_AES_CIPHER_KEY_WORD6;
-	cmac_key[6]	= CONFIG_AES_CMAC_KEY_WORD6;
-	cipher_key[7]	= CONFIG_AES_CIPHER_KEY_WORD7;
-	cmac_key[7]	= CONFIG_AES_CMAC_KEY_WORD7;
+	CONFIG_AES_CMAC_KEY_WORD6,
+	CONFIG_AES_CMAC_KEY_WORD7,
 #endif
-}
+};
 
-int secure_decrypt(void *data, unsigned int data_length, int is_signed)
+static unsigned int iv[AT91_AES_IV_SIZE_WORD] = {
+	CONFIG_AES_IV_WORD0,
+	CONFIG_AES_IV_WORD1,
+	CONFIG_AES_IV_WORD2,
+	CONFIG_AES_IV_WORD3,
+};
+
+static int secure_decrypt(void *data, unsigned int data_length, int is_signed)
 {
 	at91_aes_key_size_t key_size;
-	unsigned int cmac_key[8], cipher_key[8];
-	unsigned int iv[AT91_AES_IV_SIZE_WORD];
 	unsigned int computed_cmac[AT91_AES_BLOCK_SIZE_WORD];
 	unsigned int fixed_length;
 	const unsigned int *cmac;
 	int rc = -1;
 
-	/* Init keys */
-	init_keys(&key_size, cipher_key, cmac_key, iv);
+#if defined(CONFIG_AES_KEY_SIZE_128)
+	key_size = AT91_AES_KEY_SIZE_128;
+#elif defined(CONFIG_AES_KEY_SIZE_192)
+	key_size = AT91_AES_KEY_SIZE_192;
+#elif defined(CONFIG_AES_KEY_SIZE_256)
+	key_size = AT91_AES_KEY_SIZE_256;
+#else
+#error "bad AES key size"
+#endif
 
 	/* Init periph */
 	at91_aes_init();
@@ -117,26 +114,34 @@ exit:
 	/* Reset periph */
 	at91_aes_cleanup();
 
+	return rc;
+}
+
+static void wipe_keys()
+{
 	/* Reset keys */
 	memset(cmac_key, 0, sizeof(cmac_key));
 	memset(cipher_key, 0, sizeof(cipher_key));
 	memset(iv, 0, sizeof(iv));
-
-	return rc;
 }
 
 int secure_check(void *data)
 {
 	const at91_secure_header_t *header;
 	void *file;
+	int ret = -1;
 
 	if (secure_decrypt(data, sizeof(*header), 0))
-		return -1;
+		goto secure_wipe_keys;
 
 	header = (const at91_secure_header_t *)data;
 	if (header->magic != AT91_SECURE_MAGIC)
-		return -1;
+		goto secure_wipe_keys;
 
 	file = (unsigned char *)data + sizeof(*header);
-	return secure_decrypt(file, header->file_size, 1);
+	ret = secure_decrypt(file, header->file_size, 1);
+
+secure_wipe_keys:
+	wipe_keys();
+	return ret;
 }

programming_language: C
filename: secure.h
change_type: ModificationType.MODIFY
diff: @@ -40,8 +40,6 @@ typedef struct at91_secure_header {
 	unsigned int		reserved[2];
 } at91_secure_header_t;
 
-
-int secure_decrypt(void *data, unsigned int data_length, int is_signed);
 int secure_check(void *data);
 
 #endif /* #ifdef __SECURE_H__ */

programming_language: C