@@ -253,6 +253,99 @@ const req = https.request(options, (res) => {
253253});
254254```
255255
256+ Example pinning on certificate fingerprint, or the public key (similar to
257+ ` pin-sha256 ` ):
258+
259+ ``` js
260+ const tls = require (' tls' );
261+ const https = require (' https' );
262+ const crypto = require (' crypto' );
263+
264+ function sha256 (s ) {
265+ return crypto .createHash (' sha256' ).update (s).digest (' base64' );
266+ }
267+ const options = {
268+ hostname: ' github.com' ,
269+ port: 443 ,
270+ path: ' /' ,
271+ method: ' GET' ,
272+ checkServerIdentity : function (host , cert ) {
273+ // Make sure the certificate is issued to the host we are connected to
274+ const err = tls .checkServerIdentity (host, cert);
275+ if (err) {
276+ return err;
277+ }
278+
279+ // Pin the public key, similar to HPKP pin-sha25 pinning
280+ const pubkey256 = ' pL1+qb9HTMRZJmuC/bB/ZI9d302BYrrqiVuRyW+DGrU=' ;
281+ if (sha256 (cert .pubkey ) !== pubkey256) {
282+ const msg = ' Certificate verification error: ' +
283+ ` The public key of '${ cert .subject .CN } ' ` +
284+ ' does not match our pinned fingerprint' ;
285+ return new Error (msg);
286+ }
287+
288+ // Pin the exact certificate, rather then the pub key
289+ const cert256 = ' 25:FE:39:32:D9:63:8C:8A:FC:A1:9A:29:87:' +
290+ ' D8:3E:4C:1D:98:DB:71:E4:1A:48:03:98:EA:22:6A:BD:8B:93:16' ;
291+ if (cert .fingerprint256 !== cert256) {
292+ const msg = ' Certificate verification error: ' +
293+ ` The certificate of '${ cert .subject .CN } ' ` +
294+ ' does not match our pinned fingerprint' ;
295+ return new Error (msg);
296+ }
297+
298+ // This loop is informational only.
299+ // Print the certificate and public key fingerprints of all certs in the
300+ // chain. Its common to pin the public key of the issuer on the public
301+ // internet, while pinning the public key of the service in sensitive
302+ // environments.
303+ do {
304+ console .log (' Subject Common Name:' , cert .subject .CN );
305+ console .log (' Certificate SHA256 fingerprint:' , cert .fingerprint256 );
306+
307+ hash = crypto .createHash (' sha256' );
308+ console .log (' Public key ping-sha256:' , sha256 (cert .pubkey ));
309+
310+ lastprint256 = cert .fingerprint256 ;
311+ cert = cert .issuerCertificate ;
312+ } while (cert .fingerprint256 !== lastprint256);
313+
314+ },
315+ };
316+
317+ options .agent = new https.Agent (options);
318+ const req = https .request (options, (res ) => {
319+ console .log (' All OK. Server matched our pinned cert or public key' );
320+ console .log (' statusCode:' , res .statusCode );
321+ // Print the HPKP values
322+ console .log (' headers:' , res .headers [' public-key-pins' ]);
323+
324+ res .on (' data' , (d ) => {});
325+ });
326+
327+ req .on (' error' , (e ) => {
328+ console .error (e .message );
329+ });
330+ req .end ();
331+
332+ ```
333+ Outputs for example:
334+ ``` text
335+ Subject Common Name: github.com
336+ Certificate SHA256 fingerprint: 25:FE:39:32:D9:63:8C:8A:FC:A1:9A:29:87:D8:3E:4C:1D:98:DB:71:E4:1A:48:03:98:EA:22:6A:BD:8B:93:16
337+ Public key ping-sha256: pL1+qb9HTMRZJmuC/bB/ZI9d302BYrrqiVuRyW+DGrU=
338+ Subject Common Name: DigiCert SHA2 Extended Validation Server CA
339+ Certificate SHA256 fingerprint: 40:3E:06:2A:26:53:05:91:13:28:5B:AF:80:A0:D4:AE:42:2C:84:8C:9F:78:FA:D0:1F:C9:4B:C5:B8:7F:EF:1A
340+ Public key ping-sha256: RRM1dGqnDFsCJXBTHky16vi1obOlCgFFn/yOhI/y+ho=
341+ Subject Common Name: DigiCert High Assurance EV Root CA
342+ Certificate SHA256 fingerprint: 74:31:E5:F4:C3:C1:CE:46:90:77:4F:0B:61:E0:54:40:88:3B:A9:A0:1E:D0:0B:A6:AB:D7:80:6E:D3:B1:18:CF
343+ Public key ping-sha256: WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18=
344+ All OK. Server matched our pinned cert or public key
345+ statusCode: 200
346+ headers: max-age=0; pin-sha256="WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18="; pin-sha256="RRM1dGqnDFsCJXBTHky16vi1obOlCgFFn/yOhI/y+ho="; pin-sha256="k2v657xBsOVe1PQRwOsHsw3bsGT2VzIqz5K+59sNQws="; pin-sha256="K87oWBWM9UZfyddvDfoxL+8lpNyoUB2ptGtn0fv6G2Q="; pin-sha256="IQBnNBEiFuhj+8x6X8XLgh01V9Ic5/V3IRQLNFFc7v4="; pin-sha256="iie1VXtL7HzAMF+/PVPR9xzT80kQxdZeJ+zduCB3uj0="; pin-sha256="LvRiGEjRqfzurezaWuj8Wie2gyHMrW5Q06LspMnox7A="; includeSubDomains
347+ ```
348+
256349[ `Agent` ] : #https_class_https_agent
257350[ `URL` ] : url.html#url_the_whatwg_url_api
258351[ `http.Agent` ] : http.html#http_class_http_agent
0 commit comments