golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/tls_test.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build go1.21 6 7 package quic 8 9 import ( 10 "crypto/tls" 11 "crypto/x509" 12 "errors" 13 "testing" 14 "time" 15 ) 16 17 // handshake executes the handshake. 18 func (tc *testConn) handshake() { 19 tc.t.Helper() 20 if *testVV { 21 *testVV = false 22 defer func() { 23 tc.t.Helper() 24 *testVV = true 25 tc.t.Logf("performed connection handshake") 26 }() 27 } 28 defer func(saved map[byte]bool) { 29 tc.ignoreFrames = saved 30 }(tc.ignoreFrames) 31 tc.ignoreFrames = nil 32 t := tc.t 33 dgrams := handshakeDatagrams(tc) 34 i := 0 35 for { 36 if i == len(dgrams)-1 { 37 if tc.conn.side == clientSide { 38 want := tc.endpoint.now.Add(maxAckDelay - timerGranularity) 39 if !tc.timer.Equal(want) { 40 t.Fatalf("want timer = %v (max_ack_delay), got %v", want, tc.timer) 41 } 42 if got := tc.readDatagram(); got != nil { 43 t.Fatalf("client unexpectedly sent: %v", got) 44 } 45 } 46 tc.advance(maxAckDelay) 47 } 48 49 // Check that we're sending exactly the data we expect. 50 // Any variation from the norm here should be intentional. 51 got := tc.readDatagram() 52 var want *testDatagram 53 if !(tc.conn.side == serverSide && i == 0) && i < len(dgrams) { 54 want = dgrams[i] 55 fillCryptoFrames(want, tc.cryptoDataOut) 56 i++ 57 } 58 if !datagramEqual(got, want) { 59 t.Fatalf("dgram %v:\ngot %v\n\nwant %v", i, got, want) 60 } 61 if i >= len(dgrams) { 62 break 63 } 64 65 fillCryptoFrames(dgrams[i], tc.cryptoDataIn) 66 tc.write(dgrams[i]) 67 i++ 68 } 69 } 70 71 func handshakeDatagrams(tc *testConn) (dgrams []*testDatagram) { 72 var ( 73 clientConnIDs [][]byte 74 serverConnIDs [][]byte 75 clientResetToken statelessResetToken 76 serverResetToken statelessResetToken 77 transientConnID []byte 78 ) 79 localConnIDs := [][]byte{ 80 testLocalConnID(0), 81 testLocalConnID(1), 82 } 83 peerConnIDs := [][]byte{ 84 testPeerConnID(0), 85 testPeerConnID(1), 86 } 87 localResetToken := tc.endpoint.e.resetGen.tokenForConnID(localConnIDs[1]) 88 peerResetToken := testPeerStatelessResetToken(1) 89 if tc.conn.side == clientSide { 90 clientConnIDs = localConnIDs 91 serverConnIDs = peerConnIDs 92 clientResetToken = localResetToken 93 serverResetToken = peerResetToken 94 transientConnID = testLocalConnID(-1) 95 } else { 96 clientConnIDs = peerConnIDs 97 serverConnIDs = localConnIDs 98 clientResetToken = peerResetToken 99 serverResetToken = localResetToken 100 transientConnID = testPeerConnID(-1) 101 } 102 return []*testDatagram{{ 103 // Client Initial 104 packets: []*testPacket{{ 105 ptype: packetTypeInitial, 106 num: 0, 107 version: quicVersion1, 108 srcConnID: clientConnIDs[0], 109 dstConnID: transientConnID, 110 frames: []debugFrame{ 111 debugFrameCrypto{}, 112 }, 113 }}, 114 paddedSize: 1200, 115 }, { 116 // Server Initial + Handshake + 1-RTT 117 packets: []*testPacket{{ 118 ptype: packetTypeInitial, 119 num: 0, 120 version: quicVersion1, 121 srcConnID: serverConnIDs[0], 122 dstConnID: clientConnIDs[0], 123 frames: []debugFrame{ 124 debugFrameAck{ 125 ranges: []i64range[packetNumber]{{0, 1}}, 126 }, 127 debugFrameCrypto{}, 128 }, 129 }, { 130 ptype: packetTypeHandshake, 131 num: 0, 132 version: quicVersion1, 133 srcConnID: serverConnIDs[0], 134 dstConnID: clientConnIDs[0], 135 frames: []debugFrame{ 136 debugFrameCrypto{}, 137 }, 138 }, { 139 ptype: packetType1RTT, 140 num: 0, 141 dstConnID: clientConnIDs[0], 142 frames: []debugFrame{ 143 debugFrameNewConnectionID{ 144 seq: 1, 145 connID: serverConnIDs[1], 146 token: serverResetToken, 147 }, 148 }, 149 }}, 150 paddedSize: 1200, 151 }, { 152 // Client Initial + Handshake + 1-RTT 153 packets: []*testPacket{{ 154 ptype: packetTypeInitial, 155 num: 1, 156 version: quicVersion1, 157 srcConnID: clientConnIDs[0], 158 dstConnID: serverConnIDs[0], 159 frames: []debugFrame{ 160 debugFrameAck{ 161 ranges: []i64range[packetNumber]{{0, 1}}, 162 }, 163 }, 164 }, { 165 ptype: packetTypeHandshake, 166 num: 0, 167 version: quicVersion1, 168 srcConnID: clientConnIDs[0], 169 dstConnID: serverConnIDs[0], 170 frames: []debugFrame{ 171 debugFrameAck{ 172 ranges: []i64range[packetNumber]{{0, 1}}, 173 }, 174 debugFrameCrypto{}, 175 }, 176 }, { 177 ptype: packetType1RTT, 178 num: 0, 179 dstConnID: serverConnIDs[0], 180 frames: []debugFrame{ 181 debugFrameAck{ 182 ranges: []i64range[packetNumber]{{0, 1}}, 183 }, 184 debugFrameNewConnectionID{ 185 seq: 1, 186 connID: clientConnIDs[1], 187 token: clientResetToken, 188 }, 189 }, 190 }}, 191 paddedSize: 1200, 192 }, { 193 // Server HANDSHAKE_DONE 194 packets: []*testPacket{{ 195 ptype: packetType1RTT, 196 num: 1, 197 dstConnID: clientConnIDs[0], 198 frames: []debugFrame{ 199 debugFrameAck{ 200 ranges: []i64range[packetNumber]{{0, 1}}, 201 }, 202 debugFrameHandshakeDone{}, 203 }, 204 }}, 205 }, { 206 // Client ack (after max_ack_delay) 207 packets: []*testPacket{{ 208 ptype: packetType1RTT, 209 num: 1, 210 dstConnID: serverConnIDs[0], 211 frames: []debugFrame{ 212 debugFrameAck{ 213 ackDelay: unscaledAckDelayFromDuration( 214 maxAckDelay, ackDelayExponent), 215 ranges: []i64range[packetNumber]{{0, 2}}, 216 }, 217 }, 218 }}, 219 }} 220 } 221 222 func fillCryptoFrames(d *testDatagram, data map[tls.QUICEncryptionLevel][]byte) { 223 for _, p := range d.packets { 224 var level tls.QUICEncryptionLevel 225 switch p.ptype { 226 case packetTypeInitial: 227 level = tls.QUICEncryptionLevelInitial 228 case packetTypeHandshake: 229 level = tls.QUICEncryptionLevelHandshake 230 case packetType1RTT: 231 level = tls.QUICEncryptionLevelApplication 232 default: 233 continue 234 } 235 for i := range p.frames { 236 c, ok := p.frames[i].(debugFrameCrypto) 237 if !ok { 238 continue 239 } 240 c.data = data[level] 241 data[level] = nil 242 p.frames[i] = c 243 } 244 } 245 } 246 247 // uncheckedHandshake executes the handshake. 248 // 249 // Unlike testConn.handshake, it sends nothing unnecessary 250 // (in particular, no NEW_CONNECTION_ID frames), 251 // and does not validate the conn's responses. 252 // 253 // Useful for testing scenarios where configuration has 254 // changed the handshake responses in some way. 255 func (tc *testConn) uncheckedHandshake() { 256 tc.t.Helper() 257 defer func(saved map[byte]bool) { 258 tc.ignoreFrames = saved 259 }(tc.ignoreFrames) 260 tc.ignoreFrames = map[byte]bool{ 261 frameTypeAck: true, 262 frameTypeCrypto: true, 263 frameTypeNewConnectionID: true, 264 } 265 if tc.conn.side == serverSide { 266 tc.writeFrames(packetTypeInitial, 267 debugFrameCrypto{ 268 data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial], 269 }) 270 tc.writeFrames(packetTypeHandshake, 271 debugFrameCrypto{ 272 data: tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake], 273 }) 274 tc.wantFrame("send HANDSHAKE_DONE after handshake completes", 275 packetType1RTT, debugFrameHandshakeDone{}) 276 tc.writeFrames(packetType1RTT, 277 debugFrameAck{ 278 ackDelay: unscaledAckDelayFromDuration( 279 maxAckDelay, ackDelayExponent), 280 ranges: []i64range[packetNumber]{{0, tc.lastPacket.num + 1}}, 281 }) 282 } else { 283 tc.wantIdle("initial frames are ignored") 284 tc.writeFrames(packetTypeInitial, 285 debugFrameCrypto{ 286 data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial], 287 }) 288 tc.writeFrames(packetTypeHandshake, 289 debugFrameCrypto{ 290 data: tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake], 291 }) 292 tc.wantIdle("don't expect any frames we aren't ignoring") 293 // Send the next two frames in separate packets, so the client sends an 294 // ack immediately without delay. We want to consume that ack here, rather 295 // than returning with a delayed ack waiting to be sent. 296 tc.ignoreFrames = nil 297 tc.writeFrames(packetType1RTT, 298 debugFrameHandshakeDone{}) 299 tc.writeFrames(packetType1RTT, 300 debugFrameCrypto{ 301 data: tc.cryptoDataIn[tls.QUICEncryptionLevelApplication], 302 }) 303 tc.wantFrame("client ACKs server's first 1-RTT packet", 304 packetType1RTT, debugFrameAck{ 305 ranges: []i64range[packetNumber]{{0, 2}}, 306 }) 307 308 } 309 tc.wantIdle("handshake is done") 310 } 311 312 func TestConnClientHandshake(t *testing.T) { 313 tc := newTestConn(t, clientSide) 314 tc.handshake() 315 tc.advance(1 * time.Second) 316 tc.wantIdle("no packets should be sent by an idle conn after the handshake") 317 } 318 319 func TestConnServerHandshake(t *testing.T) { 320 tc := newTestConn(t, serverSide) 321 tc.handshake() 322 tc.advance(1 * time.Second) 323 tc.wantIdle("no packets should be sent by an idle conn after the handshake") 324 } 325 326 func TestConnKeysDiscardedClient(t *testing.T) { 327 tc := newTestConn(t, clientSide) 328 tc.ignoreFrame(frameTypeAck) 329 330 tc.wantFrame("client sends Initial CRYPTO frame", 331 packetTypeInitial, debugFrameCrypto{ 332 data: tc.cryptoDataOut[tls.QUICEncryptionLevelInitial], 333 }) 334 tc.writeFrames(packetTypeInitial, 335 debugFrameCrypto{ 336 data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial], 337 }) 338 tc.writeFrames(packetTypeHandshake, 339 debugFrameCrypto{ 340 data: tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake], 341 }) 342 tc.wantFrame("client sends Handshake CRYPTO frame", 343 packetTypeHandshake, debugFrameCrypto{ 344 data: tc.cryptoDataOut[tls.QUICEncryptionLevelHandshake], 345 }) 346 tc.wantFrame("client provides an additional connection ID", 347 packetType1RTT, debugFrameNewConnectionID{ 348 seq: 1, 349 connID: testLocalConnID(1), 350 token: testLocalStatelessResetToken(1), 351 }) 352 353 // The client discards Initial keys after sending a Handshake packet. 354 tc.writeFrames(packetTypeInitial, 355 debugFrameConnectionCloseTransport{code: errInternal}) 356 tc.wantIdle("client has discarded Initial keys, cannot read CONNECTION_CLOSE") 357 358 // The client discards Handshake keys after receiving a HANDSHAKE_DONE frame. 359 tc.writeFrames(packetType1RTT, 360 debugFrameHandshakeDone{}) 361 tc.writeFrames(packetTypeHandshake, 362 debugFrameConnectionCloseTransport{code: errInternal}) 363 tc.wantIdle("client has discarded Handshake keys, cannot read CONNECTION_CLOSE") 364 365 tc.writeFrames(packetType1RTT, 366 debugFrameConnectionCloseTransport{code: errInternal}) 367 tc.conn.Abort(nil) 368 tc.wantFrame("client closes connection after 1-RTT CONNECTION_CLOSE", 369 packetType1RTT, debugFrameConnectionCloseTransport{ 370 code: errNo, 371 }) 372 } 373 374 func TestConnKeysDiscardedServer(t *testing.T) { 375 tc := newTestConn(t, serverSide) 376 tc.ignoreFrame(frameTypeAck) 377 378 tc.writeFrames(packetTypeInitial, 379 debugFrameCrypto{ 380 data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial], 381 }) 382 tc.wantFrame("server sends Initial CRYPTO frame", 383 packetTypeInitial, debugFrameCrypto{ 384 data: tc.cryptoDataOut[tls.QUICEncryptionLevelInitial], 385 }) 386 tc.wantFrame("server sends Handshake CRYPTO frame", 387 packetTypeHandshake, debugFrameCrypto{ 388 data: tc.cryptoDataOut[tls.QUICEncryptionLevelHandshake], 389 }) 390 391 // The server discards Initial keys after receiving a Handshake packet. 392 // The Handshake packet contains only the start of the client's CRYPTO flight here, 393 // to avoids completing the handshake yet. 394 tc.writeFrames(packetTypeHandshake, 395 debugFrameCrypto{ 396 data: tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake][:1], 397 }) 398 tc.writeFrames(packetTypeInitial, 399 debugFrameConnectionCloseTransport{code: errInternal}) 400 tc.wantFrame("server provides an additional connection ID", 401 packetType1RTT, debugFrameNewConnectionID{ 402 seq: 1, 403 connID: testLocalConnID(1), 404 token: testLocalStatelessResetToken(1), 405 }) 406 tc.wantIdle("server has discarded Initial keys, cannot read CONNECTION_CLOSE") 407 408 // The server discards Handshake keys after sending a HANDSHAKE_DONE frame. 409 tc.writeFrames(packetTypeHandshake, 410 debugFrameCrypto{ 411 off: 1, 412 data: tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake][1:], 413 }) 414 tc.wantFrame("server sends HANDSHAKE_DONE after handshake completes", 415 packetType1RTT, debugFrameHandshakeDone{}) 416 tc.writeFrames(packetTypeHandshake, 417 debugFrameConnectionCloseTransport{code: errInternal}) 418 tc.wantIdle("server has discarded Handshake keys, cannot read CONNECTION_CLOSE") 419 420 tc.writeFrames(packetType1RTT, 421 debugFrameConnectionCloseTransport{code: errInternal}) 422 tc.conn.Abort(nil) 423 tc.wantFrame("server closes connection after 1-RTT CONNECTION_CLOSE", 424 packetType1RTT, debugFrameConnectionCloseTransport{ 425 code: errNo, 426 }) 427 } 428 429 func TestConnInvalidCryptoData(t *testing.T) { 430 tc := newTestConn(t, clientSide) 431 tc.ignoreFrame(frameTypeAck) 432 433 tc.wantFrame("client sends Initial CRYPTO frame", 434 packetTypeInitial, debugFrameCrypto{ 435 data: tc.cryptoDataOut[tls.QUICEncryptionLevelInitial], 436 }) 437 tc.writeFrames(packetTypeInitial, 438 debugFrameCrypto{ 439 data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial], 440 }) 441 442 // Render the server's response invalid. 443 // 444 // The client closes the connection with CRYPTO_ERROR. 445 // 446 // Changing the first byte will change the TLS message type, 447 // so we can reasonably assume that this is an unexpected_message alert (10). 448 tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake][0] ^= 0x1 449 tc.writeFrames(packetTypeHandshake, 450 debugFrameCrypto{ 451 data: tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake], 452 }) 453 tc.wantFrame("client closes connection due to TLS handshake error", 454 packetTypeInitial, debugFrameConnectionCloseTransport{ 455 code: errTLSBase + 10, 456 }) 457 } 458 459 func TestConnInvalidPeerCertificate(t *testing.T) { 460 tc := newTestConn(t, clientSide, func(c *tls.Config) { 461 c.VerifyPeerCertificate = func([][]byte, [][]*x509.Certificate) error { 462 return errors.New("I will not buy this certificate. It is scratched.") 463 } 464 }) 465 tc.ignoreFrame(frameTypeAck) 466 467 tc.wantFrame("client sends Initial CRYPTO frame", 468 packetTypeInitial, debugFrameCrypto{ 469 data: tc.cryptoDataOut[tls.QUICEncryptionLevelInitial], 470 }) 471 tc.writeFrames(packetTypeInitial, 472 debugFrameCrypto{ 473 data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial], 474 }) 475 tc.writeFrames(packetTypeHandshake, 476 debugFrameCrypto{ 477 data: tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake], 478 }) 479 tc.wantFrame("client closes connection due to rejecting server certificate", 480 packetTypeInitial, debugFrameConnectionCloseTransport{ 481 code: errTLSBase + 42, // 42: bad_certificate 482 }) 483 } 484 485 func TestConnHandshakeDoneSentToServer(t *testing.T) { 486 tc := newTestConn(t, serverSide) 487 tc.handshake() 488 489 tc.writeFrames(packetType1RTT, 490 debugFrameHandshakeDone{}) 491 tc.wantFrame("server closes connection when client sends a HANDSHAKE_DONE frame", 492 packetType1RTT, debugFrameConnectionCloseTransport{ 493 code: errProtocolViolation, 494 }) 495 } 496 497 func TestConnCryptoDataOutOfOrder(t *testing.T) { 498 tc := newTestConn(t, clientSide) 499 tc.ignoreFrame(frameTypeAck) 500 501 tc.wantFrame("client sends Initial CRYPTO frame", 502 packetTypeInitial, debugFrameCrypto{ 503 data: tc.cryptoDataOut[tls.QUICEncryptionLevelInitial], 504 }) 505 tc.writeFrames(packetTypeInitial, 506 debugFrameCrypto{ 507 data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial], 508 }) 509 tc.wantIdle("client is idle, server Handshake flight has not arrived") 510 511 tc.writeFrames(packetTypeHandshake, 512 debugFrameCrypto{ 513 off: 15, 514 data: tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake][15:], 515 }) 516 tc.wantIdle("client is idle, server Handshake flight is not complete") 517 518 tc.writeFrames(packetTypeHandshake, 519 debugFrameCrypto{ 520 off: 1, 521 data: tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake][1:20], 522 }) 523 tc.wantIdle("client is idle, server Handshake flight is still not complete") 524 525 tc.writeFrames(packetTypeHandshake, 526 debugFrameCrypto{ 527 data: tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake][0:1], 528 }) 529 tc.wantFrame("client sends Handshake CRYPTO frame", 530 packetTypeHandshake, debugFrameCrypto{ 531 data: tc.cryptoDataOut[tls.QUICEncryptionLevelHandshake], 532 }) 533 } 534 535 func TestConnCryptoBufferSizeExceeded(t *testing.T) { 536 tc := newTestConn(t, clientSide) 537 tc.ignoreFrame(frameTypeAck) 538 539 tc.wantFrame("client sends Initial CRYPTO frame", 540 packetTypeInitial, debugFrameCrypto{ 541 data: tc.cryptoDataOut[tls.QUICEncryptionLevelInitial], 542 }) 543 tc.writeFrames(packetTypeInitial, 544 debugFrameCrypto{ 545 off: cryptoBufferSize, 546 data: []byte{0}, 547 }) 548 tc.wantFrame("client closes connection after server exceeds CRYPTO buffer", 549 packetTypeInitial, debugFrameConnectionCloseTransport{ 550 code: errCryptoBufferExceeded, 551 }) 552 } 553 554 func TestConnAEADLimitReached(t *testing.T) { 555 // "[...] endpoints MUST count the number of received packets that 556 // fail authentication during the lifetime of a connection. 557 // If the total number of received packets that fail authentication [...] 558 // exceeds the integrity limit for the selected AEAD, 559 // the endpoint MUST immediately close the connection [...]" 560 // https://www.rfc-editor.org/rfc/rfc9001#section-6.6-6 561 tc := newTestConn(t, clientSide, func(c *Config) { 562 clear(c.StatelessResetKey[:]) 563 }) 564 tc.handshake() 565 566 var limit int64 567 switch suite := tc.conn.keysAppData.r.suite; suite { 568 case tls.TLS_AES_128_GCM_SHA256, tls.TLS_AES_256_GCM_SHA384: 569 limit = 1 << 52 570 case tls.TLS_CHACHA20_POLY1305_SHA256: 571 limit = 1 << 36 572 default: 573 t.Fatalf("conn.keysAppData.r.suite = %v, unknown suite", suite) 574 } 575 576 dstConnID := tc.conn.connIDState.local[0].cid 577 if tc.conn.connIDState.local[0].seq == -1 { 578 // Only use the transient connection ID in Initial packets. 579 dstConnID = tc.conn.connIDState.local[1].cid 580 } 581 invalid := encodeTestPacket(t, tc, &testPacket{ 582 ptype: packetType1RTT, 583 num: 1000, 584 frames: []debugFrame{debugFramePing{}}, 585 version: quicVersion1, 586 dstConnID: dstConnID, 587 srcConnID: tc.peerConnID, 588 }, 0) 589 invalid[len(invalid)-1] ^= 1 590 sendInvalid := func() { 591 t.Logf("<- conn under test receives invalid datagram") 592 tc.conn.sendMsg(&datagram{ 593 b: invalid, 594 }) 595 tc.wait() 596 } 597 598 // Set the conn's auth failure count to just before the AEAD integrity limit. 599 tc.conn.keysAppData.authFailures = limit - 1 600 601 tc.writeFrames(packetType1RTT, debugFramePing{}) 602 tc.advanceToTimer() 603 tc.wantFrameType("auth failures less than limit: conn ACKs packet", 604 packetType1RTT, debugFrameAck{}) 605 606 sendInvalid() 607 tc.writeFrames(packetType1RTT, debugFramePing{}) 608 tc.advanceToTimer() 609 tc.wantFrameType("auth failures at limit: conn closes", 610 packetType1RTT, debugFrameConnectionCloseTransport{ 611 code: errAEADLimitReached, 612 }) 613 614 tc.writeFrames(packetType1RTT, debugFramePing{}) 615 tc.advance(1 * time.Second) 616 tc.wantIdle("auth failures at limit: conn does not process additional packets") 617 }