GeezerVison is showing github.com — tls: add ability to get cert/peer cert as X509Certificate object · nodejs/node@dc84c18
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/crypto.md +10Lines changed: 10 additions & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -1804,6 +1804,16 @@ added: v15.6.0 | 1804 | 1804 |
| 1805 | 1805 | The issuer identification included in this certificate. | 1806 | 1806 |
| | 1807 | +### `x509.issuerCertificate` | | 1808 | +<!-- YAML | | 1809 | +added: REPLACEME | | 1810 | +--> | | 1811 | + | | 1812 | +* Type: {X509Certificate} | | 1813 | + | | 1814 | +The issuer certificate or `undefined` if the issuer certificate is not | | 1815 | +available. | | 1816 | + | 1807 | 1817 | ### `x509.keyUsage` | 1808 | 1818 | <!-- YAML | 1809 | 1819 | added: v15.6.0 | |
Collapse file Copy file name to clipboardExpand all lines: doc/api/tls.md +59-35Lines changed: 59 additions & 35 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -904,6 +904,41 @@ added: v0.11.4 | 904 | 904 | Always returns `true`. This may be used to distinguish TLS sockets from regular | 905 | 905 | `net.Socket` instances. | 906 | 906 |
| | 907 | +### `tlsSocket.exportKeyingMaterial(length, label[, context])` | | 908 | +<!-- YAML | | 909 | +added: | | 910 | + - v13.10.0 | | 911 | + - v12.17.0 | | 912 | +--> | | 913 | + | | 914 | +* `length` {number} number of bytes to retrieve from keying material | | 915 | +* `label` {string} an application specific label, typically this will be a | | 916 | + value from the | | 917 | + [IANA Exporter Label Registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#exporter-labels). | | 918 | +* `context` {Buffer} Optionally provide a context. | | 919 | + | | 920 | +* Returns: {Buffer} requested bytes of the keying material | | 921 | + | | 922 | +Keying material is used for validations to prevent different kind of attacks in | | 923 | +network protocols, for example in the specifications of IEEE 802.1X. | | 924 | + | | 925 | +Example | | 926 | + | | 927 | +```js | | 928 | +const keyingMaterial = tlsSocket.exportKeyingMaterial( | | 929 | + 128, | | 930 | + 'client finished'); | | 931 | + | | 932 | +/** | | 933 | + Example return value of keyingMaterial: | | 934 | + <Buffer 76 26 af 99 c5 56 8e 42 09 91 ef 9f 93 cb ad 6c 7b 65 f8 53 f1 d8 d9 | | 935 | + 12 5a 33 b8 b5 25 df 7b 37 9f e0 e2 4f b8 67 83 a3 2f cd 5d 41 42 4c 91 | | 936 | + 74 ef 2c ... 78 more bytes> | | 937 | +*/ | | 938 | +``` | | 939 | +See the OpenSSL [`SSL_export_keying_material`][] documentation for more | | 940 | +information. | | 941 | + | 907 | 942 | ### `tlsSocket.getCertificate()` | 908 | 943 | <!-- YAML | 909 | 944 | added: v11.2.0 | @@ -1113,6 +1148,18 @@ provided by SSL/TLS is not desired or is not enough. | 1113 | 1148 | Corresponds to the `SSL_get_peer_finished` routine in OpenSSL and may be used | 1114 | 1149 | to implement the `tls-unique` channel binding from [RFC 5929][]. | 1115 | 1150 |
| | 1151 | +### `tlsSocket.getPeerX509Certificate()` | | 1152 | +<!-- YAML | | 1153 | +added: REPLACEME | | 1154 | +--> | | 1155 | + | | 1156 | +* Returns: {X509Certificate} | | 1157 | + | | 1158 | +Returns the peer certificate as an {X509Certificate} object. | | 1159 | + | | 1160 | +If there is no peer certificate, or the socket has been destroyed, | | 1161 | +`undefined` will be returned. | | 1162 | + | 1116 | 1163 | ### `tlsSocket.getProtocol()` | 1117 | 1164 | <!-- YAML | 1118 | 1165 | added: v5.7.0 | @@ -1164,41 +1211,6 @@ See | 1164 | 1211 | [SSL_get_shared_sigalgs](https://www.openssl.org/docs/man1.1.1/man3/SSL_get_shared_sigalgs.html) | 1165 | 1212 | for more information. | 1166 | 1213 |
| 1167 | | -### `tlsSocket.exportKeyingMaterial(length, label[, context])` | 1168 | | -<!-- YAML | 1169 | | -added: | 1170 | | - - v13.10.0 | 1171 | | - - v12.17.0 | 1172 | | ---> | 1173 | | - | 1174 | | -* `length` {number} number of bytes to retrieve from keying material | 1175 | | -* `label` {string} an application specific label, typically this will be a | 1176 | | - value from the | 1177 | | - [IANA Exporter Label Registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#exporter-labels). | 1178 | | -* `context` {Buffer} Optionally provide a context. | 1179 | | - | 1180 | | -* Returns: {Buffer} requested bytes of the keying material | 1181 | | - | 1182 | | -Keying material is used for validations to prevent different kind of attacks in | 1183 | | -network protocols, for example in the specifications of IEEE 802.1X. | 1184 | | - | 1185 | | -Example | 1186 | | - | 1187 | | -```js | 1188 | | -const keyingMaterial = tlsSocket.exportKeyingMaterial( | 1189 | | - 128, | 1190 | | - 'client finished'); | 1191 | | - | 1192 | | -/** | 1193 | | - Example return value of keyingMaterial: | 1194 | | - <Buffer 76 26 af 99 c5 56 8e 42 09 91 ef 9f 93 cb ad 6c 7b 65 f8 53 f1 d8 d9 | 1195 | | - 12 5a 33 b8 b5 25 df 7b 37 9f e0 e2 4f b8 67 83 a3 2f cd 5d 41 42 4c 91 | 1196 | | - 74 ef 2c ... 78 more bytes> | 1197 | | -*/ | 1198 | | -``` | 1199 | | -See the OpenSSL [`SSL_export_keying_material`][] documentation for more | 1200 | | -information. | 1201 | | - | 1202 | 1214 | ### `tlsSocket.getTLSTicket()` | 1203 | 1215 | <!-- YAML | 1204 | 1216 | added: v0.11.4 | @@ -1213,6 +1225,18 @@ It may be useful for debugging. | 1213 | 1225 |
| 1214 | 1226 | See [Session Resumption][] for more information. | 1215 | 1227 |
| | 1228 | +### `tlsSocket.getX509Certificate()` | | 1229 | +<!-- YAML | | 1230 | +added: REPLACEME | | 1231 | +--> | | 1232 | + | | 1233 | +* Returns: {X509Certificate} | | 1234 | + | | 1235 | +Returns the local certificate as an {X509Certificate} object. | | 1236 | + | | 1237 | +If there is no local certificate, or the socket has been destroyed, | | 1238 | +`undefined` will be returned. | | 1239 | + | 1216 | 1240 | ### `tlsSocket.isSessionReused()` | 1217 | 1241 | <!-- YAML | 1218 | 1242 | added: v0.5.6 | |
Collapse file Copy file name to clipboardExpand all lines: lib/_tls_wrap.js +13Lines changed: 13 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -90,6 +90,9 @@ const { | 90 | 90 | validateString, | 91 | 91 | validateUint32 | 92 | 92 | } = require('internal/validators'); | | 93 | +const { | | 94 | + InternalX509Certificate | | 95 | +} = require('internal/crypto/x509'); | 93 | 96 | const traceTls = getOptionValue('--trace-tls'); | 94 | 97 | const tlsKeylog = getOptionValue('--tls-keylog'); | 95 | 98 | const { appendFile } = require('fs'); | @@ -998,6 +1001,16 @@ TLSSocket.prototype.getCertificate = function() { | 998 | 1001 | return null; | 999 | 1002 | }; | 1000 | 1003 |
| | 1004 | +TLSSocket.prototype.getPeerX509Certificate = function(detailed) { | | 1005 | + const cert = this._handle?.getPeerX509Certificate(); | | 1006 | + return cert ? new InternalX509Certificate(cert) : undefined; | | 1007 | +}; | | 1008 | + | | 1009 | +TLSSocket.prototype.getX509Certificate = function() { | | 1010 | + const cert = this._handle?.getX509Certificate(); | | 1011 | + return cert ? new InternalX509Certificate(cert) : undefined; | | 1012 | +}; | | 1013 | + | 1001 | 1014 | // Proxy TLSSocket handle methods | 1002 | 1015 | function makeSocketMethodProxy(name) { | 1003 | 1016 | return function socketMethodProxy(...args) { | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/crypto/x509.js +20-9Lines changed: 20 additions & 9 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -90,6 +90,15 @@ function getFlags(options = {}) { | 90 | 90 | return flags; | 91 | 91 | } | 92 | 92 |
| | 93 | +class InternalX509Certificate extends JSTransferable { | | 94 | + [kInternalState] = new SafeMap(); | | 95 | + | | 96 | + constructor(handle) { | | 97 | + super(); | | 98 | + this[kHandle] = handle; | | 99 | + } | | 100 | +} | | 101 | + | 93 | 102 | class X509Certificate extends JSTransferable { | 94 | 103 | [kInternalState] = new SafeMap(); | 95 | 104 |
| @@ -168,6 +177,17 @@ class X509Certificate extends JSTransferable { | 168 | 177 | return value; | 169 | 178 | } | 170 | 179 |
| | 180 | + get issuerCertificate() { | | 181 | + let value = this[kInternalState].get('issuerCertificate'); | | 182 | + if (value === undefined) { | | 183 | + const cert = this[kHandle].getIssuerCert(); | | 184 | + if (cert) | | 185 | + value = new InternalX509Certificate(this[kHandle].getIssuerCert()); | | 186 | + this[kInternalState].set('issuerCertificate', value); | | 187 | + } | | 188 | + return value; | | 189 | + } | | 190 | + | 171 | 191 | get infoAccess() { | 172 | 192 | let value = this[kInternalState].get('infoAccess'); | 173 | 193 | if (value === undefined) { | @@ -313,15 +333,6 @@ class X509Certificate extends JSTransferable { | 313 | 333 | } | 314 | 334 | } | 315 | 335 |
| 316 | | -class InternalX509Certificate extends JSTransferable { | 317 | | - [kInternalState] = new SafeMap(); | 318 | | - | 319 | | - constructor(handle) { | 320 | | - super(); | 321 | | - this[kHandle] = handle; | 322 | | - } | 323 | | -} | 324 | | - | 325 | 336 | InternalX509Certificate.prototype.constructor = X509Certificate; | 326 | 337 | ObjectSetPrototypeOf( | 327 | 338 | InternalX509Certificate.prototype, | |
Collapse file Copy file name to clipboardExpand all lines: src/crypto/crypto_tls.cc +26Lines changed: 26 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -1591,6 +1591,20 @@ void TLSWrap::GetPeerCertificate(const FunctionCallbackInfo<Value>& args) { | 1591 | 1591 | args.GetReturnValue().Set(ret); | 1592 | 1592 | } | 1593 | 1593 |
| | 1594 | +void TLSWrap::GetPeerX509Certificate(const FunctionCallbackInfo<Value>& args) { | | 1595 | + TLSWrap* w; | | 1596 | + ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); | | 1597 | + Environment* env = w->env(); | | 1598 | + | | 1599 | + X509Certificate::GetPeerCertificateFlag flag = w->is_server() | | 1600 | + ? X509Certificate::GetPeerCertificateFlag::SERVER | | 1601 | + : X509Certificate::GetPeerCertificateFlag::NONE; | | 1602 | + | | 1603 | + Local<Value> ret; | | 1604 | + if (X509Certificate::GetPeerCert(env, w->ssl_, flag).ToLocal(&ret)) | | 1605 | + args.GetReturnValue().Set(ret); | | 1606 | +} | | 1607 | + | 1594 | 1608 | void TLSWrap::GetCertificate(const FunctionCallbackInfo<Value>& args) { | 1595 | 1609 | TLSWrap* w; | 1596 | 1610 | ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); | @@ -1601,6 +1615,15 @@ void TLSWrap::GetCertificate(const FunctionCallbackInfo<Value>& args) { | 1601 | 1615 | args.GetReturnValue().Set(ret); | 1602 | 1616 | } | 1603 | 1617 |
| | 1618 | +void TLSWrap::GetX509Certificate(const FunctionCallbackInfo<Value>& args) { | | 1619 | + TLSWrap* w; | | 1620 | + ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); | | 1621 | + Environment* env = w->env(); | | 1622 | + Local<Value> ret; | | 1623 | + if (X509Certificate::GetCert(env, w->ssl_).ToLocal(&ret)) | | 1624 | + args.GetReturnValue().Set(ret); | | 1625 | +} | | 1626 | + | 1604 | 1627 | void TLSWrap::GetFinished(const FunctionCallbackInfo<Value>& args) { | 1605 | 1628 | Environment* env = Environment::GetCurrent(args); | 1606 | 1629 |
| @@ -2051,11 +2074,14 @@ void TLSWrap::Initialize( | 2051 | 2074 | env->SetProtoMethodNoSideEffect(t, "getALPNNegotiatedProtocol", | 2052 | 2075 | GetALPNNegotiatedProto); | 2053 | 2076 | env->SetProtoMethodNoSideEffect(t, "getCertificate", GetCertificate); | | 2077 | + env->SetProtoMethodNoSideEffect(t, "getX509Certificate", GetX509Certificate); | 2054 | 2078 | env->SetProtoMethodNoSideEffect(t, "getCipher", GetCipher); | 2055 | 2079 | env->SetProtoMethodNoSideEffect(t, "getEphemeralKeyInfo", | 2056 | 2080 | GetEphemeralKeyInfo); | 2057 | 2081 | env->SetProtoMethodNoSideEffect(t, "getFinished", GetFinished); | 2058 | 2082 | env->SetProtoMethodNoSideEffect(t, "getPeerCertificate", GetPeerCertificate); | | 2083 | + env->SetProtoMethodNoSideEffect(t, "getPeerX509Certificate", | | 2084 | + GetPeerX509Certificate); | 2059 | 2085 | env->SetProtoMethodNoSideEffect(t, "getPeerFinished", GetPeerFinished); | 2060 | 2086 | env->SetProtoMethodNoSideEffect(t, "getProtocol", GetProtocol); | 2061 | 2087 | env->SetProtoMethodNoSideEffect(t, "getSession", GetSession); | |
Collapse file Copy file name to clipboardExpand all lines: src/crypto/crypto_tls.h +4Lines changed: 4 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -184,12 +184,16 @@ class TLSWrap : public AsyncWrap, | 184 | 184 | static void GetALPNNegotiatedProto( | 185 | 185 | const v8::FunctionCallbackInfo<v8::Value>& args); | 186 | 186 | static void GetCertificate(const v8::FunctionCallbackInfo<v8::Value>& args); | | 187 | + static void GetX509Certificate( | | 188 | + const v8::FunctionCallbackInfo<v8::Value>& args); | 187 | 189 | static void GetCipher(const v8::FunctionCallbackInfo<v8::Value>& args); | 188 | 190 | static void GetEphemeralKeyInfo( | 189 | 191 | const v8::FunctionCallbackInfo<v8::Value>& args); | 190 | 192 | static void GetFinished(const v8::FunctionCallbackInfo<v8::Value>& args); | 191 | 193 | static void GetPeerCertificate( | 192 | 194 | const v8::FunctionCallbackInfo<v8::Value>& args); | | 195 | + static void GetPeerX509Certificate( | | 196 | + const v8::FunctionCallbackInfo<v8::Value>& args); | 193 | 197 | static void GetPeerFinished(const v8::FunctionCallbackInfo<v8::Value>& args); | 194 | 198 | static void GetProtocol(const v8::FunctionCallbackInfo<v8::Value>& args); | 195 | 199 | static void GetServername(const v8::FunctionCallbackInfo<v8::Value>& args); | |
|