Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 6d92eba

Browse filesBrowse files
author
Shigeki Ohtsu
committed
tls: add TLSSocket.getEphemeralKeyInfo()
Returns an object representing a type, name and size of an ephemeral key exchange in a client connection. Currently only DHE and ECHE are supported. This api only works on on a client connection. When it is called on a server connection, null is returned. When its key exchange is not ephemeral, an empty object is returned. PR-URL: #1831 Reviewed-By: indutny - Fedor Indutny <fedor.indutny@gmail.com> Reviewed-By: bnoordhuis - Ben Noordhuis <info@bnoordhuis.nl>
1 parent 503f279 commit 6d92eba
Copy full SHA for 6d92eba

File tree

Expand file treeCollapse file tree

5 files changed

+166
-0
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

5 files changed

+166
-0
lines changed
Open diff view settings
Collapse file

‎doc/api/tls.markdown‎

Copy file name to clipboardExpand all lines: doc/api/tls.markdown
+14Lines changed: 14 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,19 @@ See SSL_CIPHER_get_name() and SSL_CIPHER_get_version() in
809809
http://www.openssl.org/docs/ssl/ssl.html#DEALING_WITH_CIPHERS for more
810810
information.
811811

812+
### tlsSocket.getEphemeralKeyInfo()
813+
814+
Returns an object representing a type, name and size of parameter of
815+
an ephemeral key exchange in [Perfect forward Secrecy][] on a client
816+
connection. It returns an empty object when the key exchange is not
817+
ephemeral. As it is only supported on a client socket, it returns null
818+
if this is called on a server socket. The supported types are 'DH' and
819+
'ECDH'. The `name` property is only available in 'ECDH'.
820+
821+
Example:
822+
823+
{ type: 'ECDH', name: 'prime256v1', size: 256 }
824+
812825
### tlsSocket.renegotiate(options, callback)
813826

814827
Initiate TLS renegotiation process. The `options` may contain the following
@@ -887,6 +900,7 @@ The numeric representation of the local port.
887900
[net.Server.address()]: net.html#net_server_address
888901
['secureConnect']: #tls_event_secureconnect
889902
[secureConnection]: #tls_event_secureconnection
903+
[Perfect Forward Secrecy]: #tls_perfect_forward_secrecy
890904
[Stream]: stream.html#stream_stream
891905
[SSL_METHODS]: http://www.openssl.org/docs/ssl/ssl.html#DEALING_WITH_PROTOCOL_METHODS
892906
[tls.Server]: #tls_class_tls_server
Collapse file

‎lib/_tls_wrap.js‎

Copy file name to clipboardExpand all lines: lib/_tls_wrap.js
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,13 @@ TLSSocket.prototype.getCipher = function(err) {
628628
}
629629
};
630630

631+
TLSSocket.prototype.getEphemeralKeyInfo = function() {
632+
if (this._handle)
633+
return this._handle.getEphemeralKeyInfo();
634+
635+
return null;
636+
};
637+
631638
// TODO: support anonymous (nocert) and PSK
632639

633640

Collapse file

‎src/node_crypto.cc‎

Copy file name to clipboardExpand all lines: src/node_crypto.cc
+45Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,7 @@ void SSLWrap<Base>::AddMethods(Environment* env, Local<FunctionTemplate> t) {
11341134
env->SetProtoMethod(t, "newSessionDone", NewSessionDone);
11351135
env->SetProtoMethod(t, "setOCSPResponse", SetOCSPResponse);
11361136
env->SetProtoMethod(t, "requestOCSP", RequestOCSP);
1137+
env->SetProtoMethod(t, "getEphemeralKeyInfo", GetEphemeralKeyInfo);
11371138

11381139
#ifdef SSL_set_max_send_fragment
11391140
env->SetProtoMethod(t, "setMaxSendFragment", SetMaxSendFragment);
@@ -1744,6 +1745,50 @@ void SSLWrap<Base>::RequestOCSP(
17441745
}
17451746

17461747

1748+
template <class Base>
1749+
void SSLWrap<Base>::GetEphemeralKeyInfo(
1750+
const v8::FunctionCallbackInfo<v8::Value>& args) {
1751+
Base* w = Unwrap<Base>(args.Holder());
1752+
Environment* env = Environment::GetCurrent(args);
1753+
1754+
CHECK_NE(w->ssl_, nullptr);
1755+
1756+
// tmp key is available on only client
1757+
if (w->is_server())
1758+
return args.GetReturnValue().SetNull();
1759+
1760+
Local<Object> info = Object::New(env->isolate());
1761+
1762+
EVP_PKEY* key;
1763+
1764+
if (SSL_get_server_tmp_key(w->ssl_, &key)) {
1765+
switch (EVP_PKEY_id(key)) {
1766+
case EVP_PKEY_DH:
1767+
info->Set(env->type_string(),
1768+
FIXED_ONE_BYTE_STRING(env->isolate(), "DH"));
1769+
info->Set(env->size_string(),
1770+
Integer::New(env->isolate(), EVP_PKEY_bits(key)));
1771+
break;
1772+
case EVP_PKEY_EC:
1773+
{
1774+
EC_KEY* ec = EVP_PKEY_get1_EC_KEY(key);
1775+
int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
1776+
EC_KEY_free(ec);
1777+
info->Set(env->type_string(),
1778+
FIXED_ONE_BYTE_STRING(env->isolate(), "ECDH"));
1779+
info->Set(env->name_string(),
1780+
OneByteString(args.GetIsolate(), OBJ_nid2sn(nid)));
1781+
info->Set(env->size_string(),
1782+
Integer::New(env->isolate(), EVP_PKEY_bits(key)));
1783+
}
1784+
}
1785+
EVP_PKEY_free(key);
1786+
}
1787+
1788+
return args.GetReturnValue().Set(info);
1789+
}
1790+
1791+
17471792
#ifdef SSL_set_max_send_fragment
17481793
template <class Base>
17491794
void SSLWrap<Base>::SetMaxSendFragment(
Collapse file

‎src/node_crypto.h‎

Copy file name to clipboardExpand all lines: src/node_crypto.h
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ class SSLWrap {
236236
static void NewSessionDone(const v8::FunctionCallbackInfo<v8::Value>& args);
237237
static void SetOCSPResponse(const v8::FunctionCallbackInfo<v8::Value>& args);
238238
static void RequestOCSP(const v8::FunctionCallbackInfo<v8::Value>& args);
239+
static void GetEphemeralKeyInfo(
240+
const v8::FunctionCallbackInfo<v8::Value>& args);
239241

240242
#ifdef SSL_set_max_send_fragment
241243
static void SetMaxSendFragment(
Collapse file
+98Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
'use strict';
2+
var common = require('../common');
3+
var assert = require('assert');
4+
5+
if (!common.hasCrypto) {
6+
console.log('1..0 # Skipped: missing crypto');
7+
process.exit();
8+
}
9+
var tls = require('tls');
10+
11+
var fs = require('fs');
12+
var key = fs.readFileSync(common.fixturesDir + '/keys/agent2-key.pem');
13+
var cert = fs.readFileSync(common.fixturesDir + '/keys/agent2-cert.pem');
14+
15+
var ntests = 0;
16+
var nsuccess = 0;
17+
18+
function loadDHParam(n) {
19+
var path = common.fixturesDir;
20+
if (n !== 'error') path += '/keys';
21+
return fs.readFileSync(path + '/dh' + n + '.pem');
22+
}
23+
24+
var cipherlist = {
25+
'NOT_PFS': 'AES128-SHA256',
26+
'DH': 'DHE-RSA-AES128-GCM-SHA256',
27+
'ECDH': 'ECDHE-RSA-AES128-GCM-SHA256'
28+
};
29+
30+
function test(size, type, name, next) {
31+
var cipher = type ? cipherlist[type] : cipherlist['NOT_PFS'];
32+
33+
if (name) tls.DEFAULT_ECDH_CURVE = name;
34+
35+
var options = {
36+
key: key,
37+
cert: cert,
38+
ciphers: cipher
39+
};
40+
41+
if (type === 'DH') options.dhparam = loadDHParam(size);
42+
43+
var server = tls.createServer(options, function(conn) {
44+
assert.strictEqual(conn.getEphemeralKeyInfo(), null);
45+
conn.end();
46+
});
47+
48+
server.on('close', function(err) {
49+
assert(!err);
50+
if (next) next();
51+
});
52+
53+
server.listen(common.PORT, '127.0.0.1', function() {
54+
var client = tls.connect({
55+
port: common.PORT,
56+
rejectUnauthorized: false
57+
}, function() {
58+
var ekeyinfo = client.getEphemeralKeyInfo();
59+
assert.strictEqual(ekeyinfo.type, type);
60+
assert.strictEqual(ekeyinfo.size, size);
61+
assert.strictEqual(ekeyinfo.name, name);
62+
nsuccess++;
63+
server.close();
64+
});
65+
});
66+
}
67+
68+
function testNOT_PFS() {
69+
test(undefined, undefined, undefined, testDHE1024);
70+
ntests++;
71+
}
72+
73+
function testDHE1024() {
74+
test(1024, 'DH', undefined, testDHE2048);
75+
ntests++;
76+
}
77+
78+
function testDHE2048() {
79+
test(2048, 'DH', undefined, testECDHE256);
80+
ntests++;
81+
}
82+
83+
function testECDHE256() {
84+
test(256, 'ECDH', tls.DEFAULT_ECDH_CURVE, testECDHE512);
85+
ntests++;
86+
}
87+
88+
function testECDHE512() {
89+
test(521, 'ECDH', 'secp521r1', null);
90+
ntests++;
91+
}
92+
93+
testNOT_PFS();
94+
95+
process.on('exit', function() {
96+
assert.equal(ntests, nsuccess);
97+
assert.equal(ntests, 5);
98+
});

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.