@@ -50,10 +50,12 @@ const { TCP, constants: TCPConstants } = internalBinding('tcp_wrap');
5050const tls_wrap = internalBinding ( 'tls_wrap' ) ;
5151const { Pipe, constants : PipeConstants } = internalBinding ( 'pipe_wrap' ) ;
5252const { owner_symbol } = require ( 'internal/async_hooks' ) . symbols ;
53+ const { isArrayBufferView } = require ( 'internal/util/types' ) ;
5354const { SecureContext : NativeSecureContext } = internalBinding ( 'crypto' ) ;
5455const { connResetException, codes } = require ( 'internal/errors' ) ;
5556const {
5657 ERR_INVALID_ARG_TYPE ,
58+ ERR_INVALID_ARG_VALUE ,
5759 ERR_INVALID_CALLBACK ,
5860 ERR_MULTIPLE_CALLBACK ,
5961 ERR_SOCKET_CLOSED ,
@@ -65,8 +67,9 @@ const {
6567 ERR_TLS_SESSION_ATTACK ,
6668 ERR_TLS_SNI_FROM_SERVER
6769} = codes ;
70+ const { onpskexchange : kOnPskExchange } = internalBinding ( 'symbols' ) ;
6871const { getOptionValue } = require ( 'internal/options' ) ;
69- const { validateString } = require ( 'internal/validators' ) ;
72+ const { validateString, validateBuffer } = require ( 'internal/validators' ) ;
7073const traceTls = getOptionValue ( '--trace-tls' ) ;
7174const tlsKeylog = getOptionValue ( '--tls-keylog' ) ;
7275const { appendFile } = require ( 'fs' ) ;
@@ -77,6 +80,8 @@ const kHandshakeTimeout = Symbol('handshake-timeout');
7780const kRes = Symbol ( 'res' ) ;
7881const kSNICallback = Symbol ( 'snicallback' ) ;
7982const kEnableTrace = Symbol ( 'enableTrace' ) ;
83+ const kPskCallback = Symbol ( 'pskcallback' ) ;
84+ const kPskIdentityHint = Symbol ( 'pskidentityhint' ) ;
8085
8186const noop = ( ) => { } ;
8287
@@ -296,6 +301,67 @@ function onnewsession(sessionId, session) {
296301 done ( ) ;
297302}
298303
304+ function onPskServerCallback ( identity , maxPskLen ) {
305+ const owner = this [ owner_symbol ] ;
306+ const ret = owner [ kPskCallback ] ( owner , identity ) ;
307+ if ( ret == null )
308+ return undefined ;
309+
310+ let psk ;
311+ if ( isArrayBufferView ( ret ) ) {
312+ psk = ret ;
313+ } else {
314+ if ( typeof ret !== 'object' ) {
315+ throw new ERR_INVALID_ARG_TYPE (
316+ 'ret' ,
317+ [ 'Object' , 'Buffer' , 'TypedArray' , 'DataView' ] ,
318+ ret
319+ ) ;
320+ }
321+ psk = ret . psk ;
322+ validateBuffer ( psk , 'psk' ) ;
323+ }
324+
325+ if ( psk . length > maxPskLen ) {
326+ throw new ERR_INVALID_ARG_VALUE (
327+ 'psk' ,
328+ psk ,
329+ `Pre-shared key exceeds ${ maxPskLen } bytes`
330+ ) ;
331+ }
332+
333+ return psk ;
334+ }
335+
336+ function onPskClientCallback ( hint , maxPskLen , maxIdentityLen ) {
337+ const owner = this [ owner_symbol ] ;
338+ const ret = owner [ kPskCallback ] ( hint ) ;
339+ if ( ret == null )
340+ return undefined ;
341+
342+ if ( typeof ret !== 'object' )
343+ throw new ERR_INVALID_ARG_TYPE ( 'ret' , 'Object' , ret ) ;
344+
345+ validateBuffer ( ret . psk , 'psk' ) ;
346+ if ( ret . psk . length > maxPskLen ) {
347+ throw new ERR_INVALID_ARG_VALUE (
348+ 'psk' ,
349+ ret . psk ,
350+ `Pre-shared key exceeds ${ maxPskLen } bytes`
351+ ) ;
352+ }
353+
354+ validateString ( ret . identity , 'identity' ) ;
355+ if ( Buffer . byteLength ( ret . identity ) > maxIdentityLen ) {
356+ throw new ERR_INVALID_ARG_VALUE (
357+ 'identity' ,
358+ ret . identity ,
359+ `PSK identity exceeds ${ maxIdentityLen } bytes`
360+ ) ;
361+ }
362+
363+ return { psk : ret . psk , identity : ret . identity } ;
364+ }
299365
300366function onkeylogclient ( line ) {
301367 debug ( 'client onkeylog' ) ;
@@ -694,6 +760,32 @@ TLSSocket.prototype._init = function(socket, wrap) {
694760 ssl . setALPNProtocols ( ssl . _secureContext . alpnBuffer ) ;
695761 }
696762
763+ if ( options . pskCallback && ssl . enablePskCallback ) {
764+ if ( typeof options . pskCallback !== 'function' ) {
765+ throw new ERR_INVALID_ARG_TYPE ( 'pskCallback' ,
766+ 'function' ,
767+ options . pskCallback ) ;
768+ }
769+
770+ ssl [ kOnPskExchange ] = options . isServer ?
771+ onPskServerCallback : onPskClientCallback ;
772+
773+ this [ kPskCallback ] = options . pskCallback ;
774+ ssl . enablePskCallback ( ) ;
775+
776+ if ( options . pskIdentityHint ) {
777+ if ( typeof options . pskIdentityHint !== 'string' ) {
778+ throw new ERR_INVALID_ARG_TYPE (
779+ 'options.pskIdentityHint' ,
780+ 'string' ,
781+ options . pskIdentityHint
782+ ) ;
783+ }
784+ ssl . setPskIdentityHint ( options . pskIdentityHint ) ;
785+ }
786+ }
787+
788+
697789 if ( options . handshakeTimeout > 0 )
698790 this . setTimeout ( options . handshakeTimeout , this . _handleTimeout ) ;
699791
@@ -905,7 +997,7 @@ function makeSocketMethodProxy(name) {
905997 TLSSocket . prototype [ method ] = makeSocketMethodProxy ( method ) ;
906998} ) ;
907999
908- // TODO: support anonymous (nocert) and PSK
1000+ // TODO: support anonymous (nocert)
9091001
9101002
9111003function onServerSocketSecure ( ) {
@@ -961,6 +1053,8 @@ function tlsConnectionListener(rawSocket) {
9611053 SNICallback : this [ kSNICallback ] || SNICallback ,
9621054 enableTrace : this [ kEnableTrace ] ,
9631055 pauseOnConnect : this . pauseOnConnect ,
1056+ pskCallback : this [ kPskCallback ] ,
1057+ pskIdentityHint : this [ kPskIdentityHint ] ,
9641058 } ) ;
9651059
9661060 socket . on ( 'secure' , onServerSocketSecure ) ;
@@ -1065,6 +1159,8 @@ function Server(options, listener) {
10651159
10661160 this [ kHandshakeTimeout ] = options . handshakeTimeout || ( 120 * 1000 ) ;
10671161 this [ kSNICallback ] = options . SNICallback ;
1162+ this [ kPskCallback ] = options . pskCallback ;
1163+ this [ kPskIdentityHint ] = options . pskIdentityHint ;
10681164
10691165 if ( typeof this [ kHandshakeTimeout ] !== 'number' ) {
10701166 throw new ERR_INVALID_ARG_TYPE (
@@ -1076,6 +1172,18 @@ function Server(options, listener) {
10761172 'options.SNICallback' , 'function' , options . SNICallback ) ;
10771173 }
10781174
1175+ if ( this [ kPskCallback ] && typeof this [ kPskCallback ] !== 'function' ) {
1176+ throw new ERR_INVALID_ARG_TYPE (
1177+ 'options.pskCallback' , 'function' , options . pskCallback ) ;
1178+ }
1179+ if ( this [ kPskIdentityHint ] && typeof this [ kPskIdentityHint ] !== 'string' ) {
1180+ throw new ERR_INVALID_ARG_TYPE (
1181+ 'options.pskIdentityHint' ,
1182+ 'string' ,
1183+ options . pskIdentityHint
1184+ ) ;
1185+ }
1186+
10791187 // constructor call
10801188 net . Server . call ( this , options , tlsConnectionListener ) ;
10811189
@@ -1272,6 +1380,8 @@ Server.prototype.setOptions = deprecate(function(options) {
12721380 . digest ( 'hex' )
12731381 . slice ( 0 , 32 ) ;
12741382 }
1383+ if ( options . pskCallback ) this [ kPskCallback ] = options . pskCallback ;
1384+ if ( options . pskIdentityHint ) this [ kPskIdentityHint ] = options . pskIdentityHint ;
12751385} , 'Server.prototype.setOptions() is deprecated' , 'DEP0122' ) ;
12761386
12771387// SNI Contexts High-Level API
@@ -1459,7 +1569,8 @@ exports.connect = function connect(...args) {
14591569 session : options . session ,
14601570 ALPNProtocols : options . ALPNProtocols ,
14611571 requestOCSP : options . requestOCSP ,
1462- enableTrace : options . enableTrace
1572+ enableTrace : options . enableTrace ,
1573+ pskCallback : options . pskCallback ,
14631574 } ) ;
14641575
14651576 tlssock [ kConnectOptions ] = options ;
0 commit comments