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+
35import { ConnectionOptions } from 'tls' ;
46
57import { MainClient } from '../src/index' ;
@@ -18,27 +20,33 @@ const PINNED_PUBLIC_KEY = '8f+yoE6YBsp3ftzgATuaWqQiZna/x30yVX676Ky7lxY=';
1820const 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+
4250describe ( '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 ( / C e r t i f i c a t e v e r i f i c a t i o n e r r o r / ) ;
152+ }
123153 } ) ;
124154 } ) ;
125155} ) ;
0 commit comments