diff --git a/_dev/tris-testclient/client.go b/_dev/tris-testclient/client.go index 2603530..5dace3f 100644 --- a/_dev/tris-testclient/client.go +++ b/_dev/tris-testclient/client.go @@ -29,28 +29,38 @@ var cipherSuiteIdToName = map[uint16]string{ tls.TLS_CHACHA20_POLY1305_SHA256: "TLS_CHACHA20_POLY1305_SHA256", } +var failed uint + type Client struct { - KeyLogWriter io.Writer - failed uint - client_cert tls.Certificate - client_certpool *x509.CertPool + TLS tls.Config + addr string } -func (c *Client) run(addr string, version, cipherSuite uint16) { - fmt.Printf("TLS %s with %s\n", tlsVersionToName[version], cipherSuiteIdToName[cipherSuite]) - tls_config := &tls.Config{ - InsecureSkipVerify: true, - MinVersion: version, - MaxVersion: version, - CipherSuites: []uint16{cipherSuite}, - KeyLogWriter: c.KeyLogWriter, - Certificates: []tls.Certificate{c.client_cert}, - RootCAs: c.client_certpool, - } - con, err := tls.Dial("tcp", addr, tls_config) +func NewClient() *Client { + var c Client + c.TLS.InsecureSkipVerify = true + return &c +} + +func (c *Client) clone() *Client { + var clone Client + clone.TLS = *c.TLS.Clone() + clone.addr = c.addr + return &clone +} + +func (c *Client) setMinMaxTLS(ver uint16) { + c.TLS.MinVersion = ver + c.TLS.MaxVersion = ver +} + +func (c *Client) run() { + fmt.Printf("TLS %s with %s\n", tlsVersionToName[c.TLS.MinVersion], cipherSuiteIdToName[c.TLS.CipherSuites[0]]) + + con, err := tls.Dial("tcp", c.addr, &c.TLS) if err != nil { fmt.Printf("handshake failed: %v\n\n", err) - c.failed++ + failed++ return } defer con.Close() @@ -58,7 +68,7 @@ func (c *Client) run(addr string, version, cipherSuite uint16) { _, err = con.Write([]byte("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")) if err != nil { fmt.Printf("Write failed: %v\n\n", err) - c.failed++ + failed++ return } @@ -68,7 +78,7 @@ func (c *Client) run(addr string, version, cipherSuite uint16) { // is received right after reading data (observed with NSS selfserv). if !(n > 0 && err == io.EOF) && err != nil { fmt.Printf("Read failed: %v\n\n", err) - c.failed++ + failed++ return } fmt.Printf("Read %d bytes\n", n) @@ -76,6 +86,14 @@ func (c *Client) run(addr string, version, cipherSuite uint16) { fmt.Println("OK\n") } +func result() { + if failed > 0 { + log.Fatalf("Failed handshakes: %d\n", failed) + } else { + fmt.Println("All handshakes passed") + } +} + func main() { var keylog_file string var enable_rsa, enable_ecdsa, client_auth bool @@ -89,12 +107,13 @@ func main() { flag.Usage() os.Exit(1) } - addr := flag.Arg(0) - if !strings.Contains(addr, ":") { - addr += ":443" + + client := NewClient() + client.addr = flag.Arg(0) + if !strings.Contains(client.addr, ":") { + client.addr += ":443" } - client := Client{} if keylog_file == "" { keylog_file = os.Getenv("SSLKEYLOGFILE") } @@ -103,44 +122,55 @@ func main() { if err != nil { log.Fatalf("Cannot open keylog file: %v", err) } - client.KeyLogWriter = keylog_writer + client.TLS.KeyLogWriter = keylog_writer log.Println("Enabled keylog") } if client_auth { var err error - client.client_cert, err = tls.X509KeyPair([]byte(client_crt), []byte(client_key)) + client_cert, err := tls.X509KeyPair([]byte(client_crt), []byte(client_key)) if err != nil { panic("Can't load client certificate") } - client.client_certpool = x509.NewCertPool() - if !client.client_certpool.AppendCertsFromPEM([]byte(client_ca)) { + client.TLS.Certificates = []tls.Certificate{client_cert} + client.TLS.RootCAs = x509.NewCertPool() + if !client.TLS.RootCAs.AppendCertsFromPEM([]byte(client_ca)) { panic("Can't load client CA cert") } } if enable_rsa { // Sanity check: TLS 1.2 with the mandatory cipher suite from RFC 5246 - client.run(addr, tls.VersionTLS12, tls.TLS_RSA_WITH_AES_128_CBC_SHA) + c := client.clone() + c.TLS.CipherSuites = []uint16{tls.TLS_RSA_WITH_AES_128_CBC_SHA} + c.setMinMaxTLS(tls.VersionTLS12) + c.run() } if enable_ecdsa { // Sane cipher suite for TLS 1.2 with an ECDSA cert (as used by boringssl) - client.run(addr, tls.VersionTLS12, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) + c := client.clone() + c.TLS.CipherSuites = []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256} + c.setMinMaxTLS(tls.VersionTLS12) + c.run() } - client.run(addr, tls.VersionTLS13, tls.TLS_CHACHA20_POLY1305_SHA256) - client.run(addr, tls.VersionTLS13, tls.TLS_AES_128_GCM_SHA256) - client.run(addr, tls.VersionTLS13, tls.TLS_AES_256_GCM_SHA384) + client.setMinMaxTLS(tls.VersionTLS13) + client.TLS.CipherSuites = []uint16{tls.TLS_CHACHA20_POLY1305_SHA256} + client.run() + + client.setMinMaxTLS(tls.VersionTLS13) + client.TLS.CipherSuites = []uint16{tls.TLS_AES_128_GCM_SHA256} + client.run() + + client.setMinMaxTLS(tls.VersionTLS13) + client.TLS.CipherSuites = []uint16{tls.TLS_AES_256_GCM_SHA384} + client.run() // TODO test other kex methods besides X25519, like MTI secp256r1 // TODO limit supported groups? - if client.failed > 0 { - log.Fatalf("Failed handshakes: %d\n", client.failed) - } else { - fmt.Println("All handshakes passed") - } + result() } const (