github.com/tumi8/quic-go@v0.37.4-tum/integrationtests/self/handshake_test.go (about) 1 package self_test 2 3 import ( 4 "context" 5 "crypto/tls" 6 "errors" 7 "fmt" 8 "io" 9 "net" 10 "time" 11 12 "github.com/tumi8/quic-go" 13 "github.com/tumi8/quic-go/noninternal/protocol" 14 "github.com/tumi8/quic-go/noninternal/qerr" 15 "github.com/tumi8/quic-go/noninternal/qtls" 16 17 . "github.com/onsi/ginkgo/v2" 18 . "github.com/onsi/gomega" 19 ) 20 21 type tokenStore struct { 22 store quic.TokenStore 23 gets chan<- string 24 puts chan<- string 25 } 26 27 var _ quic.TokenStore = &tokenStore{} 28 29 func newTokenStore(gets, puts chan<- string) quic.TokenStore { 30 return &tokenStore{ 31 store: quic.NewLRUTokenStore(10, 4), 32 gets: gets, 33 puts: puts, 34 } 35 } 36 37 func (c *tokenStore) Put(key string, token *quic.ClientToken) { 38 c.puts <- key 39 c.store.Put(key, token) 40 } 41 42 func (c *tokenStore) Pop(key string) *quic.ClientToken { 43 c.gets <- key 44 return c.store.Pop(key) 45 } 46 47 var _ = Describe("Handshake tests", func() { 48 var ( 49 server *quic.Listener 50 serverConfig *quic.Config 51 acceptStopped chan struct{} 52 ) 53 54 BeforeEach(func() { 55 server = nil 56 acceptStopped = make(chan struct{}) 57 serverConfig = getQuicConfig(nil) 58 }) 59 60 AfterEach(func() { 61 if server != nil { 62 server.Close() 63 <-acceptStopped 64 } 65 }) 66 67 runServer := func(tlsConf *tls.Config) { 68 var err error 69 // start the server 70 server, err = quic.ListenAddr("localhost:0", tlsConf, serverConfig) 71 Expect(err).ToNot(HaveOccurred()) 72 73 go func() { 74 defer GinkgoRecover() 75 defer close(acceptStopped) 76 for { 77 if _, err := server.Accept(context.Background()); err != nil { 78 return 79 } 80 } 81 }() 82 } 83 84 Context("using different cipher suites", func() { 85 for n, id := range map[string]uint16{ 86 "TLS_AES_128_GCM_SHA256": tls.TLS_AES_128_GCM_SHA256, 87 "TLS_AES_256_GCM_SHA384": tls.TLS_AES_256_GCM_SHA384, 88 "TLS_CHACHA20_POLY1305_SHA256": tls.TLS_CHACHA20_POLY1305_SHA256, 89 } { 90 name := n 91 suiteID := id 92 93 It(fmt.Sprintf("using %s", name), func() { 94 reset := qtls.SetCipherSuite(suiteID) 95 defer reset() 96 97 tlsConf := getTLSConfig() 98 ln, err := quic.ListenAddr("localhost:0", tlsConf, serverConfig) 99 Expect(err).ToNot(HaveOccurred()) 100 defer ln.Close() 101 102 go func() { 103 defer GinkgoRecover() 104 conn, err := ln.Accept(context.Background()) 105 Expect(err).ToNot(HaveOccurred()) 106 str, err := conn.OpenStream() 107 Expect(err).ToNot(HaveOccurred()) 108 defer str.Close() 109 _, err = str.Write(PRData) 110 Expect(err).ToNot(HaveOccurred()) 111 }() 112 113 conn, err := quic.DialAddr( 114 context.Background(), 115 fmt.Sprintf("localhost:%d", ln.Addr().(*net.UDPAddr).Port), 116 getTLSClientConfig(), 117 getQuicConfig(nil), 118 ) 119 Expect(err).ToNot(HaveOccurred()) 120 str, err := conn.AcceptStream(context.Background()) 121 Expect(err).ToNot(HaveOccurred()) 122 data, err := io.ReadAll(str) 123 Expect(err).ToNot(HaveOccurred()) 124 Expect(data).To(Equal(PRData)) 125 Expect(conn.ConnectionState().TLS.CipherSuite).To(Equal(suiteID)) 126 Expect(conn.CloseWithError(0, "")).To(Succeed()) 127 }) 128 } 129 }) 130 131 Context("Certificate validation", func() { 132 It("accepts the certificate", func() { 133 runServer(getTLSConfig()) 134 _, err := quic.DialAddr( 135 context.Background(), 136 fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), 137 getTLSClientConfig(), 138 getQuicConfig(nil), 139 ) 140 Expect(err).ToNot(HaveOccurred()) 141 }) 142 143 It("has the right local and remote address on the tls.Config.GetConfigForClient ClientHelloInfo.Conn", func() { 144 var local, remote net.Addr 145 var local2, remote2 net.Addr 146 done := make(chan struct{}) 147 tlsConf := &tls.Config{ 148 GetConfigForClient: func(info *tls.ClientHelloInfo) (*tls.Config, error) { 149 local = info.Conn.LocalAddr() 150 remote = info.Conn.RemoteAddr() 151 conf := getTLSConfig() 152 conf.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { 153 defer close(done) 154 local2 = info.Conn.LocalAddr() 155 remote2 = info.Conn.RemoteAddr() 156 return &(conf.Certificates[0]), nil 157 } 158 return conf, nil 159 }, 160 } 161 runServer(tlsConf) 162 conn, err := quic.DialAddr( 163 context.Background(), 164 fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), 165 getTLSClientConfig(), 166 getQuicConfig(nil), 167 ) 168 Expect(err).ToNot(HaveOccurred()) 169 Eventually(done).Should(BeClosed()) 170 Expect(server.Addr()).To(Equal(local)) 171 Expect(conn.LocalAddr().(*net.UDPAddr).Port).To(Equal(remote.(*net.UDPAddr).Port)) 172 Expect(local).To(Equal(local2)) 173 Expect(remote).To(Equal(remote2)) 174 }) 175 176 It("works with a long certificate chain", func() { 177 runServer(getTLSConfigWithLongCertChain()) 178 _, err := quic.DialAddr( 179 context.Background(), 180 fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), 181 getTLSClientConfig(), 182 getQuicConfig(nil), 183 ) 184 Expect(err).ToNot(HaveOccurred()) 185 }) 186 187 It("errors if the server name doesn't match", func() { 188 runServer(getTLSConfig()) 189 conn, err := net.ListenUDP("udp", nil) 190 Expect(err).ToNot(HaveOccurred()) 191 conf := getTLSClientConfig() 192 conf.ServerName = "foo.bar" 193 _, err = quic.Dial( 194 context.Background(), 195 conn, 196 server.Addr(), 197 conf, 198 getQuicConfig(nil), 199 ) 200 Expect(err).To(HaveOccurred()) 201 var transportErr *quic.TransportError 202 Expect(errors.As(err, &transportErr)).To(BeTrue()) 203 Expect(transportErr.ErrorCode.IsCryptoError()).To(BeTrue()) 204 Expect(transportErr.Error()).To(ContainSubstring("x509: certificate is valid for localhost, not foo.bar")) 205 }) 206 207 It("fails the handshake if the client fails to provide the requested client cert", func() { 208 tlsConf := getTLSConfig() 209 tlsConf.ClientAuth = tls.RequireAndVerifyClientCert 210 runServer(tlsConf) 211 212 conn, err := quic.DialAddr( 213 context.Background(), 214 fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), 215 getTLSClientConfig(), 216 getQuicConfig(nil), 217 ) 218 // Usually, the error will occur after the client already finished the handshake. 219 // However, there's a race condition here. The server's CONNECTION_CLOSE might be 220 // received before the connection is returned, so we might already get the error while dialing. 221 if err == nil { 222 errChan := make(chan error) 223 go func() { 224 defer GinkgoRecover() 225 _, err := conn.AcceptStream(context.Background()) 226 errChan <- err 227 }() 228 Eventually(errChan).Should(Receive(&err)) 229 } 230 Expect(err).To(HaveOccurred()) 231 var transportErr *quic.TransportError 232 Expect(errors.As(err, &transportErr)).To(BeTrue()) 233 Expect(transportErr.ErrorCode.IsCryptoError()).To(BeTrue()) 234 Expect(transportErr.Error()).To(Or( 235 ContainSubstring("tls: certificate required"), 236 ContainSubstring("tls: bad certificate"), 237 )) 238 }) 239 240 It("uses the ServerName in the tls.Config", func() { 241 runServer(getTLSConfig()) 242 tlsConf := getTLSClientConfig() 243 tlsConf.ServerName = "foo.bar" 244 _, err := quic.DialAddr( 245 context.Background(), 246 fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), 247 tlsConf, 248 getQuicConfig(nil), 249 ) 250 Expect(err).To(HaveOccurred()) 251 var transportErr *quic.TransportError 252 Expect(errors.As(err, &transportErr)).To(BeTrue()) 253 Expect(transportErr.ErrorCode.IsCryptoError()).To(BeTrue()) 254 Expect(transportErr.Error()).To(ContainSubstring("x509: certificate is valid for localhost, not foo.bar")) 255 }) 256 }) 257 258 Context("rate limiting", func() { 259 var ( 260 server *quic.Listener 261 pconn net.PacketConn 262 dialer *quic.Transport 263 ) 264 265 dial := func() (quic.Connection, error) { 266 remoteAddr := fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port) 267 raddr, err := net.ResolveUDPAddr("udp", remoteAddr) 268 Expect(err).ToNot(HaveOccurred()) 269 return dialer.Dial(context.Background(), raddr, getTLSClientConfig(), getQuicConfig(nil)) 270 } 271 272 BeforeEach(func() { 273 var err error 274 // start the server, but don't call Accept 275 server, err = quic.ListenAddr("localhost:0", getTLSConfig(), serverConfig) 276 Expect(err).ToNot(HaveOccurred()) 277 278 // prepare a (single) packet conn for dialing to the server 279 laddr, err := net.ResolveUDPAddr("udp", "localhost:0") 280 Expect(err).ToNot(HaveOccurred()) 281 pconn, err = net.ListenUDP("udp", laddr) 282 Expect(err).ToNot(HaveOccurred()) 283 dialer = &quic.Transport{Conn: pconn, ConnectionIDLength: 4} 284 }) 285 286 AfterEach(func() { 287 Expect(server.Close()).To(Succeed()) 288 Expect(pconn.Close()).To(Succeed()) 289 Expect(dialer.Close()).To(Succeed()) 290 }) 291 292 It("rejects new connection attempts if connections don't get accepted", func() { 293 for i := 0; i < protocol.MaxAcceptQueueSize; i++ { 294 conn, err := dial() 295 Expect(err).ToNot(HaveOccurred()) 296 defer conn.CloseWithError(0, "") 297 } 298 time.Sleep(25 * time.Millisecond) // wait a bit for the connection to be queued 299 300 _, err := dial() 301 Expect(err).To(HaveOccurred()) 302 var transportErr *quic.TransportError 303 Expect(errors.As(err, &transportErr)).To(BeTrue()) 304 Expect(transportErr.ErrorCode).To(Equal(quic.ConnectionRefused)) 305 306 // now accept one connection, freeing one spot in the queue 307 _, err = server.Accept(context.Background()) 308 Expect(err).ToNot(HaveOccurred()) 309 // dial again, and expect that this dial succeeds 310 conn, err := dial() 311 Expect(err).ToNot(HaveOccurred()) 312 defer conn.CloseWithError(0, "") 313 time.Sleep(25 * time.Millisecond) // wait a bit for the connection to be queued 314 315 _, err = dial() 316 Expect(err).To(HaveOccurred()) 317 Expect(errors.As(err, &transportErr)).To(BeTrue()) 318 Expect(transportErr.ErrorCode).To(Equal(quic.ConnectionRefused)) 319 }) 320 321 It("removes closed connections from the accept queue", func() { 322 firstConn, err := dial() 323 Expect(err).ToNot(HaveOccurred()) 324 325 for i := 1; i < protocol.MaxAcceptQueueSize; i++ { 326 conn, err := dial() 327 Expect(err).ToNot(HaveOccurred()) 328 defer conn.CloseWithError(0, "") 329 } 330 time.Sleep(scaleDuration(20 * time.Millisecond)) // wait a bit for the connection to be queued 331 332 _, err = dial() 333 Expect(err).To(HaveOccurred()) 334 var transportErr *quic.TransportError 335 Expect(errors.As(err, &transportErr)).To(BeTrue()) 336 Expect(transportErr.ErrorCode).To(Equal(quic.ConnectionRefused)) 337 338 // Now close the one of the connection that are waiting to be accepted. 339 // This should free one spot in the queue. 340 Expect(firstConn.CloseWithError(0, "")) 341 Eventually(firstConn.Context().Done()).Should(BeClosed()) 342 time.Sleep(scaleDuration(200 * time.Millisecond)) 343 344 // dial again, and expect that this dial succeeds 345 _, err = dial() 346 Expect(err).ToNot(HaveOccurred()) 347 time.Sleep(scaleDuration(20 * time.Millisecond)) // wait a bit for the connection to be queued 348 349 _, err = dial() 350 Expect(err).To(HaveOccurred()) 351 Expect(errors.As(err, &transportErr)).To(BeTrue()) 352 Expect(transportErr.ErrorCode).To(Equal(quic.ConnectionRefused)) 353 }) 354 }) 355 356 Context("ALPN", func() { 357 It("negotiates an application protocol", func() { 358 ln, err := quic.ListenAddr("localhost:0", getTLSConfig(), serverConfig) 359 Expect(err).ToNot(HaveOccurred()) 360 361 done := make(chan struct{}) 362 go func() { 363 defer GinkgoRecover() 364 conn, err := ln.Accept(context.Background()) 365 Expect(err).ToNot(HaveOccurred()) 366 cs := conn.ConnectionState() 367 Expect(cs.TLS.NegotiatedProtocol).To(Equal(alpn)) 368 close(done) 369 }() 370 371 conn, err := quic.DialAddr( 372 context.Background(), 373 fmt.Sprintf("localhost:%d", ln.Addr().(*net.UDPAddr).Port), 374 getTLSClientConfig(), 375 nil, 376 ) 377 Expect(err).ToNot(HaveOccurred()) 378 defer conn.CloseWithError(0, "") 379 cs := conn.ConnectionState() 380 Expect(cs.TLS.NegotiatedProtocol).To(Equal(alpn)) 381 Eventually(done).Should(BeClosed()) 382 Expect(ln.Close()).To(Succeed()) 383 }) 384 385 It("errors if application protocol negotiation fails", func() { 386 runServer(getTLSConfig()) 387 388 tlsConf := getTLSClientConfig() 389 tlsConf.NextProtos = []string{"foobar"} 390 _, err := quic.DialAddr( 391 context.Background(), 392 fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), 393 tlsConf, 394 nil, 395 ) 396 Expect(err).To(HaveOccurred()) 397 var transportErr *quic.TransportError 398 Expect(errors.As(err, &transportErr)).To(BeTrue()) 399 Expect(transportErr.ErrorCode.IsCryptoError()).To(BeTrue()) 400 Expect(transportErr.Error()).To(ContainSubstring("no application protocol")) 401 }) 402 }) 403 404 Context("using tokens", func() { 405 It("uses tokens provided in NEW_TOKEN frames", func() { 406 server, err := quic.ListenAddr("localhost:0", getTLSConfig(), serverConfig) 407 Expect(err).ToNot(HaveOccurred()) 408 defer server.Close() 409 410 // dial the first connection and receive the token 411 go func() { 412 defer GinkgoRecover() 413 _, err := server.Accept(context.Background()) 414 Expect(err).ToNot(HaveOccurred()) 415 }() 416 417 gets := make(chan string, 100) 418 puts := make(chan string, 100) 419 tokenStore := newTokenStore(gets, puts) 420 quicConf := getQuicConfig(&quic.Config{TokenStore: tokenStore}) 421 conn, err := quic.DialAddr( 422 context.Background(), 423 fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), 424 getTLSClientConfig(), 425 quicConf, 426 ) 427 Expect(err).ToNot(HaveOccurred()) 428 Expect(gets).To(Receive()) 429 Eventually(puts).Should(Receive()) 430 // received a token. Close this connection. 431 Expect(conn.CloseWithError(0, "")).To(Succeed()) 432 433 // dial the second connection and verify that the token was used 434 done := make(chan struct{}) 435 go func() { 436 defer GinkgoRecover() 437 defer close(done) 438 _, err := server.Accept(context.Background()) 439 Expect(err).ToNot(HaveOccurred()) 440 }() 441 conn, err = quic.DialAddr( 442 context.Background(), 443 fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), 444 getTLSClientConfig(), 445 quicConf, 446 ) 447 Expect(err).ToNot(HaveOccurred()) 448 defer conn.CloseWithError(0, "") 449 Expect(gets).To(Receive()) 450 451 Eventually(done).Should(BeClosed()) 452 }) 453 454 It("rejects invalid Retry token with the INVALID_TOKEN error", func() { 455 serverConfig.RequireAddressValidation = func(net.Addr) bool { return true } 456 serverConfig.MaxRetryTokenAge = time.Nanosecond 457 458 server, err := quic.ListenAddr("localhost:0", getTLSConfig(), serverConfig) 459 Expect(err).ToNot(HaveOccurred()) 460 defer server.Close() 461 462 _, err = quic.DialAddr( 463 context.Background(), 464 fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), 465 getTLSClientConfig(), 466 nil, 467 ) 468 Expect(err).To(HaveOccurred()) 469 var transportErr *quic.TransportError 470 Expect(errors.As(err, &transportErr)).To(BeTrue()) 471 Expect(transportErr.ErrorCode).To(Equal(quic.InvalidToken)) 472 }) 473 }) 474 475 Context("GetConfigForClient", func() { 476 It("uses the quic.Config returned by GetConfigForClient", func() { 477 serverConfig.EnableDatagrams = false 478 var calledFrom net.Addr 479 serverConfig.GetConfigForClient = func(info *quic.ClientHelloInfo) (*quic.Config, error) { 480 conf := serverConfig.Clone() 481 conf.EnableDatagrams = true 482 calledFrom = info.RemoteAddr 483 return getQuicConfig(conf), nil 484 } 485 ln, err := quic.ListenAddr("localhost:0", getTLSConfig(), serverConfig) 486 Expect(err).ToNot(HaveOccurred()) 487 488 done := make(chan struct{}) 489 go func() { 490 defer GinkgoRecover() 491 _, err := ln.Accept(context.Background()) 492 Expect(err).ToNot(HaveOccurred()) 493 close(done) 494 }() 495 496 conn, err := quic.DialAddr( 497 context.Background(), 498 fmt.Sprintf("localhost:%d", ln.Addr().(*net.UDPAddr).Port), 499 getTLSClientConfig(), 500 getQuicConfig(&quic.Config{EnableDatagrams: true}), 501 ) 502 Expect(err).ToNot(HaveOccurred()) 503 defer conn.CloseWithError(0, "") 504 cs := conn.ConnectionState() 505 Expect(cs.SupportsDatagrams).To(BeTrue()) 506 Eventually(done).Should(BeClosed()) 507 Expect(ln.Close()).To(Succeed()) 508 Expect(calledFrom.(*net.UDPAddr).Port).To(Equal(conn.LocalAddr().(*net.UDPAddr).Port)) 509 }) 510 511 It("rejects the connection attempt if GetConfigForClient errors", func() { 512 serverConfig.EnableDatagrams = false 513 serverConfig.GetConfigForClient = func(info *quic.ClientHelloInfo) (*quic.Config, error) { 514 return nil, errors.New("rejected") 515 } 516 ln, err := quic.ListenAddr("localhost:0", getTLSConfig(), serverConfig) 517 Expect(err).ToNot(HaveOccurred()) 518 defer ln.Close() 519 520 done := make(chan struct{}) 521 go func() { 522 defer GinkgoRecover() 523 _, err := ln.Accept(context.Background()) 524 Expect(err).To(HaveOccurred()) // we don't expect to accept any connection 525 close(done) 526 }() 527 528 _, err = quic.DialAddr( 529 context.Background(), 530 fmt.Sprintf("localhost:%d", ln.Addr().(*net.UDPAddr).Port), 531 getTLSClientConfig(), 532 getQuicConfig(&quic.Config{EnableDatagrams: true}), 533 ) 534 Expect(err).To(HaveOccurred()) 535 var transportErr *quic.TransportError 536 Expect(errors.As(err, &transportErr)).To(BeTrue()) 537 Expect(transportErr.ErrorCode).To(Equal(qerr.ConnectionRefused)) 538 }) 539 }) 540 541 It("doesn't send any packets when generating the ClientHello fails", func() { 542 ln, err := net.ListenUDP("udp", nil) 543 Expect(err).ToNot(HaveOccurred()) 544 done := make(chan struct{}) 545 packetChan := make(chan struct{}) 546 go func() { 547 defer GinkgoRecover() 548 defer close(done) 549 for { 550 _, _, err := ln.ReadFromUDP(make([]byte, protocol.MaxPacketBufferSize)) 551 if err != nil { 552 return 553 } 554 packetChan <- struct{}{} 555 } 556 }() 557 558 tlsConf := getTLSClientConfig() 559 tlsConf.NextProtos = []string{""} 560 _, err = quic.DialAddr( 561 context.Background(), 562 fmt.Sprintf("localhost:%d", ln.LocalAddr().(*net.UDPAddr).Port), 563 tlsConf, 564 nil, 565 ) 566 Expect(err).To(MatchError(&qerr.TransportError{ 567 ErrorCode: qerr.InternalError, 568 ErrorMessage: "tls: invalid NextProtos value", 569 })) 570 Consistently(packetChan).ShouldNot(Receive()) 571 ln.Close() 572 Eventually(done).Should(BeClosed()) 573 }) 574 })