diff options
Diffstat (limited to 'src/crypto/tls/handshake_server_test.go')
| -rw-r--r-- | src/crypto/tls/handshake_server_test.go | 358 |
1 files changed, 335 insertions, 23 deletions
diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go index a7a5324312..ad851b6edf 100644 --- a/src/crypto/tls/handshake_server_test.go +++ b/src/crypto/tls/handshake_server_test.go @@ -6,6 +6,7 @@ package tls import ( "bytes" + "context" "crypto" "crypto/elliptic" "crypto/x509" @@ -17,9 +18,12 @@ import ( "os" "os/exec" "path/filepath" + "runtime" "strings" "testing" "time" + + "golang.org/x/crypto/curve25519" ) func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) { @@ -36,10 +40,12 @@ func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessa cli.writeRecord(recordTypeHandshake, m.marshal()) c.Close() }() + ctx := context.Background() conn := Server(s, serverConfig) - ch, err := conn.readClientHello() + ch, err := conn.readClientHello(ctx) hs := serverHandshakeState{ c: conn, + ctx: ctx, clientHello: ch, } if err == nil { @@ -852,7 +858,7 @@ func TestHandshakeServerX25519(t *testing.T) { test := &serverTest{ name: "X25519", - command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES128-GCM-SHA256", "-curves", "X25519"}, + command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256", "-curves", "X25519"}, config: config, } runServerTestTLS12(t, test) @@ -865,7 +871,7 @@ func TestHandshakeServerP256(t *testing.T) { test := &serverTest{ name: "P256", - command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES128-GCM-SHA256", "-curves", "P-256"}, + command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256", "-curves", "P-256"}, config: config, } runServerTestTLS12(t, test) @@ -878,7 +884,7 @@ func TestHandshakeServerHelloRetryRequest(t *testing.T) { test := &serverTest{ name: "HelloRetryRequest", - command: []string{"openssl", "s_client", "-no_ticket", "-curves", "X25519:P-256"}, + command: []string{"openssl", "s_client", "-no_ticket", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256", "-curves", "X25519:P-256"}, config: config, } runServerTestTLS13(t, test) @@ -892,7 +898,7 @@ func TestHandshakeServerALPN(t *testing.T) { name: "ALPN", // Note that this needs OpenSSL 1.0.2 because that is the first // version that supports the -alpn flag. - command: []string{"openssl", "s_client", "-alpn", "proto2,proto1"}, + command: []string{"openssl", "s_client", "-alpn", "proto2,proto1", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"}, config: config, validate: func(state ConnectionState) error { // The server's preferences should override the client. @@ -914,7 +920,7 @@ func TestHandshakeServerALPNNoMatch(t *testing.T) { name: "ALPN-NoMatch", // Note that this needs OpenSSL 1.0.2 because that is the first // version that supports the -alpn flag. - command: []string{"openssl", "s_client", "-alpn", "proto2,proto1"}, + command: []string{"openssl", "s_client", "-alpn", "proto2,proto1", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"}, config: config, validate: func(state ConnectionState) error { // Rather than reject the connection, Go doesn't select @@ -1067,12 +1073,12 @@ func TestServerResumption(t *testing.T) { testIssue := &serverTest{ name: "IssueTicket", - command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-sess_out", sessionFilePath}, + command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256", "-sess_out", sessionFilePath}, wait: true, } testResume := &serverTest{ name: "Resume", - command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-sess_in", sessionFilePath}, + command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256", "-sess_in", sessionFilePath}, validate: func(state ConnectionState) error { if !state.DidResume { return errors.New("did not resume") @@ -1091,9 +1097,10 @@ func TestServerResumption(t *testing.T) { config.CurvePreferences = []CurveID{CurveP256} testResumeHRR := &serverTest{ - name: "Resume-HelloRetryRequest", - command: []string{"openssl", "s_client", "-curves", "X25519:P-256", "-sess_in", sessionFilePath}, - config: config, + name: "Resume-HelloRetryRequest", + command: []string{"openssl", "s_client", "-curves", "X25519:P-256", "-cipher", "AES128-SHA", "-ciphersuites", + "TLS_AES_128_GCM_SHA256", "-sess_in", sessionFilePath}, + config: config, validate: func(state ConnectionState) error { if !state.DidResume { return errors.New("did not resume") @@ -1113,13 +1120,13 @@ func TestServerResumptionDisabled(t *testing.T) { testIssue := &serverTest{ name: "IssueTicketPreDisable", - command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-sess_out", sessionFilePath}, + command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256", "-sess_out", sessionFilePath}, config: config, wait: true, } testResume := &serverTest{ name: "ResumeDisabled", - command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-sess_in", sessionFilePath}, + command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256", "-sess_in", sessionFilePath}, config: config, validate: func(state ConnectionState) error { if state.DidResume { @@ -1157,7 +1164,7 @@ func TestFallbackSCSV(t *testing.T) { func TestHandshakeServerExportKeyingMaterial(t *testing.T) { test := &serverTest{ name: "ExportKeyingMaterial", - command: []string{"openssl", "s_client"}, + command: []string{"openssl", "s_client", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"}, config: testConfig.Clone(), validate: func(state ConnectionState) error { if km, err := state.ExportKeyingMaterial("test", nil, 42); err != nil { @@ -1176,7 +1183,7 @@ func TestHandshakeServerExportKeyingMaterial(t *testing.T) { func TestHandshakeServerRSAPKCS1v15(t *testing.T) { test := &serverTest{ name: "RSA-RSAPKCS1v15", - command: []string{"openssl", "s_client", "-no_ticket", "-sigalgs", "rsa_pkcs1_sha256"}, + command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-sigalgs", "rsa_pkcs1_sha256"}, } runServerTestTLS12(t, test) } @@ -1187,14 +1194,14 @@ func TestHandshakeServerRSAPSS(t *testing.T) { // that case. See Issue 29793. test := &serverTest{ name: "RSA-RSAPSS", - command: []string{"openssl", "s_client", "-no_ticket", "-sigalgs", "rsa_pss_rsae_sha512:rsa_pss_rsae_sha256"}, + command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256", "-sigalgs", "rsa_pss_rsae_sha512:rsa_pss_rsae_sha256"}, } runServerTestTLS12(t, test) runServerTestTLS13(t, test) test = &serverTest{ name: "RSA-RSAPSS-TooSmall", - command: []string{"openssl", "s_client", "-no_ticket", "-sigalgs", "rsa_pss_rsae_sha512"}, + command: []string{"openssl", "s_client", "-no_ticket", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256", "-sigalgs", "rsa_pss_rsae_sha512"}, expectHandshakeErrorIncluding: "peer doesn't support any of the certificate's signature algorithms", } runServerTestTLS13(t, test) @@ -1209,7 +1216,7 @@ func TestHandshakeServerEd25519(t *testing.T) { test := &serverTest{ name: "Ed25519", - command: []string{"openssl", "s_client", "-no_ticket"}, + command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-ECDSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"}, config: config, } runServerTestTLS12(t, test) @@ -1349,7 +1356,7 @@ func TestClientAuth(t *testing.T) { test := &serverTest{ name: "ClientAuthRequestedNotGiven", - command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA"}, + command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256"}, config: config, } runServerTestTLS12(t, test) @@ -1357,7 +1364,7 @@ func TestClientAuth(t *testing.T) { test = &serverTest{ name: "ClientAuthRequestedAndGiven", - command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", + command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256", "-cert", certPath, "-key", keyPath, "-client_sigalgs", "rsa_pss_rsae_sha256"}, config: config, expectedPeerCerts: []string{clientCertificatePEM}, @@ -1367,7 +1374,7 @@ func TestClientAuth(t *testing.T) { test = &serverTest{ name: "ClientAuthRequestedAndECDSAGiven", - command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", + command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256", "-cert", ecdsaCertPath, "-key", ecdsaKeyPath}, config: config, expectedPeerCerts: []string{clientECDSACertificatePEM}, @@ -1377,7 +1384,7 @@ func TestClientAuth(t *testing.T) { test = &serverTest{ name: "ClientAuthRequestedAndEd25519Given", - command: []string{"openssl", "s_client", "-no_ticket", + command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256", "-cert", ed25519CertPath, "-key", ed25519KeyPath}, config: config, expectedPeerCerts: []string{clientEd25519CertificatePEM}, @@ -1418,9 +1425,11 @@ func TestSNIGivenOnFailure(t *testing.T) { c.Close() }() conn := Server(s, serverConfig) - ch, err := conn.readClientHello() + ctx := context.Background() + ch, err := conn.readClientHello(ctx) hs := serverHandshakeState{ c: conn, + ctx: ctx, clientHello: ch, } if err == nil { @@ -1673,3 +1682,306 @@ func TestMultipleCertificates(t *testing.T) { t.Errorf("expected RSA certificate, got %v", got) } } + +func TestServerHandshakeContextCancellation(t *testing.T) { + c, s := localPipe(t) + clientConfig := testConfig.Clone() + clientErr := make(chan error, 1) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go func() { + defer close(clientErr) + defer c.Close() + clientHello := &clientHelloMsg{ + vers: VersionTLS10, + random: make([]byte, 32), + cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + compressionMethods: []uint8{compressionNone}, + } + cli := Client(c, clientConfig) + _, err := cli.writeRecord(recordTypeHandshake, clientHello.marshal()) + cancel() + clientErr <- err + }() + conn := Server(s, testConfig) + err := conn.HandshakeContext(ctx) + if err == nil { + t.Fatal("Server handshake did not error when the context was canceled") + } + if err != context.Canceled { + t.Errorf("Unexpected server handshake error: %v", err) + } + if err := <-clientErr; err != nil { + t.Errorf("Unexpected client error: %v", err) + } + if runtime.GOARCH == "wasm" { + t.Skip("conn.Close does not error as expected when called multiple times on WASM") + } + err = conn.Close() + if err == nil { + t.Error("Server connection was not closed when the context was canceled") + } +} + +func TestAESCipherReordering(t *testing.T) { + currentAESSupport := hasAESGCMHardwareSupport + defer func() { hasAESGCMHardwareSupport = currentAESSupport; initDefaultCipherSuites() }() + + tests := []struct { + name string + clientCiphers []uint16 + serverHasAESGCM bool + preferServerCipherSuites bool + serverCiphers []uint16 + expectedCipher uint16 + }{ + { + name: "server has hardware AES, client doesn't (pick ChaCha)", + clientCiphers: []uint16{ + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_128_CBC_SHA, + }, + serverHasAESGCM: true, + preferServerCipherSuites: true, + expectedCipher: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + }, + { + name: "server strongly prefers AES-GCM, client doesn't (pick AES-GCM)", + clientCiphers: []uint16{ + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_128_CBC_SHA, + }, + serverHasAESGCM: true, + preferServerCipherSuites: true, + serverCiphers: []uint16{ + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + TLS_RSA_WITH_AES_128_CBC_SHA, + }, + expectedCipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + }, + { + name: "client prefers AES-GCM, server doesn't have hardware AES (pick ChaCha)", + clientCiphers: []uint16{ + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + TLS_RSA_WITH_AES_128_CBC_SHA, + }, + serverHasAESGCM: false, + expectedCipher: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + }, + { + name: "client prefers AES-GCM, server has hardware AES (pick AES-GCM)", + clientCiphers: []uint16{ + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + TLS_RSA_WITH_AES_128_CBC_SHA, + }, + serverHasAESGCM: true, + expectedCipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + }, + { + name: "client prefers AES-GCM and sends GREASE, server has hardware AES (pick AES-GCM)", + clientCiphers: []uint16{ + 0x0A0A, // GREASE value + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + TLS_RSA_WITH_AES_128_CBC_SHA, + }, + serverHasAESGCM: true, + expectedCipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + }, + { + name: "client prefers AES-GCM and doesn't support ChaCha, server doesn't have hardware AES (pick AES-GCM)", + clientCiphers: []uint16{ + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_128_CBC_SHA, + }, + serverHasAESGCM: false, + expectedCipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + }, + { + name: "client prefers AES-GCM and AES-CBC over ChaCha, server doesn't have hardware AES (pick AES-GCM)", + clientCiphers: []uint16{ + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + }, + serverHasAESGCM: false, + expectedCipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + }, + { + name: "client prefers AES-GCM over ChaCha and sends GREASE, server doesn't have hardware AES (pick ChaCha)", + clientCiphers: []uint16{ + 0x0A0A, // GREASE value + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + TLS_RSA_WITH_AES_128_CBC_SHA, + }, + serverHasAESGCM: false, + expectedCipher: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + }, + { + name: "client supports multiple AES-GCM, server doesn't have hardware AES and doesn't support ChaCha (pick corrent AES-GCM)", + clientCiphers: []uint16{ + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + }, + serverHasAESGCM: false, + serverCiphers: []uint16{ + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + }, + expectedCipher: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + hasAESGCMHardwareSupport = tc.serverHasAESGCM + initDefaultCipherSuites() + hs := &serverHandshakeState{ + c: &Conn{ + config: &Config{ + PreferServerCipherSuites: tc.preferServerCipherSuites, + CipherSuites: tc.serverCiphers, + }, + vers: VersionTLS12, + }, + clientHello: &clientHelloMsg{ + cipherSuites: tc.clientCiphers, + vers: VersionTLS12, + }, + ecdheOk: true, + rsaSignOk: true, + rsaDecryptOk: true, + } + + err := hs.pickCipherSuite() + if err != nil { + t.Errorf("pickCipherSuite failed: %s", err) + } + + if tc.expectedCipher != hs.suite.id { + t.Errorf("unexpected cipher chosen: want %d, got %d", tc.expectedCipher, hs.suite.id) + } + }) + } +} + +func TestAESCipherReordering13(t *testing.T) { + currentAESSupport := hasAESGCMHardwareSupport + defer func() { hasAESGCMHardwareSupport = currentAESSupport; initDefaultCipherSuites() }() + + tests := []struct { + name string + clientCiphers []uint16 + serverHasAESGCM bool + preferServerCipherSuites bool + expectedCipher uint16 + }{ + { + name: "server has hardware AES, client doesn't (pick ChaCha)", + clientCiphers: []uint16{ + TLS_CHACHA20_POLY1305_SHA256, + TLS_AES_128_GCM_SHA256, + }, + serverHasAESGCM: true, + preferServerCipherSuites: true, + expectedCipher: TLS_CHACHA20_POLY1305_SHA256, + }, + { + name: "neither server nor client have hardware AES (pick ChaCha)", + clientCiphers: []uint16{ + TLS_CHACHA20_POLY1305_SHA256, + TLS_AES_128_GCM_SHA256, + }, + serverHasAESGCM: false, + preferServerCipherSuites: true, + expectedCipher: TLS_CHACHA20_POLY1305_SHA256, + }, + { + name: "client prefers AES, server doesn't have hardware, prefer server ciphers (pick ChaCha)", + clientCiphers: []uint16{ + TLS_AES_128_GCM_SHA256, + TLS_CHACHA20_POLY1305_SHA256, + }, + serverHasAESGCM: false, + preferServerCipherSuites: true, + expectedCipher: TLS_CHACHA20_POLY1305_SHA256, + }, + { + name: "client prefers AES and sends GREASE, server doesn't have hardware, prefer server ciphers (pick ChaCha)", + clientCiphers: []uint16{ + 0x0A0A, // GREASE value + TLS_AES_128_GCM_SHA256, + TLS_CHACHA20_POLY1305_SHA256, + }, + serverHasAESGCM: false, + preferServerCipherSuites: true, + expectedCipher: TLS_CHACHA20_POLY1305_SHA256, + }, + { + name: "client prefers AES, server doesn't (pick ChaCha)", + clientCiphers: []uint16{ + TLS_AES_128_GCM_SHA256, + TLS_CHACHA20_POLY1305_SHA256, + }, + serverHasAESGCM: false, + expectedCipher: TLS_CHACHA20_POLY1305_SHA256, + }, + { + name: "client prefers AES, server has hardware AES (pick AES)", + clientCiphers: []uint16{ + TLS_AES_128_GCM_SHA256, + TLS_CHACHA20_POLY1305_SHA256, + }, + serverHasAESGCM: true, + expectedCipher: TLS_AES_128_GCM_SHA256, + }, + { + name: "client prefers AES and sends GREASE, server has hardware AES (pick AES)", + clientCiphers: []uint16{ + 0x0A0A, // GREASE value + TLS_AES_128_GCM_SHA256, + TLS_CHACHA20_POLY1305_SHA256, + }, + serverHasAESGCM: true, + expectedCipher: TLS_AES_128_GCM_SHA256, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + hasAESGCMHardwareSupport = tc.serverHasAESGCM + initDefaultCipherSuites() + hs := &serverHandshakeStateTLS13{ + c: &Conn{ + config: &Config{ + PreferServerCipherSuites: tc.preferServerCipherSuites, + }, + vers: VersionTLS13, + }, + clientHello: &clientHelloMsg{ + cipherSuites: tc.clientCiphers, + supportedVersions: []uint16{VersionTLS13}, + compressionMethods: []uint8{compressionNone}, + keyShares: []keyShare{{group: X25519, data: curve25519.Basepoint}}, + }, + } + + err := hs.processClientHello() + if err != nil { + t.Errorf("pickCipherSuite failed: %s", err) + } + + if tc.expectedCipher != hs.suite.id { + t.Errorf("unexpected cipher chosen: want %d, got %d", tc.expectedCipher, hs.suite.id) + } + }) + } +} |
