Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions deps/ncrypto/ncrypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3086,6 +3086,17 @@ EVPKeyPointer SSLPointer::getPeerTempKey() const {
return EVPKeyPointer(raw_key);
}

std::optional<std::string_view> SSLPointer::getNegotiatedGroup() const {
#if OPENSSL_VERSION_PREREQ(3, 5)
if (!ssl_) return std::nullopt;
const char* group = SSL_get0_group_name(get());
if (group == nullptr) return std::nullopt;
return group;
#else
return std::nullopt;
#endif
}

std::optional<std::string_view> SSLPointer::getCipherName() const {
auto cipher = getCipher();
if (cipher == nullptr) return std::nullopt;
Expand Down
1 change: 1 addition & 0 deletions deps/ncrypto/ncrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,7 @@ class SSLPointer final {
std::optional<const std::string_view> getServerName() const;
X509View getCertificate() const;
EVPKeyPointer getPeerTempKey() const;
std::optional<std::string_view> getNegotiatedGroup() const;
const SSL_CIPHER* getCipher() const;
bool isServer() const;

Expand Down
45 changes: 29 additions & 16 deletions doc/api/tls.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ the character "E" appended to the traditional abbreviations):

Perfect forward secrecy using ECDHE is enabled by default. The `ecdhCurve`
option can be used when creating a TLS server to customize the list of supported
ECDH curves to use. See [`tls.createServer()`][] for more info.
ECDH curves for TLSv1.2 and below, and the list of supported TLS groups for
TLSv1.3. See [`tls.createServer()`][] for more info.

DHE is disabled by default but can be enabled alongside ECDHE by setting the
`dhparam` option to `'auto'`. Custom DHE parameters are also supported but
Expand Down Expand Up @@ -1196,12 +1197,19 @@ added: v5.0.0

* Returns: {Object}

Returns an object representing the type, name, and size of parameter of
an ephemeral key exchange in [perfect forward secrecy][] on a client
connection. It returns an empty object when the key exchange is not
ephemeral. As this is only supported on a client socket; `null` is returned
if called on a server socket. The supported types are `'DH'` and `'ECDH'`. The
`name` property is available only when type is `'ECDH'`.
Returns an object describing ephemeral key agreement in [perfect forward
secrecy][] on a client connection. It returns an empty object when the key
agreement is not ephemeral. As this is only supported on a client socket;
`null` is returned if called on a server socket. The supported types are `'DH'`,
`'ECDH'`, and `'TLSGroup'`. For `'DH'` and `'ECDH'`, the object describes peer
temporary key parameters. For `'TLSGroup'`, the object identifies the negotiated
TLS Supported Group used for key agreement when a peer temporary key object is
not available.

The `name` property is available only when type is `'ECDH'` or `'TLSGroup'`. The
`size` property is not available when type is `'TLSGroup'`. For `'TLSGroup'`,
`name` is the negotiated TLS Supported Group name. Standardized TLS group names
and code points are listed in the [IANA TLS Supported Groups registry][].

For example: `{ type: 'ECDH', name: 'prime256v1', size: 256 }`.

Expand Down Expand Up @@ -2019,12 +2027,16 @@ changes:
required for non-ECDHE [perfect forward secrecy][]. If omitted or invalid,
the parameters are silently discarded and DHE ciphers will not be available.
[ECDHE][]-based [perfect forward secrecy][] will still be available.
* `ecdhCurve` {string} A string describing a named curve or a colon separated
list of curve NIDs or names, for example `P-521:P-384:P-256`, to use for
ECDH key agreement. Set to `auto` to select the
curve automatically. Use [`crypto.getCurves()`][] to obtain a list of
available curve names. On recent releases, `openssl ecparam -list_curves`
will also display the name and description of each available elliptic curve.
* `ecdhCurve` {string} A string describing a named curve, TLS group, or
colon-separated list of named curves or TLS groups to use for key agreement,
for example `P-521:P-384:P-256`, `X25519`, or `X25519MLKEM768`. The
historical name of this option refers to ECDH key agreement in TLSv1.2 and
below. In TLSv1.3, this option configures the TLS Supported Groups and
key share groups offered or accepted by the TLS stack. Set to `auto` to
select the group automatically. Use [`crypto.getCurves()`][] to obtain a
list of available elliptic curve names. For TLS group names, use
`openssl list -tls-groups` or consult the [IANA TLS Supported Groups
registry][].
**Default:** [`tls.DEFAULT_ECDH_CURVE`][].
* `honorCipherOrder` {boolean} Attempt to use the server's cipher suite
preferences instead of the client's. When `true`, causes
Expand Down Expand Up @@ -2442,9 +2454,9 @@ changes:
description: Default value changed to `'auto'`.
-->

The default curve name to use for ECDH key agreement in a tls server. The
default value is `'auto'`. See [`tls.createSecureContext()`][] for further
information.
The default named curve or TLS group list to use for key agreement in a TLS
server. The default value is `'auto'`. See [`tls.createSecureContext()`][] for
further information.

## `tls.DEFAULT_MAX_VERSION`

Expand Down Expand Up @@ -2492,6 +2504,7 @@ added: v0.11.3
[Chrome's 'modern cryptography' setting]: https://www.chromium.org/Home/chromium-security/education/tls#TOC-Cipher-Suites
[DHE]: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
[ECDHE]: https://en.wikipedia.org/wiki/Elliptic_curve_Diffie%E2%80%93Hellman
[IANA TLS Supported Groups registry]: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
[Modifying the default TLS cipher suite]: #modifying-the-default-tls-cipher-suite
[Mozilla's publicly trusted list of CAs]: https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt
[OCSP request]: https://en.wikipedia.org/wiki/OCSP_stapling
Expand Down
11 changes: 10 additions & 1 deletion src/crypto/crypto_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -215,13 +215,15 @@ MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) {
Undefined(env->isolate()), // name
Undefined(env->isolate()), // size
};
EVPKeyPointer key = ssl.getPeerTempKey();

bool found = false;
if (EVPKeyPointer key = ssl.getPeerTempKey()) {
int kid = key.id();
switch (kid) {
case EVP_PKEY_DH: {
values[0] = env->dh_string();
values[2] = Integer::New(env->isolate(), key.bits());
found = true;
break;
}
case EVP_PKEY_EC:
Expand All @@ -237,10 +239,17 @@ MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) {
values[0] = env->ecdh_string();
values[1] = OneByteString(env->isolate(), curve_name);
values[2] = Integer::New(env->isolate(), key.bits());
found = true;
break;
}
}
}
if (!found) {
if (auto name = ssl.getNegotiatedGroup()) {
values[0] = env->tls_group_string();
values[1] = OneByteString(env->isolate(), name.value());
}
}

return scope.EscapeMaybe(NewDictionaryInstance(env->context(), tmpl, values));
}
Expand Down
1 change: 1 addition & 0 deletions src/env_properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@
V(target_string, "target") \
V(thread_id_string, "threadId") \
V(thread_name_string, "threadName") \
V(tls_group_string, "TLSGroup") \
V(ticketkeycallback_string, "onticketkeycallback") \
V(timeout_string, "timeout") \
V(time_to_first_byte_string, "timeToFirstByte") \
Expand Down
57 changes: 54 additions & 3 deletions test/parallel/test-tls-client-getephemeralkeyinfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ const tls = require('tls');
const key = fixtures.readKey('agent2-key.pem');
const cert = fixtures.readKey('agent2-cert.pem');

// TODO(@sam-github) test works with TLS1.3, rework test to add
// 'ECDH' with 'TLS_AES_128_GCM_SHA256',

function loadDHParam(n) {
return fixtures.readKey(`dh${n}.pem`);
}
Expand Down Expand Up @@ -89,3 +86,57 @@ test(256, 'ECDH', 'prime256v1', 'ECDHE-RSA-AES256-GCM-SHA384');
test(521, 'ECDH', 'secp521r1', 'ECDHE-RSA-AES256-GCM-SHA384');
test(253, 'ECDH', 'X25519', 'ECDHE-RSA-AES256-GCM-SHA384');
test(448, 'ECDH', 'X448', 'ECDHE-RSA-AES256-GCM-SHA384');

function testTLS13Group(size, type, name) {
const options = {
key,
cert,
ecdhCurve: name,
minVersion: 'TLSv1.3',
maxVersion: 'TLSv1.3',
};

const server = tls.createServer(options, common.mustCall((conn) => {
assert.strictEqual(conn.getEphemeralKeyInfo(), null);
conn.end();
}));

server.on('close', common.mustSucceed());

server.listen(0, common.mustCall(() => {
const client = tls.connect({
port: server.address().port,
rejectUnauthorized: false,
ecdhCurve: name,
minVersion: 'TLSv1.3',
maxVersion: 'TLSv1.3',
}, common.mustCall(() => {
const ekeyinfo = client.getEphemeralKeyInfo();
assert.strictEqual(ekeyinfo.type, type);
assert.strictEqual(ekeyinfo.size, size);
assert.strictEqual(ekeyinfo.name, name);
server.close();
}));
client.on('secureConnect', common.mustCall());
}));
}

testTLS13Group(253, 'ECDH', 'X25519');

if (hasOpenSSL(3, 5)) {
const tls13Groups = [
'MLKEM512',
'MLKEM768',
'MLKEM1024',
'SecP256r1MLKEM768',
'X25519MLKEM768',
'SecP384r1MLKEM1024',
];

if (hasOpenSSL(4, 0)) {
tls13Groups.push('curveSM2');
tls13Groups.push('curveSM2MLKEM768');
}

tls13Groups.forEach((name) => testTLS13Group(undefined, 'TLSGroup', name));
}
Loading