“It’s hard to overstate the severity of this bug. If you are using ECDSA signatures for any of these security mechanisms, then an attacker can trivially and completely bypass them if your server is running any Java 15, 16, 17, or 18 version before the April 2022 Critical Patch Update (CPU). For context, almost all WebAuthn/FIDO devices in the real world (including Yubikeys use ECDSA signatures and many OIDC providers use ECDSA-signed JWTs.”
The bug, tracked as CVE-2022-21449, carries a severity rating of 7.5 out of a possible 10, but Madden said based on his assessment, he’d rate the severity at a perfect 10 “due to the wide range of impacts on different functionality in an access management context.” In its grimmest form, the bug could be exploited by someone outside a vulnerable network with no verification at all.
Other security experts also had strong reactions, with one declaring it “the crypto bug of the year.”
A mitigating factor is that Java versions 15 and above don’t appear to be as widely used as earlier versions. Data collected in February and March 2021 from security firm Snyk showed that Java 15, the latest version at that time, accounted for 12 percent of deployments. While Madden said that the specific ECDSA implementation flaw affected only Java 15 and higher, Oracle also listed versions 7, 8, and 11 as vulnerable. Madden said that the discrepancy may result from separate crypto bugs fixed in the earlier releases.
a/0 = valid signature
ECDSA signatures rely on a pseudo-random number, typically notated as K, that’s used to derive two additional numbers, R and S. To verify a signature as valid, a party must check the equation involving R and S, the signer’s public key, and a cryptographic hash of the message. When both sides of the equation are equal, the signature is valid.
In a writeup published Wednesday, security firm Sophos further explained the process:
S1. Select a cryptographically sound random integer K between 1 and N-1 inclusive.
S2. Compute R from K using Elliptic Curve multiplication.
S3. In the unlikely event that R is zero, go back to step 1 and start over.
S4. Compute S from K, R, the hash to be signed, and the private key.
S5. In the unlikely event that S is zero, go back to step 1 and start over.
For the process to work correctly, neither R nor S can ever be a zero. That’s because one side of the equation is R, and the other is multiplied by R and a value from S. If the values are both 0, the verification check translates to 0 = 0 X (other values from the private key and hash), which will be true regardless of the additional values. That means an adversary only needs to submit a blank signature to pass the verification check successfully.
Madden wrote:
Guess which check Java forgot?
That’s right. Java’s implementation of ECDSA signature verification didn’t check if R or S were zero, so you could produce a signature value in which they are both 0 (appropriately encoded) and Java would accept it as a valid signature for any message and for any public key. The digital equivalent of a blank ID card.
Below is an interactive JShell session Madden created that shows a vulnerable implementation accepting a blank signature as valid when verifying a message and public key:
| Welcome to JShell -- Version 17.0.1
| For an introduction type: /help intro
jshell> import java.security.*
jshell> var keys = KeyPairGenerator.getInstance("EC").generateKeyPair()
keys ==> java.security.KeyPair@626b2d4a
jshell> var blankSignature = new byte[64]
blankSignature ==> byte[64] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... , 0, 0, 0, 0, 0, 0, 0, 0 }
jshell> var sig = Signature.getInstance("SHA256WithECDSAInP1363Format")
sig ==> Signature object: SHA256WithECDSAInP1363Format
jshell> sig.initVerify(keys.getPublic())
jshell> sig.update("Hello, World".getBytes())
jshell> sig.verify(blankSignature)
$8 ==> true
// Oops, that shouldn't have verified...
Organizations that are using any of the affected versions of Java to validate signatures should place a high priority on patching. It will also be important to monitor for advisories from app and product makers to see if any of their wares are made vulnerable. While the threat from CVE-2022-21449 appears limited to new Java versions, its severity is high enough to warrant vigilance.
https://arstechnica.com/information-technology/2022/04/major-crypto-blunder-in-java-enables-psychic-paper-forgeries/