@@ -168,9 +168,10 @@ changes:
168168
169169Makes a request to a secure web server.
170170
171- The following additional ` options ` from [ ` tls.connect() ` ] [ ] are also accepted
172- when using a custom [ ` Agent ` ] [ ] : ` ca ` , ` cert ` , ` ciphers ` , ` clientCertEngine ` ,
173- ` key ` , ` passphrase ` , ` pfx ` , ` rejectUnauthorized ` , ` secureProtocol ` , ` servername `
171+ Additionally, the ` options ` from [ ` tls.connect() ` ] [ ] are also accepted when
172+ using a custom [ ` Agent ` ] [ ] , such as: ` ca ` , ` cert ` , ` ciphers ` ,
173+ ` clientCertEngine ` , ` key ` , ` passphrase ` , ` pfx ` , ` rejectUnauthorized ` ,
174+ ` secureProtocol ` , ` servername ` .
174175
175176` options ` can be an object, a string, or a [ ` URL ` ] [ ] object. If ` options ` is a
176177string, it is automatically parsed with [ ` url.parse() ` ] [ ] . If it is a [ ` URL ` ] [ ]
@@ -250,6 +251,98 @@ const req = https.request(options, (res) => {
250251});
251252```
252253
254+ Example pinning on certificate fingerprint, or the public key (similar to ` pin-sha256 ` ):
255+
256+ ``` js
257+ const tls = require (' tls' );
258+ const https = require (' https' );
259+ const crypto = require (' crypto' );
260+
261+ function sha256 (s ) {
262+ return crypto .createHash (' sha256' ).update (s).digest (' base64' );
263+ }
264+ const options = {
265+ hostname: ' github.com' ,
266+ port: 443 ,
267+ path: ' /' ,
268+ method: ' GET' ,
269+ checkServerIdentity : function (host , cert ) {
270+ // Make sure the certificate is issued to the host we are connected to
271+ const err = tls .checkServerIdentity (host, cert);
272+ if (err) {
273+ return err;
274+ }
275+
276+ // Pin the public key, similar to HPKP pin-sha25 pinning
277+ const pubkey256 = ' pL1+qb9HTMRZJmuC/bB/ZI9d302BYrrqiVuRyW+DGrU=' ;
278+ if (sha256 (cert .pubkey ) !== pubkey256) {
279+ const msg = ' Certificate verification error: ' +
280+ ` The public key of '${ cert .subject .CN } ' ` +
281+ ' does not match our pinned fingerprint' ;
282+ return new Error (msg);
283+ }
284+
285+ // Pin the exact certificate, rather then the pub key
286+ const cert256 = ' 25:FE:39:32:D9:63:8C:8A:FC:A1:9A:29:87:' +
287+ ' D8:3E:4C:1D:98:DB:71:E4:1A:48:03:98:EA:22:6A:BD:8B:93:16' ;
288+ if (cert .fingerprint256 !== cert256) {
289+ const msg = ' Certificate verification error: ' +
290+ ` The certificate of '${ cert .subject .CN } ' ` +
291+ ' does not match our pinned fingerprint' ;
292+ return new Error (msg);
293+ }
294+
295+ // This loop is informational only.
296+ // Print the certificate and public key fingerprints of all certs in the
297+ // chain. Its common to pin the public key of the issuer on the public
298+ // internet, while pinning the public key of the service in sensitive
299+ // environments.
300+ do {
301+ console .log (' Subject Common Name:' , cert .subject .CN );
302+ console .log (' Certificate SHA256 fingerprint:' , cert .fingerprint256 );
303+
304+ hash = crypto .createHash (' sha256' );
305+ console .log (' Public key ping-sha256:' , sha256 (cert .pubkey ));
306+
307+ lastprint256 = cert .fingerprint256 ;
308+ cert = cert .issuerCertificate ;
309+ } while (cert .fingerprint256 !== lastprint256);
310+
311+ },
312+ };
313+
314+ options .agent = new https.Agent (options);
315+ const req = https .request (options, (res ) => {
316+ console .log (' All OK. Server matched our pinned cert or public key' );
317+ console .log (' statusCode:' , res .statusCode );
318+ // Print the HPKP values
319+ console .log (' headers:' , res .headers [' public-key-pins' ]);
320+
321+ res .on (' data' , (d ) => {});
322+ });
323+
324+ req .on (' error' , (e ) => {
325+ console .error (e .message );
326+ });
327+ req .end ();
328+
329+ ```
330+ Outputs for example:
331+ ``` text
332+ Subject Common Name: github.com
333+ 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
334+ Public key ping-sha256: pL1+qb9HTMRZJmuC/bB/ZI9d302BYrrqiVuRyW+DGrU=
335+ Subject Common Name: DigiCert SHA2 Extended Validation Server CA
336+ 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
337+ Public key ping-sha256: RRM1dGqnDFsCJXBTHky16vi1obOlCgFFn/yOhI/y+ho=
338+ Subject Common Name: DigiCert High Assurance EV Root CA
339+ 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
340+ Public key ping-sha256: WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18=
341+ All OK. Server matched our pinned cert or public key
342+ statusCode: 200
343+ 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
344+ ```
345+
253346[ `Agent` ] : #https_class_https_agent
254347[ `URL` ] : url.html#url_the_whatwg_url_api
255348[ `http.Agent` ] : http.html#http_class_http_agent
0 commit comments