Skip to content

Commit 732c9ba

Browse files
committed
chore(): improve pinning test
1 parent 64059ad commit 732c9ba

1 file changed

Lines changed: 71 additions & 41 deletions

File tree

test/network.test.ts

Lines changed: 71 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import crypto from 'crypto';
2-
import https from 'https';
1+
import crypto from 'node:crypto';
2+
import https from 'node:https';
3+
import tls, { PeerCertificate } from 'node:tls';
4+
35
import { ConnectionOptions } from 'tls';
46

57
import { MainClient } from '../src/index';
@@ -18,27 +20,33 @@ const PINNED_PUBLIC_KEY = '8f+yoE6YBsp3ftzgATuaWqQiZna/x30yVX676Ky7lxY=';
1820
const certificatePinningConfiguration: ConnectionOptions = {
1921
// ca: trustedCert, // Ensures only the specific CA is trusted
2022
checkServerIdentity: (host, cert) => {
23+
// Make sure the certificate is issued to the host we are connected to
24+
const err = tls.checkServerIdentity(host, cert);
25+
if (err) {
26+
return err;
27+
}
28+
2129
// Verify Subject Alternative Name (SAN)
2230
if (!cert.subjectaltname.includes('DNS:*.binance.com')) {
2331
throw new Error(
2432
`Certificate SAN mismatch: expected "*.binance.com", got ${cert.subjectaltname}`,
2533
);
2634
}
27-
const publicKey = cert.pubkey;
28-
const publicKeyHash = crypto
29-
.createHash('sha256')
30-
.update(publicKey)
31-
.digest('base64');
32-
35+
const publicKeyHash = sha256(cert.pubkey);
3336
if (publicKeyHash !== PINNED_PUBLIC_KEY) {
34-
throw new Error(
35-
`Certificate pinning validation failed: expected ${PINNED_PUBLIC_KEY}, got ${publicKeyHash}`,
37+
return new Error(
38+
`Certificate verification error: expected "${PINNED_PUBLIC_KEY}", got "${publicKeyHash}"`,
3639
);
3740
}
41+
3842
return undefined;
3943
},
4044
};
4145

46+
function sha256(s) {
47+
return crypto.createHash('sha256').update(s).digest('base64');
48+
}
49+
4250
describe('Test advanced https agent configuration', () => {
4351
// Simple positive check for working certificate pinning while keepAlive flag is active
4452
describe('pinned certificate', () => {
@@ -87,39 +95,61 @@ describe('Test advanced https agent configuration', () => {
8795
});
8896
});
8997

90-
describe('mismatching pinned certificate', () => {
91-
const api = new MainClient(
92-
{
93-
keepAlive: true,
94-
},
95-
{
96-
...getTestProxy(),
97-
httpsAgent: new https.Agent({
98-
rejectUnauthorized: true,
99-
checkServerIdentity: (host, cert) => {
100-
const publicKeyHash = crypto
101-
.createHash('sha256')
102-
.update(cert.pubkey)
103-
.digest('base64');
104-
105-
const PINNED_PUBLIC_KEY = 'fakePublicKeyHashShouldMismatch==';
106-
if (publicKeyHash !== PINNED_PUBLIC_KEY) {
107-
throw new Error(
108-
`Certificate pinning validation failed: expected ${PINNED_PUBLIC_KEY}, got ${publicKeyHash}`,
109-
);
110-
// eslint-disable-next-line no-unreachable
111-
}
112-
113-
return undefined;
114-
},
115-
}),
116-
},
117-
);
118-
98+
describe.only('mismatching pinned certificate', () => {
11999
it('getServerTime() should throw since the pinned certificate did not match', async () => {
120-
expect(() => api.getServerTime()).rejects.toMatchObject(
121-
expect.any(Object),
100+
const badPinClient = new MainClient(
101+
{
102+
keepAlive: true,
103+
},
104+
{
105+
// ...getTestProxy(),
106+
httpsAgent: new https.Agent({
107+
rejectUnauthorized: true,
108+
checkServerIdentity: (host, cert: PeerCertificate) => {
109+
// Make sure the certificate is issued to the host we are connected to
110+
const err = tls.checkServerIdentity(host, cert);
111+
if (err) {
112+
return err;
113+
}
114+
115+
// This loop is informational only.
116+
// Print the certificate and public key fingerprints of all certs in the
117+
// chain. Its common to pin the public key of the issuer on the public
118+
// internet, while pinning the public key of the service in sensitive
119+
// environments.
120+
let lastprint256 = '';
121+
do {
122+
console.log('Subject Common Name:', cert.subject.CN);
123+
console.log(
124+
' Certificate SHA256 fingerprint:',
125+
cert.fingerprint256,
126+
);
127+
128+
console.log(' Public key ping-sha256:', sha256(cert.pubkey));
129+
130+
lastprint256 = cert.fingerprint256;
131+
} while (cert.fingerprint256 !== lastprint256);
132+
133+
const PINNED_PUBLIC_KEY = 'fakePublicKeyHashShouldMismatch==';
134+
const publicKeyHash = sha256(cert.pubkey);
135+
136+
if (publicKeyHash !== PINNED_PUBLIC_KEY) {
137+
return new Error(
138+
`Certificate verification error: expected "${PINNED_PUBLIC_KEY}", got "${publicKeyHash}"`,
139+
);
140+
}
141+
142+
return undefined;
143+
},
144+
}),
145+
},
122146
);
147+
148+
try {
149+
expect(await badPinClient.getServerTime()).toStrictEqual('');
150+
} catch (e) {
151+
expect(e?.message).toMatch(/Certificate verification error/);
152+
}
123153
});
124154
});
125155
});

0 commit comments

Comments
 (0)