ということをやりたかったのでやり方。

やりたいこと


これ ↓ の情報をJavaScript(Node.js)で取得したい。

環境


Node.js 12.12.0 で試してます。

どうやって確認するのか


Node.jsのAPIをパラパラと確認してみたところ、TLSモジュールで確認できそうということがわかりました。

Node.js Documentation TLS

これを見ているとgetCertificate()getPeerCertificate()というそれっぽい関数があるのがわかります。このうち、getCertificate()は次のような説明になっています。

Returns an object representing the local certificate.

要するにローカル証明書を対象とした関数ということがわかります。対してgetPeerCertificate()は…

Returns an object representing the peer’s certificate.

ということで、こちらを使えばサーバ証明書の確認ができそうです。

tls.connect と tls.TLSSocket


引き続きNode.jsのTLSのドキュメントを読むと、tls.connectで接続してtls.TLSSocketを確認すれば目的が達成できそうな感じがします。ところが、サンプルコードを参考にやってみたところ接続できませんでした。ドキュメント読んだ限りだとできそうなんですが…

https モジュール


そういえばHTTPSモジュールのレスポンスにsocketがなかったっけ?と思って試してみたところ、思った通りレスポンスにTSLSocketオブジェクトがありました!これを使ってこねこねすると無事取得できました。

コード


というわけで以下簡単なコード。

1
2
3
4
5
6
7
8
9
10
11
12
13
const https = require('https');

const options = {
hostname: 'about.yoshinorin.net',
port: 443,
path: '/',
method: 'GET'
};

const r = https.request(options, (response) => {
console.log(response.socket.getPeerCertificate());
});
r.end();

これを実行するとこんな感じで取得できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
subject: [Object: null prototype] { CN: 'about.yoshinorin.net' },
issuer: [Object: null prototype] {
C: 'US',
O: 'Amazon',
OU: 'Server CA 1B',
CN: 'Amazon'
},
subjectaltname: 'DNS:about.yoshinorin.net',
infoAccess: [Object: null prototype] {
'OCSP - URI': [ 'http://ocsp.sca1b.amazontrust.com' ],
'CA Issuers - URI': [ 'http://crt.sca1b.amazontrust.com/sca1b.crt' ]
},
modulus: '8C8C42498416A6E9C809E7432B56B3EC254275411AB29DFFCAD98BA9F0AE24EE8363C9EDAEA1B6D4B0CFCD3FD0237E066093EC3D562896D5C7D674659D4DCB596B9B535936636746A58A7F70DC38F91C791A28194C4E96AF707DCE5E7639EA8FFE5B4935B8C3DB0E7FF612380F9E47D9AB53A28B1475A26646C3B8E92F79CF6CB7B16342E7E8C32A5DF63FA352F50575D55B1D7E012ABD5E57D8BA8ECE2EC817CE2CF4537F0A959394E492C7AE8B38FC19593EE0AED07DCFFAB6E2707E715A97148C82FEFF21A42A28E3119C261B53336F6537C722D4361133D7123B88B77410071533165557AC8D0266B5935C478A569C389697D0632F32B5D2129F78CA7317',
bits: 2048,
exponent: '0x10001',
pubkey: <Buffer 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82 01 01 00 8c 8c 42 49 84 16 a6 e9 c8 09 e7 43 2b 56 b3 ec 25 ... 244 more bytes>,
valid_from: 'Jul 3 00:00:00 2019 GMT',
valid_to: 'Aug 3 12:00:00 2020 GMT',
fingerprint: '15:B5:48:28:55:2B:B8:11:4B:AA:33:D0:EF:17:FE:0E:53:52:AB:F0',
fingerprint256: '29:1C:36:84:53:1F:7C:BA:43:7B:54:AA:DA:6E:BC:72:31:AC:29:6C:A7:3D:F1:38:F9:D7:FC:84:3F:87:0C:B7',
ext_key_usage: [ '1.3.6.1.5.5.7.3.1', '1.3.6.1.5.5.7.3.2' ],
serialNumber: '01D8712FC1A699840DD9E326EC4CFD25',
raw: <Buffer 30 82 05 70 30 82 04 58 a0 03 02 01 02 02 10 01 d8 71 2f c1 a6 99 84 0d d9 e3 26 ec 4c fd 25 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 46 31 0b ... 1346 more bytes>
}

おわり。