Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDenys Otrishko <shishugi@gmail.com>2018-10-29 11:38:43 +0300
committerRuben Bridgewater <ruben@bridgewater.de>2019-12-25 14:24:42 +0300
commitf8d7e2216e5821719b5a341c41251d5a860cf5f7 (patch)
tree8f3a1db4b065a844483ee1a8e388702463683570 /lib
parent3d47c8592d179991d3bfa4902f12c4fce07ac2d3 (diff)
tls: add PSK support
Add the `pskCallback` client/server option, which resolves an identity or identity hint to a pre-shared key. Add the `pskIdentityHint` server option to set the identity hint for the ServerKeyExchange message. Co-authored-by: Chris Osborn <chris.osborn@sitelier.com> Co-authored-by: stephank <gh@stephank.nl> Co-authored-by: Taylor Zane Glaeser <tzglaeser@gmail.com> PR-URL: https://github.com/nodejs/node/pull/23188 Reviewed-By: Sam Roberts <vieuxtech@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
Diffstat (limited to 'lib')
-rw-r--r--lib/_tls_wrap.js117
1 files changed, 114 insertions, 3 deletions
diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js
index 02a5074b4fe..47a59c02fc5 100644
--- a/lib/_tls_wrap.js
+++ b/lib/_tls_wrap.js
@@ -50,10 +50,12 @@ const { TCP, constants: TCPConstants } = internalBinding('tcp_wrap');
const tls_wrap = internalBinding('tls_wrap');
const { Pipe, constants: PipeConstants } = internalBinding('pipe_wrap');
const { owner_symbol } = require('internal/async_hooks').symbols;
+const { isArrayBufferView } = require('internal/util/types');
const { SecureContext: NativeSecureContext } = internalBinding('crypto');
const { connResetException, codes } = require('internal/errors');
const {
ERR_INVALID_ARG_TYPE,
+ ERR_INVALID_ARG_VALUE,
ERR_INVALID_CALLBACK,
ERR_MULTIPLE_CALLBACK,
ERR_SOCKET_CLOSED,
@@ -65,8 +67,9 @@ const {
ERR_TLS_SESSION_ATTACK,
ERR_TLS_SNI_FROM_SERVER
} = codes;
+const { onpskexchange: kOnPskExchange } = internalBinding('symbols');
const { getOptionValue } = require('internal/options');
-const { validateString } = require('internal/validators');
+const { validateString, validateBuffer } = require('internal/validators');
const traceTls = getOptionValue('--trace-tls');
const tlsKeylog = getOptionValue('--tls-keylog');
const { appendFile } = require('fs');
@@ -77,6 +80,8 @@ const kHandshakeTimeout = Symbol('handshake-timeout');
const kRes = Symbol('res');
const kSNICallback = Symbol('snicallback');
const kEnableTrace = Symbol('enableTrace');
+const kPskCallback = Symbol('pskcallback');
+const kPskIdentityHint = Symbol('pskidentityhint');
const noop = () => {};
@@ -296,6 +301,67 @@ function onnewsession(sessionId, session) {
done();
}
+function onPskServerCallback(identity, maxPskLen) {
+ const owner = this[owner_symbol];
+ const ret = owner[kPskCallback](owner, identity);
+ if (ret == null)
+ return undefined;
+
+ let psk;
+ if (isArrayBufferView(ret)) {
+ psk = ret;
+ } else {
+ if (typeof ret !== 'object') {
+ throw new ERR_INVALID_ARG_TYPE(
+ 'ret',
+ ['Object', 'Buffer', 'TypedArray', 'DataView'],
+ ret
+ );
+ }
+ psk = ret.psk;
+ validateBuffer(psk, 'psk');
+ }
+
+ if (psk.length > maxPskLen) {
+ throw new ERR_INVALID_ARG_VALUE(
+ 'psk',
+ psk,
+ `Pre-shared key exceeds ${maxPskLen} bytes`
+ );
+ }
+
+ return psk;
+}
+
+function onPskClientCallback(hint, maxPskLen, maxIdentityLen) {
+ const owner = this[owner_symbol];
+ const ret = owner[kPskCallback](hint);
+ if (ret == null)
+ return undefined;
+
+ if (typeof ret !== 'object')
+ throw new ERR_INVALID_ARG_TYPE('ret', 'Object', ret);
+
+ validateBuffer(ret.psk, 'psk');
+ if (ret.psk.length > maxPskLen) {
+ throw new ERR_INVALID_ARG_VALUE(
+ 'psk',
+ ret.psk,
+ `Pre-shared key exceeds ${maxPskLen} bytes`
+ );
+ }
+
+ validateString(ret.identity, 'identity');
+ if (Buffer.byteLength(ret.identity) > maxIdentityLen) {
+ throw new ERR_INVALID_ARG_VALUE(
+ 'identity',
+ ret.identity,
+ `PSK identity exceeds ${maxIdentityLen} bytes`
+ );
+ }
+
+ return { psk: ret.psk, identity: ret.identity };
+}
function onkeylogclient(line) {
debug('client onkeylog');
@@ -694,6 +760,32 @@ TLSSocket.prototype._init = function(socket, wrap) {
ssl.setALPNProtocols(ssl._secureContext.alpnBuffer);
}
+ if (options.pskCallback && ssl.enablePskCallback) {
+ if (typeof options.pskCallback !== 'function') {
+ throw new ERR_INVALID_ARG_TYPE('pskCallback',
+ 'function',
+ options.pskCallback);
+ }
+
+ ssl[kOnPskExchange] = options.isServer ?
+ onPskServerCallback : onPskClientCallback;
+
+ this[kPskCallback] = options.pskCallback;
+ ssl.enablePskCallback();
+
+ if (options.pskIdentityHint) {
+ if (typeof options.pskIdentityHint !== 'string') {
+ throw new ERR_INVALID_ARG_TYPE(
+ 'options.pskIdentityHint',
+ 'string',
+ options.pskIdentityHint
+ );
+ }
+ ssl.setPskIdentityHint(options.pskIdentityHint);
+ }
+ }
+
+
if (options.handshakeTimeout > 0)
this.setTimeout(options.handshakeTimeout, this._handleTimeout);
@@ -905,7 +997,7 @@ function makeSocketMethodProxy(name) {
TLSSocket.prototype[method] = makeSocketMethodProxy(method);
});
-// TODO: support anonymous (nocert) and PSK
+// TODO: support anonymous (nocert)
function onServerSocketSecure() {
@@ -961,6 +1053,8 @@ function tlsConnectionListener(rawSocket) {
SNICallback: this[kSNICallback] || SNICallback,
enableTrace: this[kEnableTrace],
pauseOnConnect: this.pauseOnConnect,
+ pskCallback: this[kPskCallback],
+ pskIdentityHint: this[kPskIdentityHint],
});
socket.on('secure', onServerSocketSecure);
@@ -1065,6 +1159,8 @@ function Server(options, listener) {
this[kHandshakeTimeout] = options.handshakeTimeout || (120 * 1000);
this[kSNICallback] = options.SNICallback;
+ this[kPskCallback] = options.pskCallback;
+ this[kPskIdentityHint] = options.pskIdentityHint;
if (typeof this[kHandshakeTimeout] !== 'number') {
throw new ERR_INVALID_ARG_TYPE(
@@ -1076,6 +1172,18 @@ function Server(options, listener) {
'options.SNICallback', 'function', options.SNICallback);
}
+ if (this[kPskCallback] && typeof this[kPskCallback] !== 'function') {
+ throw new ERR_INVALID_ARG_TYPE(
+ 'options.pskCallback', 'function', options.pskCallback);
+ }
+ if (this[kPskIdentityHint] && typeof this[kPskIdentityHint] !== 'string') {
+ throw new ERR_INVALID_ARG_TYPE(
+ 'options.pskIdentityHint',
+ 'string',
+ options.pskIdentityHint
+ );
+ }
+
// constructor call
net.Server.call(this, options, tlsConnectionListener);
@@ -1272,6 +1380,8 @@ Server.prototype.setOptions = deprecate(function(options) {
.digest('hex')
.slice(0, 32);
}
+ if (options.pskCallback) this[kPskCallback] = options.pskCallback;
+ if (options.pskIdentityHint) this[kPskIdentityHint] = options.pskIdentityHint;
}, 'Server.prototype.setOptions() is deprecated', 'DEP0122');
// SNI Contexts High-Level API
@@ -1459,7 +1569,8 @@ exports.connect = function connect(...args) {
session: options.session,
ALPNProtocols: options.ALPNProtocols,
requestOCSP: options.requestOCSP,
- enableTrace: options.enableTrace
+ enableTrace: options.enableTrace,
+ pskCallback: options.pskCallback,
});
tlssock[kConnectOptions] = options;