Commit f60a55e36f for strongswan.org
commit f60a55e36f95e210ab067de295c9f6bacefcdd1a
Author: Tobias Brunner <tobias@strongswan.org>
Date: Tue Jun 23 11:55:31 2026 +0200
pkcs5: Validate parsed parameters to avoid DoS attacks
With the unbounded iterations, an attacker can craft a PKCS#7 file and
send it during IKEv1 to block the processing thread practically for an
unlimited amount of time.
As the key length is used for an allocation on the stack, not limiting
it could cause a crash. We validate it after parsing the params, but
since `encryption_algorithm_from_oid()` only returns trusted key lengths
that are lower than the limit, that's fine.
The unlimited salt length had no direct impact (the maximum is bound by
the accepted message size), but we now limit it as well before cloning.
Fixes: 4076e3ee9121 ("Extract PKCS#5 handling from pkcs8 plugin to separate helper class")
Fixes: fd1ff46f6143 ("Added support for PKCS#5 v2 schemes when decrypting PKCS#8 files.")
Fixes: cab127cba66c ("Added support for encrypted PKCS#8 files (for some PKCS#5 v1.5 schemes).")
Fixes: CVE-2026-78129
diff --git a/src/libstrongswan/crypto/pkcs5.c b/src/libstrongswan/crypto/pkcs5.c
index 822656f84b..e01010b90a 100644
--- a/src/libstrongswan/crypto/pkcs5.c
+++ b/src/libstrongswan/crypto/pkcs5.c
@@ -14,6 +14,8 @@
* for more details.
*/
+#include <inttypes.h>
+
#include "pkcs5.h"
#include <utils/debug.h>
@@ -22,6 +24,15 @@
#include <asn1/asn1_parser.h>
#include <credentials/containers/pkcs12.h>
+/** maximum accepted length for salts in parsed parameters */
+#define PKCS5_SALT_LEN_MAX 128
+
+/** maximum accepted iteration count in parsed parameters */
+#define PKCS5_ITERATIONS_MAX 1000000
+
+/** maximum key length accepted in parsed parameters */
+#define PKCS5_KEY_LEN_MAX 64
+
typedef struct private_pkcs5_t private_pkcs5_t;
/**
@@ -379,6 +390,41 @@ METHOD(pkcs5_t, decrypt, bool,
keymat, key, iv);
}
+/**
+ * Make sure the salt has an appropriate length
+ */
+static bool validate_salt_length(chunk_t salt)
+{
+ if (salt.len > PKCS5_SALT_LEN_MAX)
+ {
+ DBG1(DBG_ASN, " salt length %zu exceeds maximum of %zu bytes",
+ salt.len, (size_t)PKCS5_SALT_LEN_MAX);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Validate that parsed parameters are in an allowed range
+ */
+static bool validate_params(private_pkcs5_t *this)
+{
+ if (!this->iterations || this->iterations > PKCS5_ITERATIONS_MAX)
+ {
+ DBG1(DBG_ASN, " iteration count %" PRIu64 " is out of range "
+ "(1-%" PRIu64 ")", this->iterations,
+ (uint64_t)PKCS5_ITERATIONS_MAX);
+ return FALSE;
+ }
+ if (this->keylen > PKCS5_KEY_LEN_MAX)
+ {
+ DBG1(DBG_ASN, " key length %zu exceeds maximum of %zu bytes",
+ this->keylen, (size_t)PKCS5_KEY_LEN_MAX);
+ return FALSE;
+ }
+ return TRUE;
+}
+
/**
* ASN.1 definition of a PBEParameter structure
*/
@@ -399,7 +445,7 @@ static bool parse_pbes1_params(private_pkcs5_t *this, chunk_t blob, int level0)
asn1_parser_t *parser;
chunk_t object;
int objectID;
- bool success;
+ bool success = FALSE;
parser = asn1_parser_create(pbeParameterObjects, blob);
parser->set_top_level(parser, level0);
@@ -410,6 +456,10 @@ static bool parse_pbes1_params(private_pkcs5_t *this, chunk_t blob, int level0)
{
case PBEPARAM_SALT:
{
+ if (!validate_salt_length(object))
+ {
+ goto end;
+ }
this->salt = chunk_clone(object);
break;
}
@@ -421,6 +471,11 @@ static bool parse_pbes1_params(private_pkcs5_t *this, chunk_t blob, int level0)
}
}
success = parser->success(parser);
+ if (success)
+ {
+ success = validate_params(this);
+ }
+end:
parser->destroy(parser);
return success;
}
@@ -471,6 +526,10 @@ static bool parse_pbkdf2_params(private_pkcs5_t *this, chunk_t blob, int level0)
{
case PBKDF2_SALT:
{
+ if (!validate_salt_length(object))
+ {
+ goto end;
+ }
this->salt = chunk_clone(object);
break;
}
@@ -500,6 +559,10 @@ static bool parse_pbkdf2_params(private_pkcs5_t *this, chunk_t blob, int level0)
}
}
success = parser->success(parser);
+ if (success)
+ {
+ success = validate_params(this);
+ }
end:
parser->destroy(parser);
return success;