tls: return correct version from getCipher()
OpenSSL 1.0.0 returned incorrect version information. OpenSSL 1.1.0 fixed this, but returning the correct information broke our tests, so was considered semver-major. Because of this, the version was hard-coded to the OpenSSL 1.0.0 (incorrect) string in 5fe81c8aff03261. This is ancient history, start returning the correct cipher version. PR-URL: https://github.com/nodejs/node/pull/26625 Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Richard Lau <riclau@uk.ibm.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
parent
1ceb6d8e9b
commit
0f745bf9bd
@ -717,18 +717,25 @@ socket has been destroyed, `null` will be returned.
|
|||||||
### tlsSocket.getCipher()
|
### tlsSocket.getCipher()
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
added: v0.11.4
|
added: v0.11.4
|
||||||
|
changes:
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/26625
|
||||||
|
description: Return the minimum cipher version, instead of a fixed string
|
||||||
|
(`'TLSv1/SSLv3'`).
|
||||||
-->
|
-->
|
||||||
|
|
||||||
* Returns: {Object}
|
* Returns: {Object}
|
||||||
|
* `name` {string} The name of the cipher suite.
|
||||||
|
* `version` {string} The minimum TLS protocol version supported by this cipher
|
||||||
|
suite.
|
||||||
|
|
||||||
Returns an object representing the cipher name. The `version` key is a legacy
|
Returns an object containing information on the negotiated cipher suite.
|
||||||
field which always contains the value `'TLSv1/SSLv3'`.
|
|
||||||
|
|
||||||
For example: `{ name: 'AES256-SHA', version: 'TLSv1/SSLv3' }`.
|
For example: `{ name: 'AES256-SHA', version: 'TLSv1/SSLv3' }`.
|
||||||
|
|
||||||
See `SSL_CIPHER_get_name()` in
|
See
|
||||||
<https://www.openssl.org/docs/man1.1.0/ssl/SSL_CIPHER_get_name.html> for more
|
[OpenSSL](https://www.openssl.org/docs/man1.1.1/man3/SSL_CIPHER_get_name.html)
|
||||||
information.
|
for more information.
|
||||||
|
|
||||||
### tlsSocket.getEphemeralKeyInfo()
|
### tlsSocket.getEphemeralKeyInfo()
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
|
@ -737,18 +737,18 @@ function makeSocketMethodProxy(name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[
|
[
|
||||||
'getFinished', 'getPeerFinished', 'getSession', 'isSessionReused',
|
'getCipher',
|
||||||
'getEphemeralKeyInfo', 'getProtocol', 'getTLSTicket'
|
'getEphemeralKeyInfo',
|
||||||
|
'getFinished',
|
||||||
|
'getPeerFinished',
|
||||||
|
'getProtocol',
|
||||||
|
'getSession',
|
||||||
|
'getTLSTicket',
|
||||||
|
'isSessionReused',
|
||||||
].forEach((method) => {
|
].forEach((method) => {
|
||||||
TLSSocket.prototype[method] = makeSocketMethodProxy(method);
|
TLSSocket.prototype[method] = makeSocketMethodProxy(method);
|
||||||
});
|
});
|
||||||
|
|
||||||
TLSSocket.prototype.getCipher = function(err) {
|
|
||||||
if (this._handle)
|
|
||||||
return this._handle.getCurrentCipher();
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: support anonymous (nocert) and PSK
|
// TODO: support anonymous (nocert) and PSK
|
||||||
|
|
||||||
|
|
||||||
|
@ -1464,7 +1464,7 @@ void SSLWrap<Base>::AddMethods(Environment* env, Local<FunctionTemplate> t) {
|
|||||||
env->SetProtoMethod(t, "loadSession", LoadSession);
|
env->SetProtoMethod(t, "loadSession", LoadSession);
|
||||||
env->SetProtoMethodNoSideEffect(t, "isSessionReused", IsSessionReused);
|
env->SetProtoMethodNoSideEffect(t, "isSessionReused", IsSessionReused);
|
||||||
env->SetProtoMethodNoSideEffect(t, "verifyError", VerifyError);
|
env->SetProtoMethodNoSideEffect(t, "verifyError", VerifyError);
|
||||||
env->SetProtoMethodNoSideEffect(t, "getCurrentCipher", GetCurrentCipher);
|
env->SetProtoMethodNoSideEffect(t, "getCipher", GetCipher);
|
||||||
env->SetProtoMethod(t, "endParser", EndParser);
|
env->SetProtoMethod(t, "endParser", EndParser);
|
||||||
env->SetProtoMethod(t, "certCbDone", CertCbDone);
|
env->SetProtoMethod(t, "certCbDone", CertCbDone);
|
||||||
env->SetProtoMethod(t, "renegotiate", Renegotiate);
|
env->SetProtoMethod(t, "renegotiate", Renegotiate);
|
||||||
@ -2357,7 +2357,7 @@ void SSLWrap<Base>::VerifyError(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
|
|
||||||
template <class Base>
|
template <class Base>
|
||||||
void SSLWrap<Base>::GetCurrentCipher(const FunctionCallbackInfo<Value>& args) {
|
void SSLWrap<Base>::GetCipher(const FunctionCallbackInfo<Value>& args) {
|
||||||
Base* w;
|
Base* w;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder());
|
||||||
Environment* env = w->ssl_env();
|
Environment* env = w->ssl_env();
|
||||||
@ -2371,8 +2371,9 @@ void SSLWrap<Base>::GetCurrentCipher(const FunctionCallbackInfo<Value>& args) {
|
|||||||
const char* cipher_name = SSL_CIPHER_get_name(c);
|
const char* cipher_name = SSL_CIPHER_get_name(c);
|
||||||
info->Set(context, env->name_string(),
|
info->Set(context, env->name_string(),
|
||||||
OneByteString(args.GetIsolate(), cipher_name)).FromJust();
|
OneByteString(args.GetIsolate(), cipher_name)).FromJust();
|
||||||
|
const char* cipher_version = SSL_CIPHER_get_version(c);
|
||||||
info->Set(context, env->version_string(),
|
info->Set(context, env->version_string(),
|
||||||
OneByteString(args.GetIsolate(), "TLSv1/SSLv3")).FromJust();
|
OneByteString(args.GetIsolate(), cipher_version)).FromJust();
|
||||||
args.GetReturnValue().Set(info);
|
args.GetReturnValue().Set(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,7 +281,7 @@ class SSLWrap {
|
|||||||
static void LoadSession(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void LoadSession(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void IsSessionReused(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void IsSessionReused(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void VerifyError(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void VerifyError(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void GetCurrentCipher(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void GetCipher(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void EndParser(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void EndParser(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void CertCbDone(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void CertCbDone(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void Renegotiate(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void Renegotiate(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
@ -30,28 +30,42 @@ const tls = require('tls');
|
|||||||
// Import fixtures directly from its module
|
// Import fixtures directly from its module
|
||||||
const fixtures = require('../common/fixtures');
|
const fixtures = require('../common/fixtures');
|
||||||
|
|
||||||
const cipher_list = ['AES128-SHA256', 'AES256-SHA256'];
|
|
||||||
const cipher_version_pattern = /TLS|SSL/;
|
|
||||||
const options = {
|
const options = {
|
||||||
key: fixtures.readKey('agent2-key.pem'),
|
key: fixtures.readKey('agent2-key.pem'),
|
||||||
cert: fixtures.readKey('agent2-cert.pem'),
|
cert: fixtures.readKey('agent2-cert.pem'),
|
||||||
ciphers: cipher_list.join(':'),
|
|
||||||
honorCipherOrder: true
|
honorCipherOrder: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const server = tls.createServer(options, common.mustCall());
|
let clients = 0;
|
||||||
|
const server = tls.createServer(options, common.mustCall(() => {
|
||||||
|
if (--clients === 0)
|
||||||
|
server.close();
|
||||||
|
}, 2));
|
||||||
|
|
||||||
server.listen(0, '127.0.0.1', common.mustCall(function() {
|
server.listen(0, '127.0.0.1', common.mustCall(function() {
|
||||||
const client = tls.connect({
|
clients++;
|
||||||
|
tls.connect({
|
||||||
host: '127.0.0.1',
|
host: '127.0.0.1',
|
||||||
port: this.address().port,
|
port: this.address().port,
|
||||||
ciphers: cipher_list.join(':'),
|
ciphers: 'AES128-SHA256',
|
||||||
rejectUnauthorized: false
|
rejectUnauthorized: false
|
||||||
}, common.mustCall(function() {
|
}, common.mustCall(function() {
|
||||||
const cipher = client.getCipher();
|
const cipher = this.getCipher();
|
||||||
assert.strictEqual(cipher.name, cipher_list[0]);
|
assert.strictEqual(cipher.name, 'AES128-SHA256');
|
||||||
assert(cipher_version_pattern.test(cipher.version));
|
assert.strictEqual(cipher.version, 'TLSv1.2');
|
||||||
client.end();
|
this.end();
|
||||||
server.close();
|
}));
|
||||||
|
|
||||||
|
clients++;
|
||||||
|
tls.connect({
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: this.address().port,
|
||||||
|
cipher: 'ECDHE-RSA-AES128-GCM-SHA256',
|
||||||
|
rejectUnauthorized: false
|
||||||
|
}, common.mustCall(function() {
|
||||||
|
const cipher = this.getCipher();
|
||||||
|
assert.strictEqual(cipher.name, 'ECDHE-RSA-AES128-GCM-SHA256');
|
||||||
|
assert.strictEqual(cipher.version, 'TLSv1.2');
|
||||||
|
this.end();
|
||||||
}));
|
}));
|
||||||
}));
|
}));
|
||||||
|
@ -157,7 +157,7 @@ function test(options) {
|
|||||||
}, common.mustCall(function() {
|
}, common.mustCall(function() {
|
||||||
assert.deepStrictEqual(ecdsa.getCipher(), {
|
assert.deepStrictEqual(ecdsa.getCipher(), {
|
||||||
name: 'ECDHE-ECDSA-AES256-GCM-SHA384',
|
name: 'ECDHE-ECDSA-AES256-GCM-SHA384',
|
||||||
version: 'TLSv1/SSLv3'
|
version: 'TLSv1.2'
|
||||||
});
|
});
|
||||||
assert.strictEqual(ecdsa.getPeerCertificate().subject.CN, eccCN);
|
assert.strictEqual(ecdsa.getPeerCertificate().subject.CN, eccCN);
|
||||||
// XXX(sam) certs don't currently include EC key info, so depend on
|
// XXX(sam) certs don't currently include EC key info, so depend on
|
||||||
@ -177,7 +177,7 @@ function test(options) {
|
|||||||
}, common.mustCall(function() {
|
}, common.mustCall(function() {
|
||||||
assert.deepStrictEqual(rsa.getCipher(), {
|
assert.deepStrictEqual(rsa.getCipher(), {
|
||||||
name: 'ECDHE-RSA-AES256-GCM-SHA384',
|
name: 'ECDHE-RSA-AES256-GCM-SHA384',
|
||||||
version: 'TLSv1/SSLv3'
|
version: 'TLSv1.2'
|
||||||
});
|
});
|
||||||
assert.strictEqual(rsa.getPeerCertificate().subject.CN, rsaCN);
|
assert.strictEqual(rsa.getPeerCertificate().subject.CN, rsaCN);
|
||||||
assert(rsa.getPeerCertificate().exponent, 'cert for an RSA key');
|
assert(rsa.getPeerCertificate().exponent, 'cert for an RSA key');
|
||||||
|
@ -42,9 +42,9 @@ const server = tls.createServer(options, function(conn) {
|
|||||||
process.on('exit', function() {
|
process.on('exit', function() {
|
||||||
assert.deepStrictEqual(ciphers, [{
|
assert.deepStrictEqual(ciphers, [{
|
||||||
name: 'ECDHE-ECDSA-AES256-GCM-SHA384',
|
name: 'ECDHE-ECDSA-AES256-GCM-SHA384',
|
||||||
version: 'TLSv1/SSLv3'
|
version: 'TLSv1.2'
|
||||||
}, {
|
}, {
|
||||||
name: 'ECDHE-RSA-AES256-GCM-SHA384',
|
name: 'ECDHE-RSA-AES256-GCM-SHA384',
|
||||||
version: 'TLSv1/SSLv3'
|
version: 'TLSv1.2'
|
||||||
}]);
|
}]);
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user