@@ -50,10 +50,12 @@ const { TCP, constants: TCPConstants } = internalBinding('tcp_wrap');
50
50
const tls_wrap = internalBinding ( 'tls_wrap' ) ;
51
51
const { Pipe, constants : PipeConstants } = internalBinding ( 'pipe_wrap' ) ;
52
52
const { owner_symbol } = require ( 'internal/async_hooks' ) . symbols ;
53
+ const { isArrayBufferView } = require ( 'internal/util/types' ) ;
53
54
const { SecureContext : NativeSecureContext } = internalBinding ( 'crypto' ) ;
54
55
const { connResetException, codes } = require ( 'internal/errors' ) ;
55
56
const {
56
57
ERR_INVALID_ARG_TYPE ,
58
+ ERR_INVALID_ARG_VALUE ,
57
59
ERR_INVALID_CALLBACK ,
58
60
ERR_MULTIPLE_CALLBACK ,
59
61
ERR_SOCKET_CLOSED ,
@@ -65,8 +67,9 @@ const {
65
67
ERR_TLS_SESSION_ATTACK ,
66
68
ERR_TLS_SNI_FROM_SERVER
67
69
} = codes ;
70
+ const { onpskexchange : kOnPskExchange } = internalBinding ( 'symbols' ) ;
68
71
const { getOptionValue } = require ( 'internal/options' ) ;
69
- const { validateString } = require ( 'internal/validators' ) ;
72
+ const { validateString, validateBuffer } = require ( 'internal/validators' ) ;
70
73
const traceTls = getOptionValue ( '--trace-tls' ) ;
71
74
const tlsKeylog = getOptionValue ( '--tls-keylog' ) ;
72
75
const { appendFile } = require ( 'fs' ) ;
@@ -77,6 +80,8 @@ const kHandshakeTimeout = Symbol('handshake-timeout');
77
80
const kRes = Symbol ( 'res' ) ;
78
81
const kSNICallback = Symbol ( 'snicallback' ) ;
79
82
const kEnableTrace = Symbol ( 'enableTrace' ) ;
83
+ const kPskCallback = Symbol ( 'pskcallback' ) ;
84
+ const kPskIdentityHint = Symbol ( 'pskidentityhint' ) ;
80
85
81
86
const noop = ( ) => { } ;
82
87
@@ -296,6 +301,67 @@ function onnewsession(sessionId, session) {
296
301
done ( ) ;
297
302
}
298
303
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
+ }
299
365
300
366
function onkeylogclient ( line ) {
301
367
debug ( 'client onkeylog' ) ;
@@ -694,6 +760,32 @@ TLSSocket.prototype._init = function(socket, wrap) {
694
760
ssl . setALPNProtocols ( ssl . _secureContext . alpnBuffer ) ;
695
761
}
696
762
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
+
697
789
if ( options . handshakeTimeout > 0 )
698
790
this . setTimeout ( options . handshakeTimeout , this . _handleTimeout ) ;
699
791
@@ -905,7 +997,7 @@ function makeSocketMethodProxy(name) {
905
997
TLSSocket . prototype [ method ] = makeSocketMethodProxy ( method ) ;
906
998
} ) ;
907
999
908
- // TODO: support anonymous (nocert) and PSK
1000
+ // TODO: support anonymous (nocert)
909
1001
910
1002
911
1003
function onServerSocketSecure ( ) {
@@ -961,6 +1053,8 @@ function tlsConnectionListener(rawSocket) {
961
1053
SNICallback : this [ kSNICallback ] || SNICallback ,
962
1054
enableTrace : this [ kEnableTrace ] ,
963
1055
pauseOnConnect : this . pauseOnConnect ,
1056
+ pskCallback : this [ kPskCallback ] ,
1057
+ pskIdentityHint : this [ kPskIdentityHint ] ,
964
1058
} ) ;
965
1059
966
1060
socket . on ( 'secure' , onServerSocketSecure ) ;
@@ -1065,6 +1159,8 @@ function Server(options, listener) {
1065
1159
1066
1160
this [ kHandshakeTimeout ] = options . handshakeTimeout || ( 120 * 1000 ) ;
1067
1161
this [ kSNICallback ] = options . SNICallback ;
1162
+ this [ kPskCallback ] = options . pskCallback ;
1163
+ this [ kPskIdentityHint ] = options . pskIdentityHint ;
1068
1164
1069
1165
if ( typeof this [ kHandshakeTimeout ] !== 'number' ) {
1070
1166
throw new ERR_INVALID_ARG_TYPE (
@@ -1076,6 +1172,18 @@ function Server(options, listener) {
1076
1172
'options.SNICallback' , 'function' , options . SNICallback ) ;
1077
1173
}
1078
1174
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
+
1079
1187
// constructor call
1080
1188
net . Server . call ( this , options , tlsConnectionListener ) ;
1081
1189
@@ -1272,6 +1380,8 @@ Server.prototype.setOptions = deprecate(function(options) {
1272
1380
. digest ( 'hex' )
1273
1381
. slice ( 0 , 32 ) ;
1274
1382
}
1383
+ if ( options . pskCallback ) this [ kPskCallback ] = options . pskCallback ;
1384
+ if ( options . pskIdentityHint ) this [ kPskIdentityHint ] = options . pskIdentityHint ;
1275
1385
} , 'Server.prototype.setOptions() is deprecated' , 'DEP0122' ) ;
1276
1386
1277
1387
// SNI Contexts High-Level API
@@ -1459,7 +1569,8 @@ exports.connect = function connect(...args) {
1459
1569
session : options . session ,
1460
1570
ALPNProtocols : options . ALPNProtocols ,
1461
1571
requestOCSP : options . requestOCSP ,
1462
- enableTrace : options . enableTrace
1572
+ enableTrace : options . enableTrace ,
1573
+ pskCallback : options . pskCallback ,
1463
1574
} ) ;
1464
1575
1465
1576
tlssock [ kConnectOptions ] = options ;
0 commit comments