@@ -168,9 +168,10 @@ changes:
168
168
169
169
Makes a request to a secure web server.
170
170
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 ` .
174
175
175
176
` options ` can be an object, a string, or a [ ` URL ` ] [ ] object. If ` options ` is a
176
177
string, it is automatically parsed with [ ` url.parse() ` ] [ ] . If it is a [ ` URL ` ] [ ]
@@ -250,6 +251,98 @@ const req = https.request(options, (res) => {
250
251
});
251
252
```
252
253
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
+
253
346
[ `Agent` ] : #https_class_https_agent
254
347
[ `URL` ] : url.html#url_the_whatwg_url_api
255
348
[ `http.Agent` ] : http.html#http_class_http_agent
0 commit comments