@@ -2,10 +2,18 @@ package utls
22
33import  (
44	"bytes" 
5+ 	"crypto/aes" 
6+ 	"crypto/cipher" 
7+ 	"crypto/hmac" 
58	"crypto/rand" 
9+ 	"crypto/sha256" 
610	"encoding/base64" 
11+ 	"encoding/binary" 
712	"encoding/hex" 
13+ 	"errors" 
14+ 	"fmt" 
815	"io" 
16+ 	"net" 
917	"net/http" 
1018	"os" 
1119	"testing" 
@@ -20,79 +28,72 @@ import (
2028	tls "github.com/refraction-networking/utls" 
2129)
2230
23- func  formatClientPacket (reg  * cj.DecoyRegistration , params  any ) ([]byte , error ) {
24- 
31+ func  connect (conn  net.Conn , reg  * cj.DecoyRegistration ) (net.Conn , error ) {
2532	// TODO: put these in params 
26- 	helloID  :=  tls .HelloChrome_102 
33+ 	helloID  :=  tls .HelloChrome_62 
2734	config  :=  tls.Config {ServerName : "" , InsecureSkipVerify : true }
2835
29- 	uTLSConn  :=  tls .UClient (nil , & config , helloID )
36+ 	uTLSConn  :=  tls .UClient (conn , & config , helloID )
3037	hmacID  :=  reg .Keys .ConjureHMAC (hmacString )
3138
32- 	err  :=  uTLSConn .BuildHandshakeState () // Apply our client hello ID 
39+ 	newRand  :=  make ([]byte , 32 )
40+ 	_ , err  :=  rand .Read (newRand )
3341	if  err  !=  nil  {
3442		return  nil , err 
3543	}
36- 	 uTLSConn . SetClientRandom ( hmacID ) 
37- 	err  =  uTLSConn .MarshalClientHello () // apply the updated ch random value  
44+ 
45+ 	err  =  uTLSConn .BuildHandshakeState () // Apply our client hello ID  
3846	if  err  !=  nil  {
3947		return  nil , err 
4048	}
49+ 	uTLSConn .SetClientRandom (newRand )
50+ 	// fmt.Printf("clientRandom set - handshaking %s\n", hex.EncodeToString(hmacID)) 
4151
42- 	return  uTLSConn .HandshakeState .Hello .Marshal ()
43- }
44- 
45- func  DisabledTestMarshalRandom (t  * testing.T ) {
46- 	hmacID  :=  make ([]byte , 32 )
47- 	_ , err  :=  rand .Read (hmacID )
48- 	require .Nil (t , err )
49- 
50- 	helloID  :=  tls .HelloChrome_102 
51- 	config  :=  tls.Config {ServerName : "" , InsecureSkipVerify : true }
52+ 	uTLSConn .HandshakeState .Hello .SessionId  =  xorBytes (hmacID , newRand )
5253
53- 	uTLSConn  :=  tls .UClient (nil , & config , helloID )
54- 
55- 	err  =  uTLSConn .BuildHandshakeState ()
56- 	require .Nil (t , err )
57- 	uTLSConn .SetClientRandom (hmacID )
58- 
59- 	err  =  uTLSConn .BuildHandshakeState ()
60- 	require .Nil (t , err )
61- 
62- 	// t.Log(hex.EncodeToString(hmacID)) 
63- 	// t.Log(hex.EncodeToString(uTLSConn.HandshakeState.Hello.Random)) 
64- 
65- 	b , err  :=  uTLSConn .HandshakeState .Hello .Marshal ()
66- 	require .Nil (t , err )
54+ 	err  =  uTLSConn .MarshalClientHello () // apply the updated ch random value 
55+ 	if  err  !=  nil  {
56+ 		return  nil , err 
57+ 	}
6758
68- 	ch  :=  tls .UnmarshalClientHello (b )
69- 	require .NotNil (t , ch )
70- 	// t.Log(hex.EncodeToString(ch.Random)) 
71- 	require .True (t , bytes .Equal (ch .Random , hmacID ))
59+ 	return  uTLSConn , uTLSConn .Handshake ()
7260}
7361
74- func  DisabledTestMarshalSNI (t  * testing.T ) {
75- 	hmacID  :=  [32 ]byte {}
76- 	_ , err  :=  rand .Read (hmacID [:])
77- 	require .Nil (t , err )
78- 
79- 	helloID  :=  tls .HelloChrome_102 
80- 	config  :=  tls.Config {ServerName : hex .EncodeToString (hmacID [:]), InsecureSkipVerify : true }
81- 
82- 	uTLSConn  :=  tls .UClient (nil , & config , helloID )
62+ func  TestByteRegex (t  * testing.T ) {
63+ 	testCases  :=  []struct  {
64+ 		s  string 
65+ 		l  uint16 
66+ 	}{
67+ 		{s : "16030100e2000000" , l : 226 },
68+ 		{s : "160301ff00000000" , l : 65280 },
69+ 	}
8370
84- 	err  =  uTLSConn .BuildHandshakeState ()
85- 	require .Nil (t , err )
71+ 	badCases  :=  []string {
72+ 		"15030100e2000000" ,
73+ 		"160301ff" ,
74+ 		"0016030100e2000000" ,
75+ 	}
8676
87- 	b , err  :=  uTLSConn .HandshakeState .Hello .Marshal ()
88- 	require .Nil (t , err )
77+ 	for  _ , c  :=  range  testCases  {
78+ 		b , err  :=  hex .DecodeString (c .s )
79+ 		require .Nil (t , err )
8980
90- 	ch  :=  tls .UnmarshalClientHello (b )
91- 	require .NotNil (t , ch )
81+ 		out  :=  tlsHeaderRegex .FindSubmatch (b )
82+ 		// for _, x := range out { 
83+ 		// 	t.Logf("%s", hex.EncodeToString(x)) 
84+ 		// } 
85+ 		require .Equal (t , 2 , len (out ))
86+ 		require .Equal (t , 2 , len (out [1 ]))
87+ 		u  :=  binary .BigEndian .Uint16 (out [1 ])
88+ 		require .Equal (t , c .l , u )
89+ 	}
90+ 	for  _ , c  :=  range  badCases  {
91+ 		b , err  :=  hex .DecodeString (c )
92+ 		require .Nil (t , err )
9293
93- 	recv ,  err   :=  hex . DecodeString ( ch . ServerName )
94- 	require .Nil (t , err )
95- 	require . True ( t ,  bytes . Equal ( recv ,  hmacID [:])) 
94+ 		 out   :=  tlsHeaderRegex . FindSubmatch ( b )
95+ 		 require .Equal (t , 0 ,  len ( out ) )
96+ 	} 
9697}
9798
9899func  TestSuccessfulWrap (t  * testing.T ) {
@@ -108,22 +109,46 @@ func TestSuccessfulWrap(t *testing.T) {
108109
109110	message  :=  []byte (`test message!` )
110111
111- 	connectMsg , err  :=  formatClientPacket (reg , nil )
112- 	require .Nil (t , err )
113- 	_ , err  =  c2p .Write (connectMsg )
112+ 	go  func () {
113+ 		var  buf  [1501 ]byte 
114+ 
115+ 		var  wrapped  net.Conn 
116+ 		var  err  error 
117+ 		for  {
118+ 			n , err  :=  sfp .Read (buf [:])
119+ 			if  err  !=  nil  {
120+ 				panic ("station read error" )
121+ 			}
122+ 
123+ 			reg , wrapped , err  =  transport .WrapConnection (bytes .NewBuffer (buf [:n ]), sfp , reg .PhantomIp , manager )
124+ 			if  errors .Is (err , transports .ErrNotTransport ) {
125+ 				panic ("failed to find registration" )
126+ 			} else  if  errors .Is (err , transports .ErrTransportNotSupported ) {
127+ 				panic ("transport supposed to be supported but isn't" )
128+ 			} else  if  err  ==  nil  {
129+ 				break 
130+ 			} // on transports.ErrTryAgain it should continue loop. 
131+ 		}
132+ 
133+ 		stationReceived  :=  make ([]byte , len (message ))
134+ 		_ , err  =  io .ReadFull (wrapped , stationReceived )
135+ 		if  err  !=  nil  {
136+ 			panic (fmt .Sprintf ("failed ReadFull: %s %s" , stationReceived , err ))
137+ 		}
138+ 		_ , err  =  wrapped .Write (stationReceived )
139+ 		if  err  !=  nil  {
140+ 			panic ("failed Write" )
141+ 		}
142+ 	}()
143+ 
144+ 	clientConn , err  :=  connect (c2p , reg )
114145	require .Nil (t , err )
115146
116- 	var  buf  [4096 ]byte 
117- 	n , _  :=  sfp .Read (buf [:])
118- 
119- 	_ , wrapped , err  :=  transport .WrapConnection (bytes .NewBuffer (buf [:n ]), sfp , reg .PhantomIp , manager )
120- 	require .Nil (t , err , "error getting wrapped connection" )
121- 
122- 	_ , err  =  c2p .Write (message )
147+ 	_ , err  =  clientConn .Write (message )
123148	require .Nil (t , err )
124149
125150	received  :=  make ([]byte , len (message ))
126- 	_ , err  =  io .ReadFull (wrapped , received )
151+ 	_ , err  =  io .ReadFull (clientConn , received )
127152	require .Nil (t , err , "failed reading from connection" )
128153	require .True (t , bytes .Equal (message , received ))
129154}
@@ -197,31 +222,52 @@ func TestSuccessfulWrapLargeMessage(t *testing.T) {
197222	defer  sfp .Close ()
198223	require .NotNil (t , reg )
199224
200- 	connectMsg , err  :=  formatClientPacket (reg , nil )
201- 	require .Nil (t , err )
202- 	_ , err  =  c2p .Write (connectMsg )
225+ 	message  :=  make ([]byte , 10000 )
226+ 	_ , err  :=  rand .Read (message )
203227	require .Nil (t , err )
204228
205- 	var  buf  [4096 ]byte 
206- 	var  buffer  bytes.Buffer 
207- 	n , _  :=  sfp .Read (buf [:])
208- 	buffer .Write (buf [:n ])
209- 
210- 	_ , wrapped , err  :=  transport .WrapConnection (& buffer , sfp , reg .PhantomIp , manager )
211- 	require .Nil (t , err , "error getting wrapped connection" )
212- 
213- 	message  :=  make ([]byte , 10000 )
214- 	_ , err  =  rand .Read (message )
229+ 	go  func () {
230+ 		var  buf  [1501 ]byte 
231+ 
232+ 		var  wrapped  net.Conn 
233+ 		var  err  error 
234+ 		for  {
235+ 			n , err  :=  sfp .Read (buf [:])
236+ 			if  err  !=  nil  {
237+ 				panic ("station read error" )
238+ 			}
239+ 
240+ 			reg , wrapped , err  =  transport .WrapConnection (bytes .NewBuffer (buf [:n ]), sfp , reg .PhantomIp , manager )
241+ 			if  errors .Is (err , transports .ErrNotTransport ) {
242+ 				panic ("failed to find registration" )
243+ 			} else  if  errors .Is (err , transports .ErrTransportNotSupported ) {
244+ 				panic ("transport supposed to be supported but isn't" )
245+ 			} else  if  err  ==  nil  {
246+ 				break 
247+ 			} // on transports.ErrTryAgain it should continue loop. 
248+ 		}
249+ 
250+ 		stationReceived  :=  make ([]byte , len (message ))
251+ 		_ , err  =  io .ReadFull (wrapped , stationReceived )
252+ 		if  err  !=  nil  {
253+ 			panic (fmt .Sprintf ("failed ReadFull: %s %s" , stationReceived , err ))
254+ 		}
255+ 		_ , err  =  wrapped .Write (stationReceived )
256+ 		if  err  !=  nil  {
257+ 			panic ("failed Write" )
258+ 		}
259+ 	}()
260+ 
261+ 	clientConn , err  :=  connect (c2p , reg )
215262	require .Nil (t , err )
216263
217- 	_ , err  =  c2p .Write (message )
264+ 	_ , err  =  clientConn .Write (message )
218265	require .Nil (t , err )
219266
220267	received  :=  make ([]byte , len (message ))
221- 	n , err  =  io .ReadFull (wrapped , received )
268+ 	n , err  : =io .ReadFull (clientConn , received )
222269	require .Nil (t , err , "failed reading from connection" )
223- 	require .True (t , bytes .Equal (message [:n ], received ), "xptd: %s\n recv: %s" , hex .EncodeToString (message [:len (received )]), hex .EncodeToString (received ))
224- 	// t.Log("l:", n) 
270+ 	require .True (t , bytes .Equal (message [:n ], received ))
225271}
226272
227273func  TestTryParamsToDstPort (t  * testing.T ) {
@@ -248,3 +294,124 @@ func TestTryParamsToDstPort(t *testing.T) {
248294		require .Equal (t , testCase .p , port )
249295	}
250296}
297+ 
298+ func  TestUtlsSessionResumption (t  * testing.T ) {
299+ 	// testSubnetPath := os.Getenv("GOPATH") + "/src/github.com/refraction-networking/conjure/application/lib/test/phantom_subnets.toml" 
300+ 	// os.Setenv("PHANTOM_SUBNET_LOCATION", testSubnetPath) 
301+ 
302+ 	// var transport Transport 
303+ 	// manager := tests.SetupRegistrationManager(tests.Transport{Index: pb.TransportType_Prefix, Transport: transport}) 
304+ 	// c2p, sfp, reg := tests.SetupPhantomConnections(manager, pb.TransportType_Prefix) 
305+ 	// defer c2p.Close() 
306+ 	// defer sfp.Close() 
307+ 	// require.NotNil(t, reg) 
308+ 	var  err  error 
309+ 	c2p , sfp  :=  net .Pipe ()
310+ 
311+ 	message  :=  []byte (`test message!` )
312+ 
313+ 	randVal  :=  [32 ]byte {}
314+ 	rand .Read (randVal [:])
315+ 
316+ 	go  func () {
317+ 
318+ 		config  :=  & tls.Config {
319+ 			Certificates :           make ([]tls.Certificate , 2 ),
320+ 			InsecureSkipVerify :     true ,
321+ 			MinVersion :             tls .VersionTLS10 ,
322+ 			MaxVersion :             tls .VersionTLS13 ,
323+ 			SessionTicketsDisabled : false ,
324+ 			ClientAuth :             tls .NoClientCert ,
325+ 		}
326+ 		// config.Certificates[0].Certificate = [][]byte{testRSACertificate} 
327+ 		// config.Certificates[0].PrivateKey = testRSAPrivateKey 
328+ 		// config.Certificates[1].Certificate = [][]byte{testSNICertificate} 
329+ 		// config.Certificates[1].PrivateKey = testRSAPrivateKey 
330+ 		// config.BuildNameToCertificate() 
331+ 		config .SetSessionTicketKeys ([][32 ]byte {randVal })
332+ 
333+ 		wrapped  :=  tls .Server (sfp , config )
334+ 
335+ 		stationReceived  :=  make ([]byte , len (message ))
336+ 		_ , err  :=  io .ReadFull (wrapped , stationReceived )
337+ 		if  err  !=  nil  {
338+ 			panic (fmt .Sprintf ("failed ReadFull: %s %s" , stationReceived , err ))
339+ 		}
340+ 		_ , err  =  wrapped .Write (stationReceived )
341+ 		if  err  !=  nil  {
342+ 			panic ("failed Write" )
343+ 		}
344+ 	}()
345+ 
346+ 	sessionTicket  :=  []uint8 (`Here goes phony session ticket: phony enough to get into ASCII range 
347+ Ticket could be of any length, but for camouflage purposes it's better to use uniformly random contents 
348+ and common length. See https://tlsfingerprint.io/session-tickets` )
349+ 
350+ 	// clientConn, err := connect(c2p, reg) 
351+ 	config  :=  & tls.Config {ServerName : "" , InsecureSkipVerify : true }
352+ 
353+ 	// Create a session ticket that wasn't actually issued by the server. 
354+ 	sessionState  :=  tls .MakeClientSessionState (sessionTicket , uint16 (tls .VersionTLS12 ),
355+ 		tls .TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 ,
356+ 		randVal [:],
357+ 		nil , nil )
358+ 
359+ 	clientTLSConn  :=  tls .UClient (c2p , config , tls .HelloGolang )
360+ 	require .NotNil (t , clientTLSConn )
361+ 
362+ 	err  =  clientTLSConn .BuildHandshakeState ()
363+ 	require .Nil (t , err )
364+ 
365+ 	err  =  clientTLSConn .SetSessionState (sessionState )
366+ 	require .Nil (t , err )
367+ 
368+ 	_ , err  =  clientTLSConn .Write (message )
369+ 	require .Nil (t , err )
370+ 
371+ 	received  :=  make ([]byte , len (message ))
372+ 	_ , err  =  io .ReadFull (clientTLSConn , received )
373+ 	require .Nil (t , err , "failed reading from connection" )
374+ 	require .True (t , bytes .Equal (message , received ))
375+ }
376+ 
377+ const  (
378+ 	// ticketKeyNameLen is the number of bytes of identifier that is prepended to 
379+ 	// an encrypted session ticket in order to identify the key used to encrypt it. 
380+ 	ticketKeyNameLen  =  16 
381+ )
382+ 
383+ // returns the session state and the marshalled sessionTicket, or an error should one occur. 
384+ func  forgeSession (secret  [32 ]byte ) (* tls.ClientSessionState , []byte , error ) {
385+ 	serverState  :=  tls .ForgeServerState (secret )
386+ 	stateBytes  :=  serverState .Marshal ()
387+ 
388+ 	encrypted  :=  make ([]byte , ticketKeyNameLen + aes .BlockSize + len (stateBytes )+ sha256 .Size )
389+ 	keyName  :=  encrypted [:ticketKeyNameLen ]
390+ 	iv  :=  encrypted [ticketKeyNameLen  : ticketKeyNameLen + aes .BlockSize ]
391+ 	macBytes  :=  encrypted [len (encrypted )- sha256 .Size :]
392+ 
393+ 	if  _ , err  :=  io .ReadFull (c .config .rand (), iv ); err  !=  nil  {
394+ 		return  nil , nil , err 
395+ 	}
396+ 
397+ 	copy (keyName , key .KeyName [:])
398+ 	block , err  :=  aes .NewCipher (key .AesKey [:])
399+ 	if  err  !=  nil  {
400+ 		return  nil , nil , errors .New ("tls: failed to create cipher while encrypting ticket: "  +  err .Error ())
401+ 	}
402+ 	cipher .NewCTR (block , iv ).XORKeyStream (encrypted [ticketKeyNameLen + aes .BlockSize :], stateBytes )
403+ 
404+ 	mac  :=  hmac .New (sha256 .New , key .HmacKey [:])
405+ 	mac .Write (encrypted [:len (encrypted )- sha256 .Size ])
406+ 	mac .Sum (macBytes [:0 ])
407+ 
408+ 	state  :=  tls .MakeClientSessionState (encrypted , uint16 (tls .VersionTLS12 ),
409+ 		tls .TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 ,
410+ 		masterSecret ,
411+ 		nil , nil )
412+ 
413+ 	return  state , encrypted , nil 
414+ }
415+ 
416+ // https://github.com/refraction-networking/utls/blob/c785bd3a1e8dd394d36526a2f3f118a21fc002c5/handshake_server_tls13.go#L736 
417+ // https://github.com/refraction-networking/utls/blob/c785bd3a1e8dd394d36526a2f3f118a21fc002c5/handshake_server.go#L769 
0 commit comments