A recent vulnerability identified as CVE-2024-4603 affects the way OpenSSL handles Digital Signature Algorithm (DSA) keys and parameters. Specifically, functions responsible for checking DSA parameters and public keys—EVP_PKEY_param_check() and EVP_PKEY_public_check()—may take an excessive amount of time when given keys or parameters with extremely large moduli (the p value in DSA). This can result in severe delays and potentially open up applications to Denial of Service (DoS) attacks, especially when processing untrusted or user-supplied keys.
Let’s break down this issue, see how it can be exploited, look at code examples, and review mitigation strategies with clear, easy-to-understand language.
The Issue in Simple Terms
DSA is a standard for digital signatures in cryptography. To verify a key is safe to use, OpenSSL has functions (EVP_PKEY_param_check, EVP_PKEY_public_check) that analyze DSA parameters. These routines, in some cases, run mathematical checks that take much longer if the parameter known as the “modulus” (often noted as p) is excessively large.
OpenSSL does restrict using gigantic keys for signature verification (setting an upper limit around 10,000 bits for public keys). But when simply checking if a DSA key or parameter is “OK”, the check functions don’t apply the same upper limit.
So, if an attacker submits a DSA key or parameters with a huge p value (for example, 100,000 bits!), and your application blindly checks it, your app could hang for a very, very long time.
Impact:
- If you accept DSA keys or parameters from untrusted users and pass them through the relevant OpenSSL checking functions, your app could freeze, serving no one.
Versions: Affects recent OpenSSL 3.x versions, including 3. and 3.1 FIPS providers.
- Not Affected: SSL/TLS core functionality, unless you call these functions directly with user keys.
Concept
An attacker sends, uploads, or otherwise provides a DSA key with a massive modulus (p). Your app, using OpenSSL, calls EVP_PKEY_param_check() or EVP_PKEY_public_check() to verify it. The check runs so slowly that your application thread or process is hogged—potentially for minutes or even longer. If you process many such keys, the service slows to a crawl.
Suppose you have a command-line tool or a server endpoint that accepts public keys for validation
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <stdio.h>
int main(int argc, char **argv) {
FILE *fp = fopen("huge_dsa_key.pem", "r");
EVP_PKEY *pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL);
fclose(fp);
if (EVP_PKEY_param_check(NULL, pkey) == 1) {
printf("The key parameters are valid.\n");
} else {
printf("The key parameters are invalid!\n");
}
EVP_PKEY_free(pkey);
return ;
}
Now, if huge_dsa_key.pem contains a DSA key with an extremely large p, calling EVP_PKEY_param_check() can make this program run *extremely* slowly or even appear to hang.
Example: Generating and Using a Malicious DSA Key
Generating huge DSA keys is not practical with current tools, but a malicious actor could craft one by editing an existing PEM file and replacing the modulus with a larger one.
If you then run
openssl pkeyparam -in huge_dsa_key.pem -check
You’ll notice how the command stalls—demonstrating the DoS condition.
Affected Scenarios
- Application Code: Apps calling EVP_PKEY_param_check() or EVP_PKEY_public_check() on user-supplied DSA keys/parameters.
OpenSSL Command Line: The pkey and pkeyparam tools with the -check switch.
- Not SSL/TLS: Normal OpenSSL client/server usage won’t invoke these checks on untrusted data.
Mitigation Strategies
1. Validate First: Don’t check DSA keys/parameters from untrusted sources unless you’ve verified their size.
For instance, reject any key where the modulus p exceeds a reasonable bit length (say, 4096-bit).
2. Patch ASAP: Monitor for official OpenSSL patches or upgrades that introduce length checks inside these functions.
3. Timeouts: Impose operation timeouts or move checks to separate, ephemeral processes to contain slowdowns.
Sample Python pseudocode for pre-checking modulus size
from cryptography.hazmat.primitives.serialization import load_pem_public_key
with open("user_key.pem", "rb") as f:
pubkey = load_pem_public_key(f.read())
if pubkey.key_size > 4096:
raise ValueError("DSA key modulus too large!")
OpenSSL Security Advisory:
https://www.openssl.org/news/secadv/20240605.txt
NIST DSA Standard:
https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
OpenSSL GitHub:
https://github.com/openssl/openssl
Conclusion
CVE-2024-4603 is an example of how cryptographic libraries can inadvertently introduce new attack vectors when dealing with untrusted data—even without “classic” security bugs. Always validate the structure and size of user-supplied crypto keys before handing them to deep library functions.
Patch, validate, and watch for OpenSSL updates—as this issue makes it way into the vulnerability-annals of 2024!
*For the latest advice, keep an eye on the OpenSSL advisories page!*
Timeline
Published on: 05/16/2024 16:15:10 UTC
Last modified on: 08/13/2024 16:35:05 UTC