Commit 52b689c4f8 for strongswan.org

commit 52b689c4f84e52cab842aad70e71118239b06ce1
Author: Tobias Brunner <tobias@strongswan.org>
Date:   Mon Jul 20 12:05:31 2026 +0200

    pem: Avoid integer underflow when verifying padding after decryption

    If the padding was larger than the whole blob, all available bytes were
    checked for a match and the blob's length was eventually adjusted and
    SUCCESS returned.  Due to the underflow this could result in a huge size
    that would then get copied.  Zero-length padding was also incorrectly
    accepted as was padding larger than the block size.

    Fixes: 160f4c225db0 ("moved PEM parsing functionality to its own plugin")

diff --git a/src/libstrongswan/plugins/pem/pem_builder.c b/src/libstrongswan/plugins/pem/pem_builder.c
index 2a7cdb55d3..217849e89f 100644
--- a/src/libstrongswan/plugins/pem/pem_builder.c
+++ b/src/libstrongswan/plugins/pem/pem_builder.c
@@ -95,6 +95,7 @@ static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg,
 	chunk_t decrypted;
 	chunk_t key = {alloca(key_size), key_size};
 	uint8_t padding, *last_padding_pos, *first_padding_pos;
+	size_t block_size;

 	if (!key_size)
 	{
@@ -141,8 +142,8 @@ static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg,
 		return NOT_SUPPORTED;
 	}

-	if (iv.len != crypter->get_iv_size(crypter) ||
-		blob->len % crypter->get_block_size(crypter))
+	block_size = crypter->get_block_size(crypter);
+	if (iv.len != crypter->get_iv_size(crypter) || blob->len % block_size)
 	{
 		DBG1(DBG_ASN, "  data size is not multiple of block size");
 		crypter->destroy(crypter);
@@ -164,14 +165,12 @@ static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg,
 	/* determine amount of padding */
 	last_padding_pos = blob->ptr + blob->len - 1;
 	padding = *last_padding_pos;
-	if (padding > blob->len)
+	if (!padding || padding > block_size)
 	{
-		first_padding_pos = blob->ptr;
-	}
-	else
-	{
-		first_padding_pos = last_padding_pos - padding;
+		DBG1(DBG_ASN, "  invalid passphrase");
+		return INVALID_ARG;
 	}
+	first_padding_pos = last_padding_pos - padding;
 	/* check the padding pattern */
 	while (--last_padding_pos > first_padding_pos)
 	{