@@ -43,10 +43,12 @@ const { TCP, constants: TCPConstants } = internalBinding('tcp_wrap');
43
43
const tls_wrap = internalBinding ( 'tls_wrap' ) ;
44
44
const { Pipe, constants : PipeConstants } = internalBinding ( 'pipe_wrap' ) ;
45
45
const { owner_symbol } = require ( 'internal/async_hooks' ) . symbols ;
46
+ const { isArrayBufferView } = require ( 'internal/util/types' ) ;
46
47
const { SecureContext : NativeSecureContext } = internalBinding ( 'crypto' ) ;
47
48
const { connResetException, codes } = require ( 'internal/errors' ) ;
48
49
const {
49
50
ERR_INVALID_ARG_TYPE ,
51
+ ERR_INVALID_ARG_VALUE ,
50
52
ERR_INVALID_CALLBACK ,
51
53
ERR_MULTIPLE_CALLBACK ,
52
54
ERR_SOCKET_CLOSED ,
@@ -58,8 +60,9 @@ const {
58
60
ERR_TLS_SESSION_ATTACK ,
59
61
ERR_TLS_SNI_FROM_SERVER
60
62
} = codes ;
63
+ const { onpskexchange : kOnPskExchange } = internalBinding ( 'symbols' ) ;
61
64
const { getOptionValue } = require ( 'internal/options' ) ;
62
- const { validateString } = require ( 'internal/validators' ) ;
65
+ const { validateString, validateBuffer } = require ( 'internal/validators' ) ;
63
66
const traceTls = getOptionValue ( '--trace-tls' ) ;
64
67
const tlsKeylog = getOptionValue ( '--tls-keylog' ) ;
65
68
const { appendFile } = require ( 'fs' ) ;
@@ -70,6 +73,8 @@ const kHandshakeTimeout = Symbol('handshake-timeout');
70
73
const kRes = Symbol ( 'res' ) ;
71
74
const kSNICallback = Symbol ( 'snicallback' ) ;
72
75
const kEnableTrace = Symbol ( 'enableTrace' ) ;
76
+ const kPskCallback = Symbol ( 'pskcallback' ) ;
77
+ const kPskIdentityHint = Symbol ( 'pskidentityhint' ) ;
73
78
74
79
const noop = ( ) => { } ;
75
80
@@ -289,6 +294,67 @@ function onnewsession(sessionId, session) {
289
294
done ( ) ;
290
295
}
291
296
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
+ }
292
358
293
359
function onkeylogclient ( line ) {
294
360
debug ( 'client onkeylog' ) ;
@@ -687,6 +753,32 @@ TLSSocket.prototype._init = function(socket, wrap) {
687
753
ssl . setALPNProtocols ( ssl . _secureContext . alpnBuffer ) ;
688
754
}
689
755
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
+
690
782
if ( options . handshakeTimeout > 0 )
691
783
this . setTimeout ( options . handshakeTimeout , this . _handleTimeout ) ;
692
784
@@ -898,7 +990,7 @@ function makeSocketMethodProxy(name) {
898
990
TLSSocket . prototype [ method ] = makeSocketMethodProxy ( method ) ;
899
991
} ) ;
900
992
901
- // TODO: support anonymous (nocert) and PSK
993
+ // TODO: support anonymous (nocert)
902
994
903
995
904
996
function onServerSocketSecure ( ) {
@@ -954,6 +1046,8 @@ function tlsConnectionListener(rawSocket) {
954
1046
SNICallback : this [ kSNICallback ] || SNICallback ,
955
1047
enableTrace : this [ kEnableTrace ] ,
956
1048
pauseOnConnect : this . pauseOnConnect ,
1049
+ pskCallback : this [ kPskCallback ] ,
1050
+ pskIdentityHint : this [ kPskIdentityHint ] ,
957
1051
} ) ;
958
1052
959
1053
socket . on ( 'secure' , onServerSocketSecure ) ;
@@ -1058,6 +1152,8 @@ function Server(options, listener) {
1058
1152
1059
1153
this [ kHandshakeTimeout ] = options . handshakeTimeout || ( 120 * 1000 ) ;
1060
1154
this [ kSNICallback ] = options . SNICallback ;
1155
+ this [ kPskCallback ] = options . pskCallback ;
1156
+ this [ kPskIdentityHint ] = options . pskIdentityHint ;
1061
1157
1062
1158
if ( typeof this [ kHandshakeTimeout ] !== 'number' ) {
1063
1159
throw new ERR_INVALID_ARG_TYPE (
@@ -1069,6 +1165,18 @@ function Server(options, listener) {
1069
1165
'options.SNICallback' , 'function' , options . SNICallback ) ;
1070
1166
}
1071
1167
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
+
1072
1180
// constructor call
1073
1181
net . Server . call ( this , options , tlsConnectionListener ) ;
1074
1182
@@ -1265,6 +1373,8 @@ Server.prototype.setOptions = deprecate(function(options) {
1265
1373
. digest ( 'hex' )
1266
1374
. slice ( 0 , 32 ) ;
1267
1375
}
1376
+ if ( options . pskCallback ) this [ kPskCallback ] = options . pskCallback ;
1377
+ if ( options . pskIdentityHint ) this [ kPskIdentityHint ] = options . pskIdentityHint ;
1268
1378
} , 'Server.prototype.setOptions() is deprecated' , 'DEP0122' ) ;
1269
1379
1270
1380
// SNI Contexts High-Level API
@@ -1440,7 +1550,8 @@ exports.connect = function connect(...args) {
1440
1550
session : options . session ,
1441
1551
ALPNProtocols : options . ALPNProtocols ,
1442
1552
requestOCSP : options . requestOCSP ,
1443
- enableTrace : options . enableTrace
1553
+ enableTrace : options . enableTrace ,
1554
+ pskCallback : options . pskCallback ,
1444
1555
} ) ;
1445
1556
1446
1557
tlssock [ kConnectOptions ] = options ;
0 commit comments