4

I'm using the node package RequestJS v2.65.0 on node v4.1.2

I'm trying to read the SSL certificate from certain sites (eg. GitHub.com). This previously worked on node 0.12. On node 4.2.1, however, getPeerCertificate() returns null.

For example:

request({
  url: 'https://github.com'
}, function (err, res, body) {
  console.log('err:', err)
  console.log('peerCertificate:',res.req.connection.getPeerCertificate());
  console.log('authorized:',res.req.connection.authorized);
  console.log('authorizationError:',res.req.connection.authorizationError);
});

will print out

err: null
peerCertificate: null
authorized: true
authorizationError: null

i.e. the secure connection is established but the certificate is null.

From my (basic) understanding, if the connection is authorized, there should be a peer certificate.

I've tried with a number of SSL sites, and the result is the same. Is there an option in request, a bug with Node 4, or a misunderstanding on my part about how SSL/TLS works in node?

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
George
  • 65
  • 1
  • 5
  • I don't see why it should work at all. You got an error: what makes you think there is even a TCP connection? let alone an authenticated SSL connection? – user207421 Sep 04 '16 at 11:20

2 Answers2

4

I think your problem is because the getPeerCertificate() will only output anything when the connection is in connected state, but when you receive your response, it's likely already too late.

If you want getPeerCertificate to output, you should do it at the TLS level independently as such:

const socket = require('tls').connect(443, "github.com", () => {
  console.log('client connected',
    socket.authorized ? 'authorized' : 'unauthorized');
  process.stdin.pipe(socket);
  process.stdin.resume();
});

Important! : Do not put the protocol in the URL. Rather, use require('url').parse(yourURL).hostname as the target.

More info and example here: https://nodejs.org/api/tls.html#tls_tls_connect_port_host_options_callback

nembleton
  • 2,392
  • 1
  • 18
  • 20
4

@nembleton is correct about why this happens. There's an issue for this at https://github.com/request/request/issues/1867

Rather than dropping down to raw TLS sockets, you can stick with Request and use its stream API. This approach is particularly useful if you're taking advantage of other Request features that would make the low-level connection more complicated (e.g. going through an HTTPS proxy).

The code snippet in the original question becomes:

request({
  url: 'https://github.com'
})
.on('error', function(err) {
    console.log('err:', err);
})
.on('response', function (res) {
  console.log('peerCertificate:',res.socket.getPeerCertificate());
  console.log('authorized:',res.socket.authorized);
  console.log('authorizationError:',res.socket.authorizationError);
});

(I used res.socket rather than res.req.connection for brevity/directness, but either will work.)

hgcummings
  • 1,043
  • 10
  • 19