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.
24 // Note: see comment in handshake_test.go for details of how the reference
27 // blockingSource is an io.Reader that blocks a Read call until it's closed.
28 type blockingSource
chan bool
30 func (b blockingSource
) Read([]byte) (n
int, err error
) {
35 // clientTest represents a test of the TLS client handshake against a reference
37 type clientTest
struct {
38 // name is a freeform string identifying the test and the file in which
39 // the expected results will be stored.
41 // command, if not empty, contains a series of arguments for the
42 // command to run for the reference server.
44 // config, if not nil, contains a custom Config to use for this test.
46 // cert, if not empty, contains a DER-encoded certificate for the
49 // key, if not nil, contains either a *rsa.PrivateKey or
50 // *ecdsa.PrivateKey which is the private key for the reference server.
54 var defaultServerCommand
= []string{"openssl", "s_server"}
56 // connFromCommand starts the reference server process, connects to it and
57 // returns a recordingConn for the connection. The stdin return value is a
58 // blockingSource for the stdin of the child process. It must be closed before
60 func (test
*clientTest
) connFromCommand() (conn
*recordingConn
, child
*exec
.Cmd
, stdin blockingSource
, err error
) {
61 cert
:= testRSACertificate
62 if len(test
.cert
) > 0 {
65 certPath
:= tempFile(string(cert
))
66 defer os
.Remove(certPath
)
68 var key
interface{} = testRSAPrivateKey
74 switch key
:= key
.(type) {
77 derBytes
= x509
.MarshalPKCS1PrivateKey(key
)
78 case *ecdsa
.PrivateKey
:
81 derBytes
, err
= x509
.MarshalECPrivateKey(key
)
86 panic("unknown key type")
89 var pemOut bytes
.Buffer
90 pem
.Encode(&pemOut
, &pem
.Block
{Type
: pemType
+ " PRIVATE KEY", Bytes
: derBytes
})
92 keyPath
:= tempFile(string(pemOut
.Bytes()))
93 defer os
.Remove(keyPath
)
96 if len(test
.command
) > 0 {
97 command
= append(command
, test
.command
...)
99 command
= append(command
, defaultServerCommand
...)
101 command
= append(command
, "-cert", certPath
, "-certform", "DER", "-key", keyPath
)
102 // serverPort contains the port that OpenSSL will listen on. OpenSSL
103 // can't take "0" as an argument here so we have to pick a number and
104 // hope that it's not in use on the machine. Since this only occurs
105 // when -update is given and thus when there's a human watching the
106 // test, this isn't too bad.
107 const serverPort
= 24323
108 command
= append(command
, "-accept", strconv
.Itoa(serverPort
))
110 cmd
:= exec
.Command(command
[0], command
[1:]...)
111 stdin
= blockingSource(make(chan bool))
116 if err
:= cmd
.Start(); err
!= nil {
117 return nil, nil, nil, err
120 // OpenSSL does print an "ACCEPT" banner, but it does so *before*
121 // opening the listening socket, so we can't use that to wait until it
122 // has started listening. Thus we are forced to poll until we get a
125 for i
:= uint(0); i
< 5; i
++ {
127 tcpConn
, err
= net
.DialTCP("tcp", nil, &net
.TCPAddr
{
128 IP
: net
.IPv4(127, 0, 0, 1),
134 time
.Sleep((1 << i
) * 5 * time
.Millisecond
)
138 out
.WriteTo(os
.Stdout
)
140 return nil, nil, nil, cmd
.Wait()
143 record
:= &recordingConn
{
147 return record
, cmd
, stdin
, nil
150 func (test
*clientTest
) dataPath() string {
151 return filepath
.Join("testdata", "Client-"+test
.name
)
154 func (test
*clientTest
) loadData() (flows
[][]byte, err error
) {
155 in
, err
:= os
.Open(test
.dataPath())
160 return parseTestData(in
)
163 func (test
*clientTest
) run(t
*testing
.T
, write
bool) {
164 var clientConn
, serverConn net
.Conn
165 var recordingConn
*recordingConn
166 var childProcess
*exec
.Cmd
167 var stdin blockingSource
171 recordingConn
, childProcess
, stdin
, err
= test
.connFromCommand()
173 t
.Fatalf("Failed to start subcommand: %s", err
)
175 clientConn
= recordingConn
177 clientConn
, serverConn
= net
.Pipe()
180 config
:= test
.config
184 client
:= Client(clientConn
, config
)
186 doneChan
:= make(chan bool)
188 if _
, err
:= client
.Write([]byte("hello\n")); err
!= nil {
189 t
.Logf("Client.Write failed: %s", err
)
197 flows
, err
:= test
.loadData()
199 t
.Fatalf("%s: failed to load data from %s", test
.name
, test
.dataPath())
201 for i
, b
:= range flows
{
206 bb
:= make([]byte, len(b
))
207 _
, err
:= io
.ReadFull(serverConn
, bb
)
209 t
.Fatalf("%s #%d: %s", test
.name
, i
, err
)
211 if !bytes
.Equal(b
, bb
) {
212 t
.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test
.name
, i
, bb
, b
)
221 path
:= test
.dataPath()
222 out
, err
:= os
.OpenFile(path
, os
.O_WRONLY|os
.O_CREATE|os
.O_TRUNC
, 0644)
224 t
.Fatalf("Failed to create output file: %s", err
)
227 recordingConn
.Close()
229 childProcess
.Process
.Kill()
231 if len(recordingConn
.flows
) < 3 {
232 childProcess
.Stdout
.(*bytes
.Buffer
).WriteTo(os
.Stdout
)
233 t
.Fatalf("Client connection didn't work")
235 recordingConn
.WriteTo(out
)
236 fmt
.Printf("Wrote %s\n", path
)
240 func runClientTestForVersion(t
*testing
.T
, template
*clientTest
, prefix
, option
string) {
242 test
.name
= prefix
+ test
.name
243 if len(test
.command
) == 0 {
244 test
.command
= defaultClientCommand
246 test
.command
= append([]string(nil), test
.command
...)
247 test
.command
= append(test
.command
, option
)
251 func runClientTestTLS10(t
*testing
.T
, template
*clientTest
) {
252 runClientTestForVersion(t
, template
, "TLSv10-", "-tls1")
255 func runClientTestTLS11(t
*testing
.T
, template
*clientTest
) {
256 runClientTestForVersion(t
, template
, "TLSv11-", "-tls1_1")
259 func runClientTestTLS12(t
*testing
.T
, template
*clientTest
) {
260 runClientTestForVersion(t
, template
, "TLSv12-", "-tls1_2")
263 func TestHandshakeClientRSARC4(t
*testing
.T
) {
266 command
: []string{"openssl", "s_server", "-cipher", "RC4-SHA"},
268 runClientTestTLS10(t
, test
)
269 runClientTestTLS11(t
, test
)
270 runClientTestTLS12(t
, test
)
273 func TestHandshakeClientECDHERSAAES(t
*testing
.T
) {
275 name
: "ECDHE-RSA-AES",
276 command
: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES128-SHA"},
278 runClientTestTLS10(t
, test
)
279 runClientTestTLS11(t
, test
)
280 runClientTestTLS12(t
, test
)
283 func TestHandshakeClientECDHEECDSAAES(t
*testing
.T
) {
285 name
: "ECDHE-ECDSA-AES",
286 command
: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA"},
287 cert
: testECDSACertificate
,
288 key
: testECDSAPrivateKey
,
290 runClientTestTLS10(t
, test
)
291 runClientTestTLS11(t
, test
)
292 runClientTestTLS12(t
, test
)
295 func TestHandshakeClientECDHEECDSAAESGCM(t
*testing
.T
) {
297 name
: "ECDHE-ECDSA-AES-GCM",
298 command
: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-GCM-SHA256"},
299 cert
: testECDSACertificate
,
300 key
: testECDSAPrivateKey
,
302 runClientTestTLS12(t
, test
)
305 func TestHandshakeClientCertRSA(t
*testing
.T
) {
306 config
:= *testConfig
307 cert
, _
:= X509KeyPair([]byte(clientCertificatePEM
), []byte(clientKeyPEM
))
308 config
.Certificates
= []Certificate
{cert
}
311 name
: "ClientCert-RSA-RSA",
312 command
: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
316 runClientTestTLS10(t
, test
)
317 runClientTestTLS12(t
, test
)
320 name
: "ClientCert-RSA-ECDSA",
321 command
: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"},
323 cert
: testECDSACertificate
,
324 key
: testECDSAPrivateKey
,
327 runClientTestTLS10(t
, test
)
328 runClientTestTLS12(t
, test
)
331 func TestHandshakeClientCertECDSA(t
*testing
.T
) {
332 config
:= *testConfig
333 cert
, _
:= X509KeyPair([]byte(clientECDSACertificatePEM
), []byte(clientECDSAKeyPEM
))
334 config
.Certificates
= []Certificate
{cert
}
337 name
: "ClientCert-ECDSA-RSA",
338 command
: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
342 runClientTestTLS10(t
, test
)
343 runClientTestTLS12(t
, test
)
346 name
: "ClientCert-ECDSA-ECDSA",
347 command
: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"},
349 cert
: testECDSACertificate
,
350 key
: testECDSAPrivateKey
,
353 runClientTestTLS10(t
, test
)
354 runClientTestTLS12(t
, test
)