From e7a3a51459e795136c249bfe83978b41d7d5ecdd Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 23 Jun 2026 11:55:31 +0200 Subject: [PATCH] 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 --- src/libstrongswan/crypto/pkcs5.c | 65 +++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/src/libstrongswan/crypto/pkcs5.c b/src/libstrongswan/crypto/pkcs5.c index 822656f84b22..e01010b90ad8 100644 --- a/src/libstrongswan/crypto/pkcs5.c +++ b/src/libstrongswan/crypto/pkcs5.c @@ -14,6 +14,8 @@ * for more details. */ +#include + #include "pkcs5.h" #include @@ -22,6 +24,15 @@ #include #include +/** 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; -- 2.43.0