Skip to contentSkip to conversation

crypto: Add __cleanup functions for zeroizing aes_cmac_key & aes_cmac_ctx

PATCH NAK Thomas Huth 5 participants 14 messages Aug 7 – Aug 13

Subsystems (10)
lore
Share & tools
lore
#0 lore raw

v2 cover crypto: Add __cleanup functions for zeroizing aes_cmac_key & aes_cmac_ctx

Code that uses AES-CMAC might need to zeroize their local aes_cmac_key and/or aes_cmac_ctx structures after use to avoid leaking sensitive material on the stack.

The first patch introduces an aes_cmac_zeroize_key() and an aes_cmac_zeroize_ctx() helper function that can be used with __cleanup() to automatically clear the key and context when they go out of scope.

Patches 2 - 4 add the __cleanup markers to spots in the code that missed to clean up the structures so far.

The final two patches are just cosmetics and change some memzero_explicit() calls to use the __cleanup() way instead.

Note: There are more spots in the smb, tcp-ao and bluetooth code that need some zeroization of sensitive data on the stack. I will tackle those in later patches, this series here focuses on the new __cleanup wrappers.

v2:
- Update comments and positions of the functions in the 1st patch
- Also clear tmp[] in the bluetooth patch (the patch is pointless otherwise)

Thomas Huth (6):
crypto: Provide wrapper functions for zeroizing aes_cmac_key and
aes_cmac_ctx
smb: clear the aes_cmac_key and aes_cmac_ctx when done net/tcp-ao: clear the aes_cmac_key when done
Bluetooth: SMP: clear the aes_cmac_key when done lib/crypto: aes: Use _cleanup() for aes_cmac_key instead of
memzero_explicit()
mac80211: fils_aead: Use _cleanup for aes_cmac_key instead of
memzero_explicit

 fs/smb/client/smb2transport.c |  4 ++--
 fs/smb/server/auth.c          |  2 +-
 include/crypto/aes-cbc-macs.h | 34 ++++++++++++++++++++++++++++++++++
 lib/crypto/aes.c              |  3 +--
 net/bluetooth/smp.c           |  3 ++-
 net/ipv4/tcp_ao.c             |  2 +-
 net/mac80211/fils_aead.c      |  3 +--
 7 files changed, 42 insertions(+), 9 deletions(-)
Signature · 1 line
2.55.0
#1 lore raw

PATCH v2 1/6 crypto: Provide wrapper functions for zeroizing aes_cmac_key and aes_cmac_ctx

From: Thomas Huth <[email protected]>

Code that uses AES-CMAC might need to zeroize their local aes_cmac_key and/or aes_cmac_ctx structures after use to avoid leaking sensitive material on the stack.

Provide an aes_cmac_zeroize_key() and an aes_cmac_zeroize_ctx() helper function that can be used with __cleanup() to automatically clear the key and context when they go out of scope.

---
 include/crypto/aes-cbc-macs.h | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)
include/crypto/aes-cbc-macs.h +34 -0
index e61df108b926d..06e8a22f8a0ac 100644
@@ -8,6 +8,7 @@
 #define _CRYPTO_AES_CBC_MACS_H
 
 #include <crypto/aes.h>
+#include <linux/string.h>
 
 /**
  * struct aes_cmac_key - Prepared key for AES-CMAC or AES-XCBC-MAC
@@ -24,6 +25,19 @@ struct aes_cmac_key {
 	} k_final[2];
 };
 
+/**
+ * aes_cmac_zeroize_key() - Zeroize an aes_cmac_key structure
+ * @key: The location of the key structure that should be zeroized
+ *
+ * Explicitly fills the aes_cmac_key with zeroes. This should be done once
+ * the key is not required anymore to avoid that its contents are leaked
+ * on the stack or heap (if not using kfree_sensitive()).
+ */
+static inline void aes_cmac_zeroize_key(struct aes_cmac_key *key)
+{
+	memzero_explicit(key, sizeof(*key));
+}
+
 /**
  * struct aes_cmac_ctx - Context for computing an AES-CMAC or AES-XCBC-MAC value
  * @key: Pointer to the key struct.  A pointer is used rather than a copy of the
@@ -40,6 +54,19 @@ struct aes_cmac_ctx {
 	u8 h[AES_BLOCK_SIZE];
 };
 
+/**
+ * aes_cmac_zeroize_ctx() - Zeroize an aes_cmac_ctx structure
+ * @ctx: The location of the context that should be zeroized
+ *
+ * Explicitly fills the aes_cmac_ctx with zeroes. This should be done once
+ * the context is not required anymore to avoid that its contents are
+ * leaked on the stack or heap. Only required if not using aes_cmac_final().
+ */
+static inline void aes_cmac_zeroize_ctx(struct aes_cmac_ctx *ctx)
+{
+	memzero_explicit(ctx, sizeof(*ctx));
+}
+
 /**
  * aes_cmac_preparekey() - Prepare a key for AES-CMAC
  * @key: (output) The key struct to initialize
@@ -47,6 +74,10 @@ struct aes_cmac_ctx {
  * @key_len: Length of the raw key in bytes.  The supported values are
  *	     AES_KEYSIZE_128, AES_KEYSIZE_192, and AES_KEYSIZE_256.
  *
+ * On success, the caller should ensure that the prepared key is zeroized
+ * at the end of its lifetime, e.g. by calling aes_cmac_zeroize_key() or
+ * kfree_sensitive().
+ *
  * Context: Any context.
  * Return: 0 on success or -EINVAL if the given key length is invalid.  No other
  *	   errors are possible, so callers that always pass a valid key length
@@ -79,6 +110,9 @@ void aes_xcbcmac_preparekey(struct aes_cmac_key *key,
  *
  * This supports both AES-CMAC and AES-XCBC-MAC.  Which one is done depends on
  * whether aes_cmac_preparekey() or aes_xcbcmac_preparekey() was called.
+ *
+ * The caller should ensure that the context is zeroized at the end of its
+ * lifetime, e.g. by calling aes_cmac_final() or aes_cmac_zeroize_ctx().
  */
 static inline void aes_cmac_init(struct aes_cmac_ctx *ctx,
 				 const struct aes_cmac_key *key)
Signature · 1 line
2.55.0
#2 lore raw

PATCH v2 2/6 smb: clear the aes_cmac_key and aes_cmac_ctx when done

In reply to Thomas Huth

From: Thomas Huth <[email protected]>

Clear the local crypto-related structures via __cleanup() functions when we're done with them to avoid that sensitive data could leak on the stack.

Note: cmac_ctx in ksmbd_sign_smb3_pdu() gets cleared in aes_cmac_final() already, so this does not need a __cleanup() marker.

---
 fs/smb/client/smb2transport.c | 4 ++--
 fs/smb/server/auth.c          | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)
fs/smb/client/smb2transport.c +2 -2
index 1143ee52470a7..d23566da2ac81 100644
@@ -464,8 +464,8 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 	unsigned char smb3_signature[SMB2_CMACAES_SIZE];
 	struct kvec *iov = rqst->rq_iov;
 	struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
-	struct aes_cmac_key cmac_key;
-	struct aes_cmac_ctx cmac_ctx;
+	struct aes_cmac_key cmac_key __cleanup(aes_cmac_zeroize_key);
+	struct aes_cmac_ctx cmac_ctx __cleanup(aes_cmac_zeroize_ctx);
 	struct smb_rqst drqst;
 	u8 key[SMB3_SIGN_KEY_SIZE];
 
fs/smb/server/auth.c +1 -1
index 4e7b6f0e6b8cd..e8d1c068a43e8 100644
@@ -509,7 +509,7 @@ void ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
 void ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
 			 int n_vec, char *sig)
 {
-	struct aes_cmac_key cmac_key;
+	struct aes_cmac_key cmac_key __cleanup(aes_cmac_zeroize_key);
 	struct aes_cmac_ctx cmac_ctx;
 	int i;
 
Signature · 1 line
2.55.0
maintainer
#3 lore raw

Re: [PATCH v2 2/6] smb: clear the aes_cmac_key and aes_cmac_ctx when done

Quoted 5 lines
fs/smb/client/smb2transport.c +0 -0
index 1143ee52470a7..d23566da2ac81 100644

fs/smb/client/smb2transport.c smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) · line 470

Quoted 9 lines
fs/smb/client/smb2transport.c +2 -2
@@ -464,8 +464,8 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        unsigned char smb3_signature[SMB2_CMACAES_SIZE];
        struct kvec *iov = rqst->rq_iov;
        struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
-       struct aes_cmac_key cmac_key;
-       struct aes_cmac_ctx cmac_ctx;
+       struct aes_cmac_key cmac_key __cleanup(aes_cmac_zeroize_key);
+       struct aes_cmac_ctx cmac_ctx __cleanup(aes_cmac_zeroize_ctx);
        struct smb_rqst drqst;
        u8 key[SMB3_SIGN_KEY_SIZE];

Shouldn’t we also clear the raw key with memzero_explicit(key, sizeof(key)) immediately after aes_cmac_preparekey() ?

        rc = aes_cmac_preparekey(&cmac_key, key, SMB2_CMACAES_SIZE);
+        memzero_explicit(key, sizeof(key));
        if (rc) {
                cifs_server_dbg(VFS, "%s: Could not set key for cmac
aes\n", __func__);
                return rc;
        }
#4 lore raw

Re: [PATCH v2 2/6] smb: clear the aes_cmac_key and aes_cmac_ctx when done

Quoted 17 lines · Namjae Jeon
Quoted 5 lines
fs/smb/client/smb2transport.c +0 -0
index 1143ee52470a7..d23566da2ac81 100644

fs/smb/client/smb2transport.c smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) · line 470

Quoted 9 lines
fs/smb/client/smb2transport.c +2 -2
@@ -464,8 +464,8 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
         unsigned char smb3_signature[SMB2_CMACAES_SIZE];
         struct kvec *iov = rqst->rq_iov;
         struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
-       struct aes_cmac_key cmac_key;
-       struct aes_cmac_ctx cmac_ctx;
+       struct aes_cmac_key cmac_key __cleanup(aes_cmac_zeroize_key);
+       struct aes_cmac_ctx cmac_ctx __cleanup(aes_cmac_zeroize_ctx);
         struct smb_rqst drqst;
         u8 key[SMB3_SIGN_KEY_SIZE];

Shouldn’t we also clear the raw key with memzero_explicit(key, sizeof(key)) immediately after aes_cmac_preparekey() ?

Quoted 7 lines
         rc = aes_cmac_preparekey(&cmac_key, key, SMB2_CMACAES_SIZE);
+        memzero_explicit(key, sizeof(key));
         if (rc) {
                 cifs_server_dbg(VFS, "%s: Could not set key for cmac
aes\n", __func__);
                 return rc;
         }

Yes, but I was planning to do all the scrubbing for such other spots in a separate patch series (similar to what I've posted for the smb/server code already) ... this patch series here focuses on aes_cmac_zeroize_key and aes_cmac_zeroize_ctx only. I hope that's ok?

Thomas

maintainer Acked-by
#5 lore raw

Re: [PATCH v2 2/6] smb: clear the aes_cmac_key and aes_cmac_ctx when done

Quoted 26 lines · Thomas Huth
Quoted 17 lines · Namjae Jeon
Quoted 5 lines
fs/smb/client/smb2transport.c +0 -0
index 1143ee52470a7..d23566da2ac81 100644

fs/smb/client/smb2transport.c smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) · line 470

Quoted 9 lines
fs/smb/client/smb2transport.c +2 -2
@@ -464,8 +464,8 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
         unsigned char smb3_signature[SMB2_CMACAES_SIZE];
         struct kvec *iov = rqst->rq_iov;
         struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
-       struct aes_cmac_key cmac_key;
-       struct aes_cmac_ctx cmac_ctx;
+       struct aes_cmac_key cmac_key __cleanup(aes_cmac_zeroize_key);
+       struct aes_cmac_ctx cmac_ctx __cleanup(aes_cmac_zeroize_ctx);
         struct smb_rqst drqst;
         u8 key[SMB3_SIGN_KEY_SIZE];

Shouldn’t we also clear the raw key with memzero_explicit(key, sizeof(key)) immediately after aes_cmac_preparekey() ?

Quoted 7 lines
         rc = aes_cmac_preparekey(&cmac_key, key, SMB2_CMACAES_SIZE);
+        memzero_explicit(key, sizeof(key));
         if (rc) {
                 cifs_server_dbg(VFS, "%s: Could not set key for cmac
aes\n", __func__);
                 return rc;
         }
Quoted 4 lines

Yes, but I was planning to do all the scrubbing for such other spots in a separate patch series (similar to what I've posted for the smb/server code already) ... this patch series here focuses on aes_cmac_zeroize_key and aes_cmac_zeroize_ctx only. I hope that's ok?

Thanks.

#6 lore raw

PATCH v2 3/6 net/tcp-ao: clear the aes_cmac_key when done

In reply to Thomas Huth

From: Thomas Huth <[email protected]>

Clear the local aes_cmac_key structure via __cleanup() function when we're done with it to avoid that sensitive data could leak on the stack.

---
 net/ipv4/tcp_ao.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/ipv4/tcp_ao.c +1 -1
index e4ec60a334963..0626cbf60620c 100644
@@ -141,7 +141,7 @@ void tcp_ao_calc_traffic_key(const struct tcp_ao_key *mkt, u8 *traffic_key,
 					traffic_key);
 		return;
 	case TCP_AO_ALGO_AES_128_CMAC: {
-		struct aes_cmac_key k;
+		struct aes_cmac_key k __cleanup(aes_cmac_zeroize_key);
 
 		aes_cmac_preparekey(&k, mkt->key, AES_KEYSIZE_128);
 		aes_cmac(&k, input, input_len, traffic_key);
Signature · 1 line
2.55.0
maintainer NAK
#7 lore raw

Re: [PATCH v2 3/6] net/tcp-ao: clear the aes_cmac_key when done

net/ipv4/tcp_ao.c void tcp_ao_calc_traffic_key(const struct tcp_ao_key *mkt, u8 *traffic_key, · line 144

Quoted 2 lines · On Fri, 7 Aug 2026 14:58:40 +0200 Thomas Huth wrote:
net/ipv4/tcp_ao.c +1 -1
-		struct aes_cmac_key k;
+		struct aes_cmac_key k __cleanup(aes_cmac_zeroize_key);

Nak, we don't like the auto-cleanup stuff in networking. If y'all need a garbage collector there're jobs programming in Java.

#8 lore raw

Re: [PATCH v2 3/6] net/tcp-ao: clear the aes_cmac_key when done

Quoted 5 lines · Jakub Kicinski

net/ipv4/tcp_ao.c void tcp_ao_calc_traffic_key(const struct tcp_ao_key *mkt, u8 *traffic_key, · line 144

Quoted 2 lines · On Fri, 7 Aug 2026 14:58:40 +0200 Thomas Huth wrote:
net/ipv4/tcp_ao.c +1 -1
-		struct aes_cmac_key k;
+		struct aes_cmac_key k __cleanup(aes_cmac_zeroize_key);

Nak, we don't like the auto-cleanup stuff in networking.

Ok, if you don't like it, then let's drop this patch.

Quoted 1 line

If y'all need a garbage collector there're jobs programming in Java.

No need for derogatory statements, Jakub. That's really inappropriate.

Thomas

#9 lore raw

PATCH v2 4/6 Bluetooth: SMP: clear the aes_cmac_key when done

In reply to Thomas Huth

From: Thomas Huth <[email protected]>

Clear the local aes_cmac_key structure via __cleanup() function when we're done with it to avoid that sensitive data could leak on the stack.

While we're at it, also clear the tmp[] array here that is populated with a raw version of the original key and thus would leak the same information via the stack otherwise.

---
 net/bluetooth/smp.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/bluetooth/smp.c +2 -1
index c4470958b0d57..4a32e4f80b48a 100644
@@ -164,7 +164,7 @@ static inline void swap_buf(const u8 *src, u8 *dst, size_t len)
 static int smp_aes_cmac(const u8 k[16], const u8 *m, size_t len, u8 mac[16])
 {
 	uint8_t tmp[16], mac_msb[16], msg_msb[CMAC_MSG_MAX];
-	struct aes_cmac_key key;
+	struct aes_cmac_key key __cleanup(aes_cmac_zeroize_key);
 	int err;
 
 	if (len > CMAC_MSG_MAX)
@@ -178,6 +178,7 @@ static int smp_aes_cmac(const u8 k[16], const u8 *m, size_t len, u8 mac[16])
 	SMP_DBG("key %16phN", k);
 
 	err = aes_cmac_preparekey(&key, tmp, 16);
+	memzero_explicit(tmp, sizeof(tmp));
 	if (WARN_ON_ONCE(err)) /* Should never happen, as 16 is valid keylen */
 		return err;
 	aes_cmac(&key, msg_msb, len, mac_msb);
Signature · 1 line
2.55.0
#10 lore raw

PATCH v2 5/6 lib/crypto: aes: Use __cleanup() for aes_cmac_key instead of memzero_explicit()

In reply to Thomas Huth

From: Thomas Huth <[email protected]>

By using __cleanup(aes_cmac_zeroize_key) for clearing the key data, we can save one line of code here.

---
 lib/crypto/aes.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
lib/crypto/aes.c +1 -2
index 41aaa82cb1a1c..f1549839b3de0 100644
@@ -740,7 +740,7 @@ EXPORT_SYMBOL_NS_GPL(aes_cbcmac_final, "CRYPTO_INTERNAL");
 /* FIPS cryptographic algorithm self-test for AES-CMAC */
 static void __init aes_cmac_fips_test(void)
 {
-	struct aes_cmac_key key;
+	struct aes_cmac_key key __cleanup(aes_cmac_zeroize_key);
 	u8 mac[AES_BLOCK_SIZE];
 
 	if (aes_cmac_preparekey(&key, fips_test_key, sizeof(fips_test_key)) !=
@@ -749,7 +749,6 @@ static void __init aes_cmac_fips_test(void)
 	aes_cmac(&key, fips_test_data, sizeof(fips_test_data), mac);
 	if (memcmp(fips_test_aes_cmac_value, mac, sizeof(mac)) != 0)
 		panic("aes: CMAC FIPS self-test failed (wrong MAC)\n");
-	memzero_explicit(&key, sizeof(key));
 }
 #else /* CONFIG_CRYPTO_LIB_AES_CBC_MACS */
 static inline void aes_cmac_fips_test(void)
Signature · 1 line
2.55.0
#11 lore raw

PATCH v2 6/6 mac80211: fils_aead: Use __cleanup() for aes_cmac_key instead of memzero_explicit()

In reply to Thomas Huth

From: Thomas Huth <[email protected]>

By using __cleanup(aes_cmac_zeroize_key) for clearing the key data, we can save one line of code here.

---
 net/mac80211/fils_aead.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
net/mac80211/fils_aead.c +1 -2
index d2f4a17eab990..293590976489a 100644
@@ -24,7 +24,7 @@ static int aes_s2v(const u8 *in_key, size_t key_len,
 		   size_t num_elem, const u8 *addr[], size_t len[], u8 *v)
 {
 	u8 d[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE] = {};
-	struct aes_cmac_key key;
+	struct aes_cmac_key key __cleanup(aes_cmac_zeroize_key);
 	struct aes_cmac_ctx ctx;
 	size_t i;
 	int res;
@@ -62,7 +62,6 @@ static int aes_s2v(const u8 *in_key, size_t key_len,
 	aes_cmac_update(&ctx, d, AES_BLOCK_SIZE);
 	aes_cmac_final(&ctx, v);
 
-	memzero_explicit(&key, sizeof(key));
 	return 0;
 }
 
Signature · 1 line
2.55.0
maintainer Acked-by on v2 6/6
#12 lore raw

Re: [PATCH v2 6/6] mac80211: fils_aead: Use __cleanup() for aes_cmac_key instead of memzero_explicit()

Quoted 4 lines · Thomas Huth

From: Thomas Huth <[email protected]>

By using __cleanup(aes_cmac_zeroize_key) for clearing the key data, we can save one line of code here.

I'm assuming this won't be going via my tree, since it's part of a bigger series.

johannes

maintainer
#13 lore raw
In reply to Thomas Huth
Quoted 34 lines · Thomas Huth

Code that uses AES-CMAC might need to zeroize their local aes_cmac_key and/or aes_cmac_ctx structures after use to avoid leaking sensitive material on the stack.

The first patch introduces an aes_cmac_zeroize_key() and an aes_cmac_zeroize_ctx() helper function that can be used with __cleanup() to automatically clear the key and context when they go out of scope.

Patches 2 - 4 add the __cleanup markers to spots in the code that missed to clean up the structures so far.

The final two patches are just cosmetics and change some memzero_explicit() calls to use the __cleanup() way instead.

Note: There are more spots in the smb, tcp-ao and bluetooth code that need some zeroization of sensitive data on the stack. I will tackle those in later patches, this series here focuses on the new __cleanup wrappers.

v2:
- Update comments and positions of the functions in the 1st patch
- Also clear tmp[] in the bluetooth patch (the patch is pointless otherwise)

Thomas Huth (6):
crypto: Provide wrapper functions for zeroizing aes_cmac_key and
aes_cmac_ctx
smb: clear the aes_cmac_key and aes_cmac_ctx when done net/tcp-ao: clear the aes_cmac_key when done
Bluetooth: SMP: clear the aes_cmac_key when done lib/crypto: aes: Use _cleanup() for aes_cmac_key instead of
memzero_explicit()
mac80211: fils_aead: Use _cleanup for aes_cmac_key instead of
memzero_explicit

Quoted 8 lines
 fs/smb/client/smb2transport.c |  4 ++--
 fs/smb/server/auth.c          |  2 +-
 include/crypto/aes-cbc-macs.h | 34 ++++++++++++++++++++++++++++++++++
 lib/crypto/aes.c              |  3 +--
 net/bluetooth/smp.c           |  3 ++-
 net/ipv4/tcp_ao.c             |  2 +-
 net/mac80211/fils_aead.c      |  3 +--
 7 files changed, 42 insertions(+), 9 deletions(-)

Applied all except patch 3 to
https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/log/?h=libcrypto-next

- Eric