Skip to content

Commit eca030d

Browse files
panvajuanarbol
authored andcommitted
test: check ecdsa psychic signature
PR-URL: #42863 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Akhil Marsonya <akhil.marsonya27@gmail.com>
1 parent bc0d8a3 commit eca030d

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
'use strict';
2+
const common = require('../common');
3+
if (!common.hasCrypto)
4+
common.skip('missing crypto');
5+
6+
const assert = require('assert');
7+
8+
const crypto = require('crypto');
9+
10+
// Tests for CVE-2022-21449
11+
// https://neilmadden.blog/2022/04/19/psychic-signatures-in-java/
12+
// Dubbed "Psychic Signatures", these signatures bypassed the ECDSA signature
13+
// verification implementation in Java in 15, 16, 17, and 18. OpenSSL is not
14+
// (and was not) vulnerable so these are a precaution.
15+
16+
const vectors = {
17+
'ieee-p1363': [
18+
Buffer.from('0000000000000000000000000000000000000000000000000000000000000000' +
19+
'0000000000000000000000000000000000000000000000000000000000000000', 'hex'),
20+
Buffer.from('ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551' +
21+
'ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551', 'hex'),
22+
],
23+
'der': [
24+
Buffer.from('3046022100' +
25+
'0000000000000000000000000000000000000000000000000000000000000000' +
26+
'022100' +
27+
'0000000000000000000000000000000000000000000000000000000000000000', 'hex'),
28+
Buffer.from('3046022100' +
29+
'ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551' +
30+
'022100' +
31+
'ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551', 'hex'),
32+
],
33+
};
34+
35+
const keyPair = crypto.generateKeyPairSync('ec', {
36+
namedCurve: 'P-256',
37+
publicKeyEncoding: {
38+
format: 'der',
39+
type: 'spki'
40+
},
41+
});
42+
43+
const data = Buffer.from('Hello!');
44+
45+
for (const [encoding, signatures] of Object.entries(vectors)) {
46+
for (const signature of signatures) {
47+
const key = {
48+
key: keyPair.publicKey,
49+
format: 'der',
50+
type: 'spki',
51+
dsaEncoding: encoding,
52+
};
53+
54+
// one-shot sync
55+
assert.strictEqual(
56+
crypto.verify(
57+
'sha256',
58+
data,
59+
key,
60+
signature,
61+
),
62+
false,
63+
);
64+
65+
// one-shot async
66+
crypto.verify(
67+
'sha256',
68+
data,
69+
key,
70+
signature,
71+
common.mustSucceed((verified) => assert.strictEqual(verified, false)),
72+
);
73+
74+
// stream
75+
assert.strictEqual(
76+
crypto.createVerify('sha256')
77+
.update(data)
78+
.verify(key, signature),
79+
false,
80+
);
81+
82+
// webcrypto
83+
crypto.webcrypto.subtle.importKey(
84+
'spki',
85+
keyPair.publicKey,
86+
{ name: 'ECDSA', namedCurve: 'P-256' },
87+
false,
88+
['verify'],
89+
).then((publicKey) => {
90+
return crypto.webcrypto.subtle.verify(
91+
{ name: 'ECDSA', hash: 'SHA-256' },
92+
publicKey,
93+
signature,
94+
data,
95+
);
96+
}).then(common.mustCall((verified) => {
97+
assert.strictEqual(verified, false);
98+
}));
99+
}
100+
}

0 commit comments

Comments
 (0)