github.com/fjballest/golang@v0.0.0-20151209143359-e4c5fe594ca8/src/crypto/tls/handshake_client_test.go (about) 1 // Copyright 2010 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 package tls 6 7 import ( 8 "bytes" 9 "crypto/ecdsa" 10 "crypto/rsa" 11 "crypto/x509" 12 "encoding/base64" 13 "encoding/binary" 14 "encoding/pem" 15 "fmt" 16 "io" 17 "net" 18 "os" 19 "os/exec" 20 "path/filepath" 21 "strconv" 22 "strings" 23 "testing" 24 "time" 25 ) 26 27 // Note: see comment in handshake_test.go for details of how the reference 28 // tests work. 29 30 // blockingSource is an io.Reader that blocks a Read call until it's closed. 31 type blockingSource chan bool 32 33 func (b blockingSource) Read([]byte) (n int, err error) { 34 <-b 35 return 0, io.EOF 36 } 37 38 // clientTest represents a test of the TLS client handshake against a reference 39 // implementation. 40 type clientTest struct { 41 // name is a freeform string identifying the test and the file in which 42 // the expected results will be stored. 43 name string 44 // command, if not empty, contains a series of arguments for the 45 // command to run for the reference server. 46 command []string 47 // config, if not nil, contains a custom Config to use for this test. 48 config *Config 49 // cert, if not empty, contains a DER-encoded certificate for the 50 // reference server. 51 cert []byte 52 // key, if not nil, contains either a *rsa.PrivateKey or 53 // *ecdsa.PrivateKey which is the private key for the reference server. 54 key interface{} 55 // extensions, if not nil, contains a list of extension data to be returned 56 // from the ServerHello. The data should be in standard TLS format with 57 // a 2-byte uint16 type, 2-byte data length, followed by the extension data. 58 extensions [][]byte 59 // validate, if not nil, is a function that will be called with the 60 // ConnectionState of the resulting connection. It returns a non-nil 61 // error if the ConnectionState is unacceptable. 62 validate func(ConnectionState) error 63 } 64 65 var defaultServerCommand = []string{"openssl", "s_server"} 66 67 // connFromCommand starts the reference server process, connects to it and 68 // returns a recordingConn for the connection. The stdin return value is a 69 // blockingSource for the stdin of the child process. It must be closed before 70 // Waiting for child. 71 func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, stdin blockingSource, err error) { 72 cert := testRSACertificate 73 if len(test.cert) > 0 { 74 cert = test.cert 75 } 76 certPath := tempFile(string(cert)) 77 defer os.Remove(certPath) 78 79 var key interface{} = testRSAPrivateKey 80 if test.key != nil { 81 key = test.key 82 } 83 var pemType string 84 var derBytes []byte 85 switch key := key.(type) { 86 case *rsa.PrivateKey: 87 pemType = "RSA" 88 derBytes = x509.MarshalPKCS1PrivateKey(key) 89 case *ecdsa.PrivateKey: 90 pemType = "EC" 91 var err error 92 derBytes, err = x509.MarshalECPrivateKey(key) 93 if err != nil { 94 panic(err) 95 } 96 default: 97 panic("unknown key type") 98 } 99 100 var pemOut bytes.Buffer 101 pem.Encode(&pemOut, &pem.Block{Type: pemType + " PRIVATE KEY", Bytes: derBytes}) 102 103 keyPath := tempFile(string(pemOut.Bytes())) 104 defer os.Remove(keyPath) 105 106 var command []string 107 if len(test.command) > 0 { 108 command = append(command, test.command...) 109 } else { 110 command = append(command, defaultServerCommand...) 111 } 112 command = append(command, "-cert", certPath, "-certform", "DER", "-key", keyPath) 113 // serverPort contains the port that OpenSSL will listen on. OpenSSL 114 // can't take "0" as an argument here so we have to pick a number and 115 // hope that it's not in use on the machine. Since this only occurs 116 // when -update is given and thus when there's a human watching the 117 // test, this isn't too bad. 118 const serverPort = 24323 119 command = append(command, "-accept", strconv.Itoa(serverPort)) 120 121 if len(test.extensions) > 0 { 122 var serverInfo bytes.Buffer 123 for _, ext := range test.extensions { 124 pem.Encode(&serverInfo, &pem.Block{ 125 Type: fmt.Sprintf("SERVERINFO FOR EXTENSION %d", binary.BigEndian.Uint16(ext)), 126 Bytes: ext, 127 }) 128 } 129 serverInfoPath := tempFile(serverInfo.String()) 130 defer os.Remove(serverInfoPath) 131 command = append(command, "-serverinfo", serverInfoPath) 132 } 133 134 cmd := exec.Command(command[0], command[1:]...) 135 stdin = blockingSource(make(chan bool)) 136 cmd.Stdin = stdin 137 var out bytes.Buffer 138 cmd.Stdout = &out 139 cmd.Stderr = &out 140 if err := cmd.Start(); err != nil { 141 return nil, nil, nil, err 142 } 143 144 // OpenSSL does print an "ACCEPT" banner, but it does so *before* 145 // opening the listening socket, so we can't use that to wait until it 146 // has started listening. Thus we are forced to poll until we get a 147 // connection. 148 var tcpConn net.Conn 149 for i := uint(0); i < 5; i++ { 150 tcpConn, err = net.DialTCP("tcp", nil, &net.TCPAddr{ 151 IP: net.IPv4(127, 0, 0, 1), 152 Port: serverPort, 153 }) 154 if err == nil { 155 break 156 } 157 time.Sleep((1 << i) * 5 * time.Millisecond) 158 } 159 if err != nil { 160 close(stdin) 161 out.WriteTo(os.Stdout) 162 cmd.Process.Kill() 163 return nil, nil, nil, cmd.Wait() 164 } 165 166 record := &recordingConn{ 167 Conn: tcpConn, 168 } 169 170 return record, cmd, stdin, nil 171 } 172 173 func (test *clientTest) dataPath() string { 174 return filepath.Join("testdata", "Client-"+test.name) 175 } 176 177 func (test *clientTest) loadData() (flows [][]byte, err error) { 178 in, err := os.Open(test.dataPath()) 179 if err != nil { 180 return nil, err 181 } 182 defer in.Close() 183 return parseTestData(in) 184 } 185 186 func (test *clientTest) run(t *testing.T, write bool) { 187 var clientConn, serverConn net.Conn 188 var recordingConn *recordingConn 189 var childProcess *exec.Cmd 190 var stdin blockingSource 191 192 if write { 193 var err error 194 recordingConn, childProcess, stdin, err = test.connFromCommand() 195 if err != nil { 196 t.Fatalf("Failed to start subcommand: %s", err) 197 } 198 clientConn = recordingConn 199 } else { 200 clientConn, serverConn = net.Pipe() 201 } 202 203 config := test.config 204 if config == nil { 205 config = testConfig 206 } 207 client := Client(clientConn, config) 208 209 doneChan := make(chan bool) 210 go func() { 211 if _, err := client.Write([]byte("hello\n")); err != nil { 212 t.Errorf("Client.Write failed: %s", err) 213 } 214 if test.validate != nil { 215 if err := test.validate(client.ConnectionState()); err != nil { 216 t.Errorf("validate callback returned error: %s", err) 217 } 218 } 219 client.Close() 220 clientConn.Close() 221 doneChan <- true 222 }() 223 224 if !write { 225 flows, err := test.loadData() 226 if err != nil { 227 t.Fatalf("%s: failed to load data from %s: %v", test.name, test.dataPath(), err) 228 } 229 for i, b := range flows { 230 if i%2 == 1 { 231 serverConn.Write(b) 232 continue 233 } 234 bb := make([]byte, len(b)) 235 _, err := io.ReadFull(serverConn, bb) 236 if err != nil { 237 t.Fatalf("%s #%d: %s", test.name, i, err) 238 } 239 if !bytes.Equal(b, bb) { 240 t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i, bb, b) 241 } 242 } 243 serverConn.Close() 244 } 245 246 <-doneChan 247 248 if write { 249 path := test.dataPath() 250 out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) 251 if err != nil { 252 t.Fatalf("Failed to create output file: %s", err) 253 } 254 defer out.Close() 255 recordingConn.Close() 256 close(stdin) 257 childProcess.Process.Kill() 258 childProcess.Wait() 259 if len(recordingConn.flows) < 3 { 260 childProcess.Stdout.(*bytes.Buffer).WriteTo(os.Stdout) 261 t.Fatalf("Client connection didn't work") 262 } 263 recordingConn.WriteTo(out) 264 fmt.Printf("Wrote %s\n", path) 265 } 266 } 267 268 func runClientTestForVersion(t *testing.T, template *clientTest, prefix, option string) { 269 test := *template 270 test.name = prefix + test.name 271 if len(test.command) == 0 { 272 test.command = defaultClientCommand 273 } 274 test.command = append([]string(nil), test.command...) 275 test.command = append(test.command, option) 276 test.run(t, *update) 277 } 278 279 func runClientTestTLS10(t *testing.T, template *clientTest) { 280 runClientTestForVersion(t, template, "TLSv10-", "-tls1") 281 } 282 283 func runClientTestTLS11(t *testing.T, template *clientTest) { 284 runClientTestForVersion(t, template, "TLSv11-", "-tls1_1") 285 } 286 287 func runClientTestTLS12(t *testing.T, template *clientTest) { 288 runClientTestForVersion(t, template, "TLSv12-", "-tls1_2") 289 } 290 291 func TestHandshakeClientRSARC4(t *testing.T) { 292 test := &clientTest{ 293 name: "RSA-RC4", 294 command: []string{"openssl", "s_server", "-cipher", "RC4-SHA"}, 295 } 296 runClientTestTLS10(t, test) 297 runClientTestTLS11(t, test) 298 runClientTestTLS12(t, test) 299 } 300 301 func TestHandshakeClientRSAAES128GCM(t *testing.T) { 302 test := &clientTest{ 303 name: "AES128-GCM-SHA256", 304 command: []string{"openssl", "s_server", "-cipher", "AES128-GCM-SHA256"}, 305 } 306 runClientTestTLS12(t, test) 307 } 308 309 func TestHandshakeClientRSAAES256GCM(t *testing.T) { 310 test := &clientTest{ 311 name: "AES256-GCM-SHA384", 312 command: []string{"openssl", "s_server", "-cipher", "AES256-GCM-SHA384"}, 313 } 314 runClientTestTLS12(t, test) 315 } 316 317 func TestHandshakeClientECDHERSAAES(t *testing.T) { 318 test := &clientTest{ 319 name: "ECDHE-RSA-AES", 320 command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES128-SHA"}, 321 } 322 runClientTestTLS10(t, test) 323 runClientTestTLS11(t, test) 324 runClientTestTLS12(t, test) 325 } 326 327 func TestHandshakeClientECDHEECDSAAES(t *testing.T) { 328 test := &clientTest{ 329 name: "ECDHE-ECDSA-AES", 330 command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA"}, 331 cert: testECDSACertificate, 332 key: testECDSAPrivateKey, 333 } 334 runClientTestTLS10(t, test) 335 runClientTestTLS11(t, test) 336 runClientTestTLS12(t, test) 337 } 338 339 func TestHandshakeClientECDHEECDSAAESGCM(t *testing.T) { 340 test := &clientTest{ 341 name: "ECDHE-ECDSA-AES-GCM", 342 command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-GCM-SHA256"}, 343 cert: testECDSACertificate, 344 key: testECDSAPrivateKey, 345 } 346 runClientTestTLS12(t, test) 347 } 348 349 func TestHandshakeClientAES256GCMSHA384(t *testing.T) { 350 test := &clientTest{ 351 name: "ECDHE-ECDSA-AES256-GCM-SHA384", 352 command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES256-GCM-SHA384"}, 353 cert: testECDSACertificate, 354 key: testECDSAPrivateKey, 355 } 356 runClientTestTLS12(t, test) 357 } 358 359 func TestHandshakeClientCertRSA(t *testing.T) { 360 config := *testConfig 361 cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM)) 362 config.Certificates = []Certificate{cert} 363 364 test := &clientTest{ 365 name: "ClientCert-RSA-RSA", 366 command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"}, 367 config: &config, 368 } 369 370 runClientTestTLS10(t, test) 371 runClientTestTLS12(t, test) 372 373 test = &clientTest{ 374 name: "ClientCert-RSA-ECDSA", 375 command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"}, 376 config: &config, 377 cert: testECDSACertificate, 378 key: testECDSAPrivateKey, 379 } 380 381 runClientTestTLS10(t, test) 382 runClientTestTLS12(t, test) 383 384 test = &clientTest{ 385 name: "ClientCert-RSA-AES256-GCM-SHA384", 386 command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES256-GCM-SHA384", "-verify", "1"}, 387 config: &config, 388 cert: testRSACertificate, 389 key: testRSAPrivateKey, 390 } 391 392 runClientTestTLS12(t, test) 393 } 394 395 func TestHandshakeClientCertECDSA(t *testing.T) { 396 config := *testConfig 397 cert, _ := X509KeyPair([]byte(clientECDSACertificatePEM), []byte(clientECDSAKeyPEM)) 398 config.Certificates = []Certificate{cert} 399 400 test := &clientTest{ 401 name: "ClientCert-ECDSA-RSA", 402 command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"}, 403 config: &config, 404 } 405 406 runClientTestTLS10(t, test) 407 runClientTestTLS12(t, test) 408 409 test = &clientTest{ 410 name: "ClientCert-ECDSA-ECDSA", 411 command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"}, 412 config: &config, 413 cert: testECDSACertificate, 414 key: testECDSAPrivateKey, 415 } 416 417 runClientTestTLS10(t, test) 418 runClientTestTLS12(t, test) 419 } 420 421 func TestClientResumption(t *testing.T) { 422 serverConfig := &Config{ 423 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA}, 424 Certificates: testConfig.Certificates, 425 } 426 427 issuer, err := x509.ParseCertificate(testRSACertificateIssuer) 428 if err != nil { 429 panic(err) 430 } 431 432 rootCAs := x509.NewCertPool() 433 rootCAs.AddCert(issuer) 434 435 clientConfig := &Config{ 436 CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, 437 ClientSessionCache: NewLRUClientSessionCache(32), 438 RootCAs: rootCAs, 439 ServerName: "example.golang", 440 } 441 442 testResumeState := func(test string, didResume bool) { 443 _, hs, err := testHandshake(clientConfig, serverConfig) 444 if err != nil { 445 t.Fatalf("%s: handshake failed: %s", test, err) 446 } 447 if hs.DidResume != didResume { 448 t.Fatalf("%s resumed: %v, expected: %v", test, hs.DidResume, didResume) 449 } 450 if didResume && (hs.PeerCertificates == nil || hs.VerifiedChains == nil) { 451 t.Fatalf("expected non-nil certificates after resumption. Got peerCertificates: %#v, verifedCertificates: %#v", hs.PeerCertificates, hs.VerifiedChains) 452 } 453 } 454 455 getTicket := func() []byte { 456 return clientConfig.ClientSessionCache.(*lruSessionCache).q.Front().Value.(*lruSessionCacheEntry).state.sessionTicket 457 } 458 randomKey := func() [32]byte { 459 var k [32]byte 460 if _, err := io.ReadFull(serverConfig.rand(), k[:]); err != nil { 461 t.Fatalf("Failed to read new SessionTicketKey: %s", err) 462 } 463 return k 464 } 465 466 testResumeState("Handshake", false) 467 ticket := getTicket() 468 testResumeState("Resume", true) 469 if !bytes.Equal(ticket, getTicket()) { 470 t.Fatal("first ticket doesn't match ticket after resumption") 471 } 472 473 key2 := randomKey() 474 serverConfig.SetSessionTicketKeys([][32]byte{key2}) 475 476 testResumeState("InvalidSessionTicketKey", false) 477 testResumeState("ResumeAfterInvalidSessionTicketKey", true) 478 479 serverConfig.SetSessionTicketKeys([][32]byte{randomKey(), key2}) 480 ticket = getTicket() 481 testResumeState("KeyChange", true) 482 if bytes.Equal(ticket, getTicket()) { 483 t.Fatal("new ticket wasn't included while resuming") 484 } 485 testResumeState("KeyChangeFinish", true) 486 487 clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA} 488 testResumeState("DifferentCipherSuite", false) 489 testResumeState("DifferentCipherSuiteRecovers", true) 490 491 clientConfig.ClientSessionCache = nil 492 testResumeState("WithoutSessionCache", false) 493 } 494 495 func TestLRUClientSessionCache(t *testing.T) { 496 // Initialize cache of capacity 4. 497 cache := NewLRUClientSessionCache(4) 498 cs := make([]ClientSessionState, 6) 499 keys := []string{"0", "1", "2", "3", "4", "5", "6"} 500 501 // Add 4 entries to the cache and look them up. 502 for i := 0; i < 4; i++ { 503 cache.Put(keys[i], &cs[i]) 504 } 505 for i := 0; i < 4; i++ { 506 if s, ok := cache.Get(keys[i]); !ok || s != &cs[i] { 507 t.Fatalf("session cache failed lookup for added key: %s", keys[i]) 508 } 509 } 510 511 // Add 2 more entries to the cache. First 2 should be evicted. 512 for i := 4; i < 6; i++ { 513 cache.Put(keys[i], &cs[i]) 514 } 515 for i := 0; i < 2; i++ { 516 if s, ok := cache.Get(keys[i]); ok || s != nil { 517 t.Fatalf("session cache should have evicted key: %s", keys[i]) 518 } 519 } 520 521 // Touch entry 2. LRU should evict 3 next. 522 cache.Get(keys[2]) 523 cache.Put(keys[0], &cs[0]) 524 if s, ok := cache.Get(keys[3]); ok || s != nil { 525 t.Fatalf("session cache should have evicted key 3") 526 } 527 528 // Update entry 0 in place. 529 cache.Put(keys[0], &cs[3]) 530 if s, ok := cache.Get(keys[0]); !ok || s != &cs[3] { 531 t.Fatalf("session cache failed update for key 0") 532 } 533 534 // Adding a nil entry is valid. 535 cache.Put(keys[0], nil) 536 if s, ok := cache.Get(keys[0]); !ok || s != nil { 537 t.Fatalf("failed to add nil entry to cache") 538 } 539 } 540 541 func TestHandshakeClientALPNMatch(t *testing.T) { 542 config := *testConfig 543 config.NextProtos = []string{"proto2", "proto1"} 544 545 test := &clientTest{ 546 name: "ALPN", 547 // Note that this needs OpenSSL 1.0.2 because that is the first 548 // version that supports the -alpn flag. 549 command: []string{"openssl", "s_server", "-alpn", "proto1,proto2"}, 550 config: &config, 551 validate: func(state ConnectionState) error { 552 // The server's preferences should override the client. 553 if state.NegotiatedProtocol != "proto1" { 554 return fmt.Errorf("Got protocol %q, wanted proto1", state.NegotiatedProtocol) 555 } 556 return nil 557 }, 558 } 559 runClientTestTLS12(t, test) 560 } 561 562 func TestHandshakeClientALPNNoMatch(t *testing.T) { 563 config := *testConfig 564 config.NextProtos = []string{"proto3"} 565 566 test := &clientTest{ 567 name: "ALPN-NoMatch", 568 // Note that this needs OpenSSL 1.0.2 because that is the first 569 // version that supports the -alpn flag. 570 command: []string{"openssl", "s_server", "-alpn", "proto1,proto2"}, 571 config: &config, 572 validate: func(state ConnectionState) error { 573 // There's no overlap so OpenSSL will not select a protocol. 574 if state.NegotiatedProtocol != "" { 575 return fmt.Errorf("Got protocol %q, wanted ''", state.NegotiatedProtocol) 576 } 577 return nil 578 }, 579 } 580 runClientTestTLS12(t, test) 581 } 582 583 // sctsBase64 contains data from `openssl s_client -serverinfo 18 -connect ritter.vg:443` 584 const sctsBase64 = "ABIBaQFnAHUApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFHl5nuFgAABAMARjBEAiAcS4JdlW5nW9sElUv2zvQyPoZ6ejKrGGB03gjaBZFMLwIgc1Qbbn+hsH0RvObzhS+XZhr3iuQQJY8S9G85D9KeGPAAdgBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUeX4bVwAAAEAwBHMEUCIDIhFDgG2HIuADBkGuLobU5a4dlCHoJLliWJ1SYT05z6AiEAjxIoZFFPRNWMGGIjskOTMwXzQ1Wh2e7NxXE1kd1J0QsAdgDuS723dc5guuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAUhcZIqHAAAEAwBHMEUCICmJ1rBT09LpkbzxtUC+Hi7nXLR0J+2PmwLp+sJMuqK+AiEAr0NkUnEVKVhAkccIFpYDqHOlZaBsuEhWWrYpg2RtKp0=" 585 586 func TestHandshakClientSCTs(t *testing.T) { 587 config := *testConfig 588 589 scts, err := base64.StdEncoding.DecodeString(sctsBase64) 590 if err != nil { 591 t.Fatal(err) 592 } 593 594 test := &clientTest{ 595 name: "SCT", 596 // Note that this needs OpenSSL 1.0.2 because that is the first 597 // version that supports the -serverinfo flag. 598 command: []string{"openssl", "s_server"}, 599 config: &config, 600 extensions: [][]byte{scts}, 601 validate: func(state ConnectionState) error { 602 expectedSCTs := [][]byte{ 603 scts[8:125], 604 scts[127:245], 605 scts[247:], 606 } 607 if n := len(state.SignedCertificateTimestamps); n != len(expectedSCTs) { 608 return fmt.Errorf("Got %d scts, wanted %d", n, len(expectedSCTs)) 609 } 610 for i, expected := range expectedSCTs { 611 if sct := state.SignedCertificateTimestamps[i]; !bytes.Equal(sct, expected) { 612 return fmt.Errorf("SCT #%d contained %x, expected %x", i, sct, expected) 613 } 614 } 615 return nil 616 }, 617 } 618 runClientTestTLS12(t, test) 619 } 620 621 func TestNoIPAddressesInSNI(t *testing.T) { 622 for _, ipLiteral := range []string{"1.2.3.4", "::1"} { 623 c, s := net.Pipe() 624 625 go func() { 626 client := Client(c, &Config{ServerName: ipLiteral}) 627 client.Handshake() 628 }() 629 630 var header [5]byte 631 if _, err := io.ReadFull(s, header[:]); err != nil { 632 t.Fatal(err) 633 } 634 recordLen := int(header[3])<<8 | int(header[4]) 635 636 record := make([]byte, recordLen) 637 if _, err := io.ReadFull(s, record[:]); err != nil { 638 t.Fatal(err) 639 } 640 s.Close() 641 642 if bytes.Index(record, []byte(ipLiteral)) != -1 { 643 t.Errorf("IP literal %q found in ClientHello: %x", ipLiteral, record) 644 } 645 } 646 } 647 648 func TestServerSelectingUnconfiguredCipherSuite(t *testing.T) { 649 // This checks that the server can't select a cipher suite that the 650 // client didn't offer. See #13174. 651 652 c, s := net.Pipe() 653 errChan := make(chan error, 1) 654 655 go func() { 656 client := Client(c, &Config{ 657 ServerName: "foo", 658 CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, 659 }) 660 errChan <- client.Handshake() 661 }() 662 663 var header [5]byte 664 if _, err := io.ReadFull(s, header[:]); err != nil { 665 t.Fatal(err) 666 } 667 recordLen := int(header[3])<<8 | int(header[4]) 668 669 record := make([]byte, recordLen) 670 if _, err := io.ReadFull(s, record); err != nil { 671 t.Fatal(err) 672 } 673 674 // Create a ServerHello that selects a different cipher suite than the 675 // sole one that the client offered. 676 serverHello := &serverHelloMsg{ 677 vers: VersionTLS12, 678 random: make([]byte, 32), 679 cipherSuite: TLS_RSA_WITH_AES_256_GCM_SHA384, 680 } 681 serverHelloBytes := serverHello.marshal() 682 683 s.Write([]byte{ 684 byte(recordTypeHandshake), 685 byte(VersionTLS12 >> 8), 686 byte(VersionTLS12 & 0xff), 687 byte(len(serverHelloBytes) >> 8), 688 byte(len(serverHelloBytes)), 689 }) 690 s.Write(serverHelloBytes) 691 s.Close() 692 693 if err := <-errChan; !strings.Contains(err.Error(), "unconfigured cipher") { 694 t.Fatalf("Expected error about unconfigured cipher suite but got %q", err) 695 } 696 }