Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
Forge ChangeLog
===============

## 1.4.1 - 2026-xx-xx

### Security
- **HIGH**: Signature forgery in RSA-PKCS due to incomplete `DigestInfo` fix.
- The fix for CVE-2026-33894 in 1.4.0 only checked the element count of the
outer `DigestInfo` SEQUENCE. The nested `DigestAlgorithm` SEQUENCE was not
checked for extra, unconsumed elements, allowing the same class of low
public exponent (e.g. `e=3`) signature forgery via garbage bytes placed
inside that nested structure instead of the outer `DigestInfo` structure.
- Reported by geo-chen.
- CVE ID: [CVE-2026-85393](https://www.cve.org/CVERecord?id=CVE-2026-85393)

### Fixed
- [rsa] Fix RFC 8017 DigestInfo parsing to also require the nested
DigestAlgorithm sequence to contain only the OID and an optional NULL,
rejecting any extra, unconsumed elements. See #1149.

## 1.4.0 - 2026-03-24

### Security
Expand Down
9 changes: 7 additions & 2 deletions lib/rsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -1168,11 +1168,16 @@ pki.setRsaPublicKey = pki.rsa.setPublicKey = function(n, e) {
parseAllBytes: options._parseAllDigestBytes
});

// validate DigestInfo structure and element count
// validate DigestInfo structure and element counts (outer DigestInfo
// and nested DigestAlgorithm). asn1.validate ignores extra children,
// so length must be checked explicitly at each nesting level to
// prevent low-exponent PKCS#1 v1.5 signature forgery (CVE-2026-85393).
var capture = {};
var errors = [];
if(!asn1.validate(obj, digestInfoValidator, capture, errors) ||
obj.value.length !== 2) {
obj.value.length !== 2 ||
obj.value[0].value.length !==
(('parameters' in capture) ? 2 : 1)) {
var error = new Error(
'ASN.1 object does not contain a valid RSASSA-PKCS1-v1_5 ' +
'DigestInfo value.');
Expand Down
31 changes: 31 additions & 0 deletions tests/unit/rsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -1159,6 +1159,37 @@ var UTIL = require('../../lib/util');

_checkBadDigestInfo(publicKey, S);
});

it('should check nested DigestAlgorithm element count', function() {
var publicKey = RSA.setPublicKey(N, e);
// garbage OCTET STRING injected as an extra, unconsumed child of the
// nested DigestInfo.DigestAlgorithm SEQUENCE (after the OID and
// NULL). The GHSA-ppp5-5v6c-4jwp / CVE-2026-33894 fix only checks the
// element count of the outer DigestInfo SEQUENCE, so this nested
// garbage previously passed validation and could be used to forge
// signatures for low public exponent keys (e.g. e=3). See #1149 /
// CVE-2026-85393.
var I = UTIL.binary.hex.decode(
'0001ffffffffffffffff003081f23081cd060960864801650304020105000481bd88' +
'88888888888888888888888888888888888888888888888888888888888888888888' +
'88888888888888888888888888888888888888888888888888888888888888888888' +
'88888888888888888888888888888888888888888888888888888888888888888888' +
'88888888888888888888888888888888888888888888888888888888888888888888' +
'88888888888888888888888888888888888888888888888888888888888888888888' +
'88888888888888888888888888888888888804207509e5bda0c762d2bac7f90d758b' +
'5b2263fa01ccbc542ab5e3df163be08e6ca9');
var S = UTIL.binary.hex.decode(
'a4ae63dd5e7712b78f4870d0f51e294df5503d4f16c5d27ae33370981fb57f0de49f' +
'50f3d6a04666774cd984cd13972db9bf8e12bd294ef0ddc916c7c86cbae63efd7b6b' +
'97885e69760c208a40f1aecc76a90d7af5145177efce1bb55807a8d05c20b1596753' +
'ba710642fc9acdde6c160232654662c77cc4466c8257a38edb49f894e8845d0fd987' +
'b857ced88f4b62505a080bd87ef700d35d392a6e8f6fde34250c50b86fae606cb551' +
'215e8f4813239b77651d5565ad453698c071d48c31e8e526fb4a37610f64b3e1fb8e' +
'5be5898e408ad08197a0947794a530b54f84485377ce4a7488ed485ce4e5e105dd89' +
'698a472f390c3b1b76bc16b73276c4d1c81d');

_checkBadDigestInfo(publicKey, S);
});
});

describe('GHSA-ppp5-5v6c-4jwp DigestInfo/padding checks', function() {
Expand Down