@@ -43,10 +43,12 @@ const { TCP, constants: TCPConstants } = internalBinding('tcp_wrap');
4343const tls_wrap = internalBinding('tls_wrap');
4444const { Pipe, constants: PipeConstants } = internalBinding('pipe_wrap');
4545const { owner_symbol } = require('internal/async_hooks').symbols;
46+ const { isArrayBufferView } = require('internal/util/types');
4647const { SecureContext: NativeSecureContext } = internalBinding('crypto');
4748const { connResetException, codes } = require('internal/errors');
4849const {
4950 ERR_INVALID_ARG_TYPE,
51+ ERR_INVALID_ARG_VALUE,
5052 ERR_INVALID_CALLBACK,
5153 ERR_MULTIPLE_CALLBACK,
5254 ERR_SOCKET_CLOSED,
@@ -58,8 +60,9 @@ const {
5860 ERR_TLS_SESSION_ATTACK,
5961 ERR_TLS_SNI_FROM_SERVER
6062} = codes;
63+ const { onpskexchange: kOnPskExchange } = internalBinding('symbols');
6164const { getOptionValue } = require('internal/options');
62- const { validateString } = require('internal/validators');
65+ const { validateString, validateBuffer } = require('internal/validators');
6366const traceTls = getOptionValue('--trace-tls');
6467const tlsKeylog = getOptionValue('--tls-keylog');
6568const { appendFile } = require('fs');
@@ -70,6 +73,8 @@ const kHandshakeTimeout = Symbol('handshake-timeout');
7073const kRes = Symbol('res');
7174const kSNICallback = Symbol('snicallback');
7275const kEnableTrace = Symbol('enableTrace');
76+ const kPskCallback = Symbol('pskcallback');
77+ const kPskIdentityHint = Symbol('pskidentityhint');
7378
7479const noop = () => {};
7580
@@ -289,6 +294,67 @@ function onnewsession(sessionId, session) {
289294 done();
290295}
291296
297+ function onPskServerCallback(identity, maxPskLen) {
298+ const owner = this[owner_symbol];
299+ const ret = owner[kPskCallback](owner, identity);
300+ if (ret == null)
301+ return undefined;
302+
303+ let psk;
304+ if (isArrayBufferView(ret)) {
305+ psk = ret;
306+ } else {
307+ if (typeof ret !== 'object') {
308+ throw new ERR_INVALID_ARG_TYPE(
309+ 'ret',
310+ ['Object', 'Buffer', 'TypedArray', 'DataView'],
311+ ret
312+ );
313+ }
314+ psk = ret.psk;
315+ validateBuffer(psk, 'psk');
316+ }
317+
318+ if (psk.length > maxPskLen) {
319+ throw new ERR_INVALID_ARG_VALUE(
320+ 'psk',
321+ psk,
322+ `Pre-shared key exceeds ${maxPskLen} bytes`
323+ );
324+ }
325+
326+ return psk;
327+ }
328+
329+ function onPskClientCallback(hint, maxPskLen, maxIdentityLen) {
330+ const owner = this[owner_symbol];
331+ const ret = owner[kPskCallback](hint);
332+ if (ret == null)
333+ return undefined;
334+
335+ if (typeof ret !== 'object')
336+ throw new ERR_INVALID_ARG_TYPE('ret', 'Object', ret);
337+
338+ validateBuffer(ret.psk, 'psk');
339+ if (ret.psk.length > maxPskLen) {
340+ throw new ERR_INVALID_ARG_VALUE(
341+ 'psk',
342+ ret.psk,
343+ `Pre-shared key exceeds ${maxPskLen} bytes`
344+ );
345+ }
346+
347+ validateString(ret.identity, 'identity');
348+ if (Buffer.byteLength(ret.identity) > maxIdentityLen) {
349+ throw new ERR_INVALID_ARG_VALUE(
350+ 'identity',
351+ ret.identity,
352+ `PSK identity exceeds ${maxIdentityLen} bytes`
353+ );
354+ }
355+
356+ return { psk: ret.psk, identity: ret.identity };
357+ }
292358
293359function onkeylogclient(line) {
294360 debug('client onkeylog');
@@ -687,6 +753,32 @@ TLSSocket.prototype._init = function(socket, wrap) {
687753 ssl.setALPNProtocols(ssl._secureContext.alpnBuffer);
688754 }
689755
756+ if (options.pskCallback && ssl.enablePskCallback) {
757+ if (typeof options.pskCallback !== 'function') {
758+ throw new ERR_INVALID_ARG_TYPE('pskCallback',
759+ 'function',
760+ options.pskCallback);
761+ }
762+
763+ ssl[kOnPskExchange] = options.isServer ?
764+ onPskServerCallback : onPskClientCallback;
765+
766+ this[kPskCallback] = options.pskCallback;
767+ ssl.enablePskCallback();
768+
769+ if (options.pskIdentityHint) {
770+ if (typeof options.pskIdentityHint !== 'string') {
771+ throw new ERR_INVALID_ARG_TYPE(
772+ 'options.pskIdentityHint',
773+ 'string',
774+ options.pskIdentityHint
775+ );
776+ }
777+ ssl.setPskIdentityHint(options.pskIdentityHint);
778+ }
779+ }
780+
781+
690782 if (options.handshakeTimeout > 0)
691783 this.setTimeout(options.handshakeTimeout, this._handleTimeout);
692784
@@ -898,7 +990,7 @@ function makeSocketMethodProxy(name) {
898990 TLSSocket.prototype[method] = makeSocketMethodProxy(method);
899991});
900992
901- // TODO: support anonymous (nocert) and PSK
993+ // TODO: support anonymous (nocert)
902994
903995
904996function onServerSocketSecure() {
@@ -954,6 +1046,8 @@ function tlsConnectionListener(rawSocket) {
9541046 SNICallback: this[kSNICallback] || SNICallback,
9551047 enableTrace: this[kEnableTrace],
9561048 pauseOnConnect: this.pauseOnConnect,
1049+ pskCallback: this[kPskCallback],
1050+ pskIdentityHint: this[kPskIdentityHint],
9571051 });
9581052
9591053 socket.on('secure', onServerSocketSecure);
@@ -1058,6 +1152,8 @@ function Server(options, listener) {
10581152
10591153 this[kHandshakeTimeout] = options.handshakeTimeout || (120 * 1000);
10601154 this[kSNICallback] = options.SNICallback;
1155+ this[kPskCallback] = options.pskCallback;
1156+ this[kPskIdentityHint] = options.pskIdentityHint;
10611157
10621158 if (typeof this[kHandshakeTimeout] !== 'number') {
10631159 throw new ERR_INVALID_ARG_TYPE(
@@ -1069,6 +1165,18 @@ function Server(options, listener) {
10691165 'options.SNICallback', 'function', options.SNICallback);
10701166 }
10711167
1168+ if (this[kPskCallback] && typeof this[kPskCallback] !== 'function') {
1169+ throw new ERR_INVALID_ARG_TYPE(
1170+ 'options.pskCallback', 'function', options.pskCallback);
1171+ }
1172+ if (this[kPskIdentityHint] && typeof this[kPskIdentityHint] !== 'string') {
1173+ throw new ERR_INVALID_ARG_TYPE(
1174+ 'options.pskIdentityHint',
1175+ 'string',
1176+ options.pskIdentityHint
1177+ );
1178+ }
1179+
10721180 // constructor call
10731181 net.Server.call(this, options, tlsConnectionListener);
10741182
@@ -1265,6 +1373,8 @@ Server.prototype.setOptions = deprecate(function(options) {
12651373 .digest('hex')
12661374 .slice(0, 32);
12671375 }
1376+ if (options.pskCallback) this[kPskCallback] = options.pskCallback;
1377+ if (options.pskIdentityHint) this[kPskIdentityHint] = options.pskIdentityHint;
12681378}, 'Server.prototype.setOptions() is deprecated', 'DEP0122');
12691379
12701380// SNI Contexts High-Level API
@@ -1440,7 +1550,8 @@ exports.connect = function connect(...args) {
14401550 session: options.session,
14411551 ALPNProtocols: options.ALPNProtocols,
14421552 requestOCSP: options.requestOCSP,
1443- enableTrace: options.enableTrace
1553+ enableTrace: options.enableTrace,
1554+ pskCallback: options.pskCallback,
14441555 });
14451556
14461557 tlssock[kConnectOptions] = options;
0 commit comments