From 52b689c4f84e52cab842aad70e71118239b06ce1 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 20 Jul 2026 12:05:31 +0200 Subject: [PATCH] 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") --- src/libstrongswan/plugins/pem/pem_builder.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/libstrongswan/plugins/pem/pem_builder.c b/src/libstrongswan/plugins/pem/pem_builder.c index 2a7cdb55d..217849e89 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) {