tls: get the local certificate after tls handshake
Add an API to get the local certificate chosen during TLS handshake from the SSL context. Fix: https://github.com/nodejs/node/issues/24095 PR-URL: https://github.com/nodejs/node/pull/24261 Fixes: https://github.com/nodejs/node/issues/24095 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
This commit is contained in:
parent
98278584ee
commit
db35fee1e1
@ -566,6 +566,22 @@ added: v0.11.4
|
||||
Always returns `true`. This may be used to distinguish TLS sockets from regular
|
||||
`net.Socket` instances.
|
||||
|
||||
### tlsSocket.getCertificate()
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
* Returns: {Object}
|
||||
|
||||
Returns an object representing the local certificate. The returned object has
|
||||
some properties corresponding to the fields of the certificate.
|
||||
|
||||
See [`tls.TLSSocket.getPeerCertificate()`][] for an example of the certificate
|
||||
structure.
|
||||
|
||||
If there is no local certificate, an empty object will be returned. If the
|
||||
socket has been destroyed, `null` will be returned.
|
||||
|
||||
### tlsSocket.getCipher()
|
||||
<!-- YAML
|
||||
added: v0.11.4
|
||||
@ -658,6 +674,7 @@ certificate.
|
||||
```
|
||||
|
||||
If the peer does not provide a certificate, an empty object will be returned.
|
||||
If the socket has been destroyed, `null` will be returned.
|
||||
|
||||
### tlsSocket.getPeerFinished()
|
||||
<!-- YAML
|
||||
|
@ -202,6 +202,9 @@ exports.createSecureContext = function createSecureContext(options) {
|
||||
return c;
|
||||
};
|
||||
|
||||
// Translate some fields from the handle's C-friendly format into more idiomatic
|
||||
// javascript object representations before passing them back to the user. Can
|
||||
// be used on any cert object, but changing the name would be semver-major.
|
||||
exports.translatePeerCertificate = function translatePeerCertificate(c) {
|
||||
if (!c)
|
||||
return null;
|
||||
|
@ -660,7 +660,17 @@ TLSSocket.prototype.setSession = function(session) {
|
||||
TLSSocket.prototype.getPeerCertificate = function(detailed) {
|
||||
if (this._handle) {
|
||||
return common.translatePeerCertificate(
|
||||
this._handle.getPeerCertificate(detailed));
|
||||
this._handle.getPeerCertificate(detailed)) || {};
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
TLSSocket.prototype.getCertificate = function() {
|
||||
if (this._handle) {
|
||||
// It's not a peer cert, but the formatting is identical.
|
||||
return common.translatePeerCertificate(
|
||||
this._handle.getCertificate()) || {};
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -1409,6 +1409,7 @@ void SSLWrap<Base>::AddMethods(Environment* env, Local<FunctionTemplate> t) {
|
||||
HandleScope scope(env->isolate());
|
||||
|
||||
env->SetProtoMethodNoSideEffect(t, "getPeerCertificate", GetPeerCertificate);
|
||||
env->SetProtoMethodNoSideEffect(t, "getCertificate", GetCertificate);
|
||||
env->SetProtoMethodNoSideEffect(t, "getFinished", GetFinished);
|
||||
env->SetProtoMethodNoSideEffect(t, "getPeerFinished", GetPeerFinished);
|
||||
env->SetProtoMethodNoSideEffect(t, "getSession", GetSession);
|
||||
@ -1871,8 +1872,26 @@ void SSLWrap<Base>::GetPeerCertificate(
|
||||
}
|
||||
|
||||
done:
|
||||
if (result.IsEmpty())
|
||||
result = Object::New(env->isolate());
|
||||
args.GetReturnValue().Set(result);
|
||||
}
|
||||
|
||||
|
||||
template <class Base>
|
||||
void SSLWrap<Base>::GetCertificate(
|
||||
const FunctionCallbackInfo<Value>& args) {
|
||||
Base* w;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder());
|
||||
Environment* env = w->ssl_env();
|
||||
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
|
||||
Local<Object> result;
|
||||
|
||||
X509Pointer cert(SSL_get_certificate(w->ssl_.get()));
|
||||
|
||||
if (cert)
|
||||
result = X509ToObject(env, cert.get());
|
||||
|
||||
args.GetReturnValue().Set(result);
|
||||
}
|
||||
|
||||
|
@ -272,6 +272,7 @@ class SSLWrap {
|
||||
|
||||
static void GetPeerCertificate(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void GetCertificate(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void GetFinished(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void GetPeerFinished(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void GetSession(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
@ -26,7 +26,6 @@ if (!common.hasCrypto)
|
||||
|
||||
const assert = require('assert');
|
||||
const tls = require('tls');
|
||||
const util = require('util');
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
const options = {
|
||||
@ -37,13 +36,22 @@ const options = {
|
||||
const server = tls.createServer(options, function(cleartext) {
|
||||
cleartext.end('World');
|
||||
});
|
||||
|
||||
server.once('secureConnection', common.mustCall(function(socket) {
|
||||
const cert = socket.getCertificate();
|
||||
// The server's local cert is the client's peer cert.
|
||||
assert.deepStrictEqual(
|
||||
cert.subject.OU,
|
||||
['Information Technology', 'Engineering', 'Marketing']
|
||||
);
|
||||
}));
|
||||
|
||||
server.listen(0, common.mustCall(function() {
|
||||
const socket = tls.connect({
|
||||
port: this.address().port,
|
||||
rejectUnauthorized: false
|
||||
}, common.mustCall(function() {
|
||||
const peerCert = socket.getPeerCertificate();
|
||||
console.error(util.inspect(peerCert));
|
||||
assert.deepStrictEqual(
|
||||
peerCert.subject.OU,
|
||||
['Information Technology', 'Engineering', 'Marketing']
|
||||
|
@ -43,6 +43,8 @@ connect({
|
||||
}, function(err, pair, cleanup) {
|
||||
assert.ifError(err);
|
||||
const socket = pair.client.conn;
|
||||
const localCert = socket.getCertificate();
|
||||
assert.deepStrictEqual(localCert, {});
|
||||
let peerCert = socket.getPeerCertificate();
|
||||
assert.ok(!peerCert.issuerCertificate);
|
||||
|
||||
|
@ -22,6 +22,8 @@ const server = tls
|
||||
rejectUnauthorized: false
|
||||
},
|
||||
common.mustCall(function(c) {
|
||||
assert.strictEqual(c.getPeerCertificate().serialNumber,
|
||||
'FAD50CC6A07F516C');
|
||||
assert.strictEqual(c.authorizationError, null);
|
||||
c.end();
|
||||
})
|
||||
@ -35,6 +37,8 @@ const server = tls
|
||||
rejectUnauthorized: false
|
||||
},
|
||||
function() {
|
||||
assert.strictEqual(client.getCertificate().serialNumber,
|
||||
'FAD50CC6A07F516C');
|
||||
client.end();
|
||||
server.close();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user