@@ -114,6 +114,82 @@ const kIsVerified = Symbol('verified');
114114
115115const noop = ( ) => { } ;
116116
117+ const kTLSSessionStatePrefix = Buffer . from ( '\0nodejs:tls:session:1\0' ) ;
118+
119+ function getSessionServerIdentity ( options ) {
120+ return options ?. servername ||
121+ options ?. host ||
122+ options ?. socket ?. _host ||
123+ 'localhost' ;
124+ }
125+
126+ function wrapSessionState ( session , options ) {
127+ if ( ! Buffer . isBuffer ( session ) || options ?. isServer )
128+ return session ;
129+
130+ const servername = Buffer . from ( getSessionServerIdentity ( options ) , 'utf8' ) ;
131+ const servernameLength = Buffer . allocUnsafe ( 2 ) ;
132+ servernameLength . writeUInt16BE ( servername . length , 0 ) ;
133+
134+ return Buffer . concat ( [
135+ kTLSSessionStatePrefix ,
136+ servernameLength ,
137+ servername ,
138+ session ,
139+ ] ) ;
140+ }
141+
142+ function unwrapSessionState ( session ) {
143+ if ( ! Buffer . isBuffer ( session ) ||
144+ session . length < kTLSSessionStatePrefix . length + 2 ||
145+ Buffer . compare (
146+ session . subarray ( 0 , kTLSSessionStatePrefix . length ) ,
147+ kTLSSessionStatePrefix ,
148+ ) !== 0 ) {
149+ return ;
150+ }
151+
152+ const start = kTLSSessionStatePrefix . length ;
153+ const servernameLength = session . readUInt16BE ( start ) ;
154+ const servernameStart = start + 2 ;
155+ const servernameEnd = servernameStart + servernameLength ;
156+ if ( session . length < servernameEnd )
157+ return ;
158+
159+ return {
160+ servername : session . toString ( 'utf8' , servernameStart , servernameEnd ) ,
161+ session : session . subarray ( servernameEnd ) ,
162+ } ;
163+ }
164+
165+ function getSessionForReuse ( session , options ) {
166+ if ( typeof session === 'string' )
167+ session = Buffer . from ( session , 'latin1' ) ;
168+
169+ if ( options ?. isServer )
170+ return session ;
171+
172+ const wrappedSession = unwrapSessionState ( session ) ;
173+ if ( wrappedSession !== undefined ) {
174+ const servername = getSessionServerIdentity ( options ) ;
175+ if ( wrappedSession . servername !== servername ) {
176+ debug ( 'ignore session for %s: authenticated for %s' ,
177+ servername , wrappedSession . servername ) ;
178+ return ;
179+ }
180+
181+ return wrappedSession . session ;
182+ }
183+
184+ if ( Buffer . isBuffer ( session ) && options ?. rejectUnauthorized !== false ) {
185+ debug ( 'ignore raw session for verified client connection to %s' ,
186+ getSessionServerIdentity ( options ) ) ;
187+ return ;
188+ }
189+
190+ return session ;
191+ }
192+
117193let tlsTracingWarned = false ;
118194
119195// Server side times how long a handshake is taking to protect against slow
@@ -341,10 +417,11 @@ function requestOCSPDone(socket) {
341417function onnewsessionclient ( sessionId , session ) {
342418 debug ( 'client emit session' ) ;
343419 const owner = this [ owner_symbol ] ;
420+ const wrappedSession = wrapSessionState ( session , owner [ kConnectOptions ] ) ;
344421 if ( owner [ kIsVerified ] ) {
345- owner . emit ( 'session' , session ) ;
422+ owner . emit ( 'session' , wrappedSession ) ;
346423 } else {
347- owner [ kPendingSession ] = session ;
424+ owner [ kPendingSession ] = wrappedSession ;
348425 }
349426}
350427
@@ -1139,9 +1216,19 @@ TLSSocket.prototype.setServername = function(name) {
11391216} ;
11401217
11411218TLSSocket . prototype . setSession = function ( session ) {
1142- if ( typeof session === 'string' )
1143- session = Buffer . from ( session , 'latin1' ) ;
1144- this . _handle . setSession ( session ) ;
1219+ session = getSessionForReuse ( session , this [ kConnectOptions ] || this . _tlsOptions ) ;
1220+ if ( session !== undefined )
1221+ this . _handle . setSession ( session ) ;
1222+ } ;
1223+
1224+ TLSSocket . prototype . getSession = function ( ) {
1225+ if ( ! this . _handle )
1226+ return null ;
1227+
1228+ return wrapSessionState (
1229+ this . _handle . getSession ( ) ,
1230+ this [ kConnectOptions ] || this . _tlsOptions ,
1231+ ) ;
11451232} ;
11461233
11471234TLSSocket . prototype . getPeerCertificate = function ( detailed ) {
@@ -1200,7 +1287,6 @@ function makeSocketMethodProxy(name) {
12001287 'getFinished' ,
12011288 'getPeerFinished' ,
12021289 'getProtocol' ,
1203- 'getSession' ,
12041290 'getTLSTicket' ,
12051291 'isSessionReused' ,
12061292 'enableTrace' ,
@@ -1663,12 +1749,11 @@ function onConnectSecure() {
16631749 // Verify that server's identity matches it's certificate's names
16641750 // Unless server has resumed our existing session
16651751 if ( ! verifyError && ! this . isSessionReused ( ) ) {
1666- const hostname = options . servername ||
1667- options . host ||
1668- ( options . socket ?. _host ) ||
1669- 'localhost' ;
16701752 const cert = this . getPeerCertificate ( true ) ;
1671- verifyError = options . checkServerIdentity ( hostname , cert ) ;
1753+ verifyError = options . checkServerIdentity (
1754+ getSessionServerIdentity ( options ) ,
1755+ cert ,
1756+ ) ;
16721757 }
16731758
16741759 if ( verifyError ) {
@@ -1753,6 +1838,8 @@ exports.connect = function connect(...args) {
17531838 ) ;
17541839 }
17551840
1841+ options . session = getSessionForReuse ( options . session , options ) ;
1842+
17561843 const tlssock = new TLSSocket ( options . socket , {
17571844 allowHalfOpen : options . allowHalfOpen ,
17581845 pipe : ! ! options . path ,
0 commit comments