VYPR
High severity8.7NVD Advisory· Published Mar 23, 2026· Updated Apr 29, 2026

CVE-2026-4601

CVE-2026-4601

Description

Versions of the package jsrsasign before 11.1.1 are vulnerable to Missing Cryptographic Step via the KJUR.crypto.DSA.signWithMessageHash process in the DSA signing implementation. An attacker can recover the private key by forcing r or s to be zero, so the library emits an invalid signature without retrying, and then solves for x from the resulting signature.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
jsrsasignnpm
< 11.1.111.1.1

Affected products

1

Patches

1
0710e392ec35

Merge pull request #645 from Kr0emer/fix/bug-001-sign_s_zero

https://github.com/kjur/jsrsasignKenji UrushimaFeb 20, 2026via ghsa
2 files changed · +47 9
  • src/dsa-2.0.js+12 9 modified
    @@ -164,21 +164,24 @@ KJUR.crypto.DSA = function() {
     	var y = this.y; // public key (p q g y)
     	var x = this.x; // private key
     
    -	// NIST FIPS 186-4 4.5 DSA Per-Message Secret Number (p18)
    -	// 1. get random k where 0 < k < q
    -	var k = KJUR.crypto.Util.getRandomBigIntegerMinToMax(BigInteger.ONE.add(BigInteger.ONE),
    -							     q.subtract(BigInteger.ONE));
    -
     	// NIST FIPS 186-4 4.6 DSA Signature Generation (p19)
     	// 2. get z where the left most min(N, outlen) bits of Hash(M)
     	var hZ = sHashHex.substr(0, q.bitLength() / 4);
     	var z = new BigInteger(hZ, 16);
     
    -	// 3. get r where (g^k mod p) mod q, r != 0
    -	var r = (g.modPow(k,p)).mod(q); 
    +	var k, r, s;
    +	do {
    +	    // NIST FIPS 186-4 4.5 DSA Per-Message Secret Number (p18)
    +	    // 1. get random k where 0 < k < q
    +	    k = KJUR.crypto.Util.getRandomBigIntegerMinToMax(BigInteger.ONE.add(BigInteger.ONE),
    +							 q.subtract(BigInteger.ONE));
    +
    +	    // 3. get r where (g^k mod p) mod q, r != 0
    +	    r = (g.modPow(k,p)).mod(q); 
     
    -	// 4. get s where k^-1 (z + xr) mod q, s != 0
    -	var s = (k.modInverse(q).multiply(z.add(x.multiply(r)))).mod(q);
    +	    // 4. get s where k^-1 (z + xr) mod q, s != 0
    +	    s = (k.modInverse(q).multiply(z.add(x.multiply(r)))).mod(q);
    +	} while (r.compareTo(BigInteger.ZERO) == 0 || s.compareTo(BigInteger.ZERO) == 0);
     
     	// 5. signature (r, s)
     	var result = KJUR.asn1.ASN1Util.jsonToASN1HEX({
    
  • test/qunit-do-dsa.html+35 0 modified
    @@ -129,6 +129,41 @@
       ok(dsa2.verifyWithMessageHash(sHashHex, hSigVal), "");
     });
     
    +test("signWithMessageHash retries when s is zero", function() {
    +  var pSmall = new BigInteger("17", 16);
    +  var qSmall = new BigInteger("0b", 16);
    +  var gSmall = new BigInteger("04", 16);
    +  var xSmall = new BigInteger("03", 16);
    +  var ySmall = gSmall.modPow(xSmall, pSmall);
    +  var dsaPrv = new KJUR.crypto.DSA();
    +  dsaPrv.setPrivate(pSmall, qSmall, gSmall, null, xSmall);
    +  var dsaPub = new KJUR.crypto.DSA();
    +  dsaPub.setPublic(pSmall, qSmall, gSmall, ySmall);
    +
    +  var kList = [new BigInteger("2", 10), new BigInteger("3", 10)];
    +  var kIdx = 0;
    +  var fOrig = KJUR.crypto.Util.getRandomBigIntegerMinToMax;
    +
    +  var r0 = gSmall.modPow(kList[0], pSmall).mod(qSmall);
    +  var z = qSmall.subtract(xSmall.multiply(r0).mod(qSmall)).mod(qSmall);
    +  var sHashHex = z.toString(16);
    +
    +  KJUR.crypto.Util.getRandomBigIntegerMinToMax = function() {
    +    return kList[kIdx++];
    +  };
    +
    +  try {
    +    var hSigVal = dsaPrv.signWithMessageHash(sHashHex);
    +    var rs = dsaPrv.parseASN1Signature(hSigVal);
    +    ok(kIdx >= 2, "retry with a new k");
    +    ok(rs[0].compareTo(BigInteger.ZERO) != 0, "r != 0");
    +    ok(rs[1].compareTo(BigInteger.ZERO) != 0, "s != 0");
    +    ok(dsaPub.verifyWithMessageHash(sHashHex, hSigVal), "signature verifies");
    +  } finally {
    +    KJUR.crypto.Util.getRandomBigIntegerMinToMax = fOrig;
    +  }
    +});
    +
     test("readPKCS5PrvKeyHex d1", function() {
       var key = new KJUR.crypto.DSA();
       key.readPKCS5PrvKeyHex(D1PRVP5HEX);
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.