Skip to content

Commit 5ec93b3

Browse files
authored
test: add regression tests for issue #118 (error queue pollution) (#926)
1 parent eb50e4a commit 5ec93b3

2 files changed

Lines changed: 122 additions & 0 deletions

File tree

example/src/hooks/useTestsList.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import '../tests/keys/generate_key';
2323
import '../tests/keys/generate_keypair';
2424
import '../tests/keys/keyobject_from_tocryptokey_tests';
2525
import '../tests/keys/public_cipher';
26+
import '../tests/keys/sign_verify_error_queue';
2627
import '../tests/keys/sign_verify_oneshot';
2728
import '../tests/keys/sign_verify_streaming';
2829
import '../tests/pbkdf2/pbkdf2_tests';
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/**
2+
* Regression test for GitHub issue #118:
3+
* "Failed to read private key" after calling other crypto operations.
4+
*
5+
* The original bug was caused by OpenSSL error queue pollution — calling
6+
* operations like pbkdf2Sync before sign() would leave stale errors in the
7+
* per-thread error queue, causing subsequent key parsing to fail.
8+
*/
9+
10+
import {
11+
Buffer,
12+
sign,
13+
verify,
14+
createHash,
15+
createHmac,
16+
pbkdf2Sync,
17+
randomBytes,
18+
createCipheriv,
19+
createDecipheriv,
20+
generateKeyPairSync,
21+
} from 'react-native-quick-crypto';
22+
import { expect } from 'chai';
23+
import { test } from '../util';
24+
import { rsaPrivateKeyPem, rsaPublicKeyPem } from './fixtures';
25+
26+
const SUITE = 'keys.sign/verify';
27+
28+
const testData = Buffer.from('test data for issue 118');
29+
30+
const ITERATIONS = 10;
31+
32+
test(SUITE, 'sign after pbkdf2Sync (repeated)', () => {
33+
for (let i = 0; i < ITERATIONS; i++) {
34+
pbkdf2Sync('password', 'salt', 1000, 32, 'SHA-256');
35+
const sig = sign('SHA256', testData, rsaPrivateKeyPem);
36+
const valid = verify('SHA256', testData, rsaPublicKeyPem, sig);
37+
expect(valid).to.equal(true, `iteration ${i} failed`);
38+
}
39+
});
40+
41+
test(SUITE, 'sign after createHash (repeated)', () => {
42+
for (let i = 0; i < ITERATIONS; i++) {
43+
createHash('sha256').update('some data').digest();
44+
const sig = sign('SHA256', testData, rsaPrivateKeyPem);
45+
const valid = verify('SHA256', testData, rsaPublicKeyPem, sig);
46+
expect(valid).to.equal(true, `iteration ${i} failed`);
47+
}
48+
});
49+
50+
test(SUITE, 'sign after createHmac (repeated)', () => {
51+
for (let i = 0; i < ITERATIONS; i++) {
52+
createHmac('sha256', 'secret').update('some data').digest();
53+
const sig = sign('SHA256', testData, rsaPrivateKeyPem);
54+
const valid = verify('SHA256', testData, rsaPublicKeyPem, sig);
55+
expect(valid).to.equal(true, `iteration ${i} failed`);
56+
}
57+
});
58+
59+
test(SUITE, 'sign after AES cipher/decipher (repeated)', () => {
60+
const key = Buffer.alloc(32, 0xab);
61+
const iv = Buffer.alloc(16, 0xcd);
62+
const plaintext = Buffer.from('hello world');
63+
64+
for (let i = 0; i < ITERATIONS; i++) {
65+
const cipher = createCipheriv('aes-256-cbc', key, iv);
66+
const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
67+
68+
const decipher = createDecipheriv('aes-256-cbc', key, iv);
69+
Buffer.concat([decipher.update(encrypted), decipher.final()]);
70+
71+
const sig = sign('SHA256', testData, rsaPrivateKeyPem);
72+
const valid = verify('SHA256', testData, rsaPublicKeyPem, sig);
73+
expect(valid).to.equal(true, `iteration ${i} failed`);
74+
}
75+
});
76+
77+
test(SUITE, 'sign after mixed crypto operations (repeated)', () => {
78+
for (let i = 0; i < ITERATIONS; i++) {
79+
pbkdf2Sync('password', 'salt', 100, 32, 'SHA-512');
80+
createHash('sha512').update(randomBytes(64)).digest();
81+
createHmac('sha384', 'key').update('data').digest();
82+
pbkdf2Sync('pass2', 'salt2', 100, 64, 'SHA-384');
83+
84+
const sig = sign('SHA256', testData, rsaPrivateKeyPem);
85+
const valid = verify('SHA256', testData, rsaPublicKeyPem, sig);
86+
expect(valid).to.equal(true, `iteration ${i} failed`);
87+
}
88+
});
89+
90+
test(SUITE, 'Ed25519 sign after mixed crypto operations', () => {
91+
const { privateKey, publicKey } = generateKeyPairSync('ed25519', {
92+
publicKeyEncoding: { type: 'spki', format: 'pem' },
93+
privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
94+
});
95+
96+
for (let i = 0; i < ITERATIONS; i++) {
97+
pbkdf2Sync('password', 'salt', 100, 32, 'SHA-256');
98+
createHash('sha256').update('noise').digest();
99+
100+
const sig = sign(null, testData, privateKey as string);
101+
const valid = verify(null, testData, publicKey as string, sig);
102+
expect(valid).to.equal(true, `iteration ${i} failed`);
103+
}
104+
});
105+
106+
test(SUITE, 'ECDSA sign after mixed crypto operations', () => {
107+
const { privateKey, publicKey } = generateKeyPairSync('ec', {
108+
namedCurve: 'P-256',
109+
publicKeyEncoding: { type: 'spki', format: 'pem' },
110+
privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
111+
});
112+
113+
for (let i = 0; i < ITERATIONS; i++) {
114+
pbkdf2Sync('password', 'salt', 100, 32, 'SHA-256');
115+
createHash('sha384').update('noise').digest();
116+
117+
const sig = sign('SHA256', testData, privateKey as string);
118+
const valid = verify('SHA256', testData, publicKey as string, sig);
119+
expect(valid).to.equal(true, `iteration ${i} failed`);
120+
}
121+
});

0 commit comments

Comments
 (0)