@@ -113,6 +113,82 @@ const kIsVerified = Symbol('verified');
113113
114114const noop = ( ) => { } ;
115115
116+ const kTLSSessionStatePrefix = Buffer . from ( '\0nodejs:tls:session:1\0' ) ;
117+
118+ function getSessionServerIdentity ( options ) {
119+ return options ?. servername ||
120+ options ?. host ||
121+ options ?. socket ?. _host ||
122+ 'localhost' ;
123+ }
124+
125+ function wrapSessionState ( session , options ) {
126+ if ( ! Buffer . isBuffer ( session ) || options ?. isServer )
127+ return session ;
128+
129+ const servername = Buffer . from ( getSessionServerIdentity ( options ) , 'utf8' ) ;
130+ const servernameLength = Buffer . allocUnsafe ( 2 ) ;
131+ servernameLength . writeUInt16BE ( servername . length , 0 ) ;
132+
133+ return Buffer . concat ( [
134+ kTLSSessionStatePrefix ,
135+ servernameLength ,
136+ servername ,
137+ session ,
138+ ] ) ;
139+ }
140+
141+ function unwrapSessionState ( session ) {
142+ if ( ! Buffer . isBuffer ( session ) ||
143+ session . length < kTLSSessionStatePrefix . length + 2 ||
144+ Buffer . compare (
145+ session . subarray ( 0 , kTLSSessionStatePrefix . length ) ,
146+ kTLSSessionStatePrefix ,
147+ ) !== 0 ) {
148+ return ;
149+ }
150+
151+ const start = kTLSSessionStatePrefix . length ;
152+ const servernameLength = session . readUInt16BE ( start ) ;
153+ const servernameStart = start + 2 ;
154+ const servernameEnd = servernameStart + servernameLength ;
155+ if ( session . length < servernameEnd )
156+ return ;
157+
158+ return {
159+ servername : session . toString ( 'utf8' , servernameStart , servernameEnd ) ,
160+ session : session . subarray ( servernameEnd ) ,
161+ } ;
162+ }
163+
164+ function getSessionForReuse ( session , options ) {
165+ if ( typeof session === 'string' )
166+ session = Buffer . from ( session , 'latin1' ) ;
167+
168+ if ( options ?. isServer )
169+ return session ;
170+
171+ const wrappedSession = unwrapSessionState ( session ) ;
172+ if ( wrappedSession !== undefined ) {
173+ const servername = getSessionServerIdentity ( options ) ;
174+ if ( wrappedSession . servername !== servername ) {
175+ debug ( 'ignore session for %s: authenticated for %s' ,
176+ servername , wrappedSession . servername ) ;
177+ return ;
178+ }
179+
180+ return wrappedSession . session ;
181+ }
182+
183+ if ( Buffer . isBuffer ( session ) && options ?. rejectUnauthorized !== false ) {
184+ debug ( 'ignore raw session for verified client connection to %s' ,
185+ getSessionServerIdentity ( options ) ) ;
186+ return ;
187+ }
188+
189+ return session ;
190+ }
191+
116192let ipServernameWarned = false ;
117193let tlsTracingWarned = false ;
118194
@@ -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
@@ -1134,9 +1211,19 @@ TLSSocket.prototype.setServername = function(name) {
11341211} ;
11351212
11361213TLSSocket . prototype . setSession = function ( session ) {
1137- if ( typeof session === 'string' )
1138- session = Buffer . from ( session , 'latin1' ) ;
1139- this . _handle . setSession ( session ) ;
1214+ session = getSessionForReuse ( session , this [ kConnectOptions ] || this . _tlsOptions ) ;
1215+ if ( session !== undefined )
1216+ this . _handle . setSession ( session ) ;
1217+ } ;
1218+
1219+ TLSSocket . prototype . getSession = function ( ) {
1220+ if ( ! this . _handle )
1221+ return null ;
1222+
1223+ return wrapSessionState (
1224+ this . _handle . getSession ( ) ,
1225+ this [ kConnectOptions ] || this . _tlsOptions ,
1226+ ) ;
11401227} ;
11411228
11421229TLSSocket . prototype . getPeerCertificate = function ( detailed ) {
@@ -1195,7 +1282,6 @@ function makeSocketMethodProxy(name) {
11951282 'getFinished' ,
11961283 'getPeerFinished' ,
11971284 'getProtocol' ,
1198- 'getSession' ,
11991285 'getTLSTicket' ,
12001286 'isSessionReused' ,
12011287 'enableTrace' ,
@@ -1658,12 +1744,11 @@ function onConnectSecure() {
16581744 // Verify that server's identity matches it's certificate's names
16591745 // Unless server has resumed our existing session
16601746 if ( ! verifyError && ! this . isSessionReused ( ) ) {
1661- const hostname = options . servername ||
1662- options . host ||
1663- ( options . socket ?. _host ) ||
1664- 'localhost' ;
16651747 const cert = this . getPeerCertificate ( true ) ;
1666- verifyError = options . checkServerIdentity ( hostname , cert ) ;
1748+ verifyError = options . checkServerIdentity (
1749+ getSessionServerIdentity ( options ) ,
1750+ cert ,
1751+ ) ;
16671752 }
16681753
16691754 if ( verifyError ) {
@@ -1740,6 +1825,8 @@ exports.connect = function connect(...args) {
17401825
17411826 const context = options . secureContext || tls . createSecureContext ( options ) ;
17421827
1828+ options . session = getSessionForReuse ( options . session , options ) ;
1829+
17431830 const tlssock = new TLSSocket ( options . socket , {
17441831 allowHalfOpen : options . allowHalfOpen ,
17451832 pipe : ! ! options . path ,
0 commit comments