github.com/Psiphon-Labs/tls-tris@v0.0.0-20230824155421-58bf6d336a9a/_dev/tris-testclient/client.go (about)

     1  package main
     2  
     3  import (
     4  	"crypto/tls"
     5  	"crypto/x509"
     6  	"flag"
     7  	"fmt"
     8  	"io"
     9  	"log"
    10  	"os"
    11  	"strings"
    12  )
    13  
    14  var tlsVersionToName = map[uint16]string{
    15  	tls.VersionTLS10: "1.0",
    16  	tls.VersionTLS11: "1.1",
    17  	tls.VersionTLS12: "1.2",
    18  	tls.VersionTLS13: "1.3",
    19  }
    20  
    21  var cipherSuiteIdToName = map[uint16]string{
    22  	tls.TLS_RSA_WITH_AES_128_CBC_SHA:            "TLS_RSA_WITH_AES_128_CBC_SHA",
    23  	tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
    24  	tls.TLS_AES_128_GCM_SHA256:                  "TLS_AES_128_GCM_SHA256",
    25  	tls.TLS_AES_256_GCM_SHA384:                  "TLS_AES_256_GCM_SHA384",
    26  	tls.TLS_CHACHA20_POLY1305_SHA256:            "TLS_CHACHA20_POLY1305_SHA256",
    27  }
    28  
    29  var failed uint
    30  
    31  type Client struct {
    32  	TLS  tls.Config
    33  	addr string
    34  }
    35  
    36  func NewClient() *Client {
    37  	var c Client
    38  	c.TLS.InsecureSkipVerify = true
    39  	return &c
    40  }
    41  
    42  func (c *Client) clone() *Client {
    43  	var clone Client
    44  	clone.TLS = *c.TLS.Clone()
    45  	clone.addr = c.addr
    46  	return &clone
    47  }
    48  
    49  func (c *Client) setMinMaxTLS(ver uint16) {
    50  	c.TLS.MinVersion = ver
    51  	c.TLS.MaxVersion = ver
    52  }
    53  
    54  func (c *Client) run() {
    55  	fmt.Printf("TLS %s with %s\n", tlsVersionToName[c.TLS.MinVersion], cipherSuiteIdToName[c.TLS.CipherSuites[0]])
    56  
    57  	con, err := tls.Dial("tcp", c.addr, &c.TLS)
    58  	if err != nil {
    59  		fmt.Printf("handshake failed: %v\n\n", err)
    60  		failed++
    61  		return
    62  	}
    63  	defer con.Close()
    64  
    65  	_, err = con.Write([]byte("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"))
    66  	if err != nil {
    67  		fmt.Printf("Write failed: %v\n\n", err)
    68  		failed++
    69  		return
    70  	}
    71  
    72  	buf := make([]byte, 1024)
    73  	n, err := con.Read(buf)
    74  	// A non-zero read with EOF is acceptable and occurs when a close_notify
    75  	// is received right after reading data (observed with NSS selfserv).
    76  	if !(n > 0 && err == io.EOF) && err != nil {
    77  		fmt.Printf("Read failed: %v\n\n", err)
    78  		failed++
    79  		return
    80  	}
    81  	fmt.Printf("Read %d bytes\n", n)
    82  
    83  	fmt.Println("OK\n")
    84  }
    85  
    86  func result() {
    87  	if failed > 0 {
    88  		log.Fatalf("Failed handshakes: %d\n", failed)
    89  	} else {
    90  		fmt.Println("All handshakes passed")
    91  	}
    92  }
    93  
    94  // Usage client args host:port
    95  func main() {
    96  	var keylog_file string
    97  	var enable_rsa, enable_ecdsa, client_auth bool
    98  
    99  	flag.StringVar(&keylog_file, "keylogfile", "", "Secrets will be logged here")
   100  	flag.BoolVar(&enable_rsa, "rsa", true, "Whether to enable RSA cipher suites")
   101  	flag.BoolVar(&enable_ecdsa, "ecdsa", true, "Whether to enable ECDSA cipher suites")
   102  	flag.BoolVar(&client_auth, "cliauth", false, "Whether to enable client authentication")
   103  	flag.Parse()
   104  	if flag.NArg() != 1 {
   105  		flag.Usage()
   106  		os.Exit(1)
   107  	}
   108  
   109  	client := NewClient()
   110  	client.addr = flag.Arg(0)
   111  	if !strings.Contains(client.addr, ":") {
   112  		client.addr += ":443"
   113  	}
   114  
   115  	if keylog_file == "" {
   116  		keylog_file = os.Getenv("SSLKEYLOGFILE")
   117  	}
   118  	if keylog_file != "" {
   119  		keylog_writer, err := os.OpenFile(keylog_file, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
   120  		if err != nil {
   121  			log.Fatalf("Cannot open keylog file: %v", err)
   122  		}
   123  		client.TLS.KeyLogWriter = keylog_writer
   124  		log.Println("Enabled keylog")
   125  	}
   126  
   127  	if client_auth {
   128  		var err error
   129  		client_cert, err := tls.X509KeyPair([]byte(client_crt), []byte(client_key))
   130  		if err != nil {
   131  			panic("Can't load client certificate")
   132  		}
   133  
   134  		client.TLS.Certificates = []tls.Certificate{client_cert}
   135  		client.TLS.RootCAs = x509.NewCertPool()
   136  		if !client.TLS.RootCAs.AppendCertsFromPEM([]byte(client_ca)) {
   137  			panic("Can't load client CA cert")
   138  		}
   139  	}
   140  
   141  	if enable_rsa {
   142  		// Sanity check: TLS 1.2 with the mandatory cipher suite from RFC 5246
   143  		c := client.clone()
   144  		c.TLS.CipherSuites = []uint16{tls.TLS_RSA_WITH_AES_128_CBC_SHA}
   145  		c.setMinMaxTLS(tls.VersionTLS12)
   146  		c.run()
   147  	}
   148  	if enable_ecdsa {
   149  		// Sane cipher suite for TLS 1.2 with an ECDSA cert (as used by boringssl)
   150  		c := client.clone()
   151  		c.TLS.CipherSuites = []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}
   152  		c.setMinMaxTLS(tls.VersionTLS12)
   153  		c.run()
   154  	}
   155  
   156  	client.setMinMaxTLS(tls.VersionTLS13)
   157  	client.TLS.CipherSuites = []uint16{tls.TLS_CHACHA20_POLY1305_SHA256}
   158  	client.run()
   159  
   160  	client.setMinMaxTLS(tls.VersionTLS13)
   161  	client.TLS.CipherSuites = []uint16{tls.TLS_AES_128_GCM_SHA256}
   162  	client.run()
   163  
   164  	client.setMinMaxTLS(tls.VersionTLS13)
   165  	client.TLS.CipherSuites = []uint16{tls.TLS_AES_256_GCM_SHA384}
   166  	client.run()
   167  
   168  	// TODO test other kex methods besides X25519, like MTI secp256r1
   169  	// TODO limit supported groups?
   170  
   171  	result()
   172  }
   173  
   174  const (
   175  	client_ca = `-----BEGIN CERTIFICATE-----
   176  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
   205  -----END CERTIFICATE-----`
   206  	client_crt = `-----BEGIN CERTIFICATE-----
   207  MIID/jCCAeYCAQEwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV
   208  BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
   209  ZDAeFw0xODAyMTMyMDU0MjZaFw0xOTAyMTMyMDU0MjZaMEUxCzAJBgNVBAYTAkFV
   210  MRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRz
   211  IFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDD1li7/35Q
   212  C/T6FACSbsd0WlImu42i6w96wfngAfEgbz5Ip+IA2rJ8G5LNHTYYCpr9LlmhY6zm
   213  soHgAkff6XwUnZaetX01UmGP4CD4D3UumkR1uKY4bCSNImm53SZgelOznpsqAWKE
   214  zosMrDcOAJKJSN411KwVzWysfRCPyxvmLETzU9KHFCJ1oY3t1HzYIAqpHv9sMSst
   215  dNHW3X7bWEAVKCQMKO+rWe/wAhE4iTVdlRi02oRoRWSVj41+nk6jI8KJNq70stHc
   216  QSST0A7SUacPYKJWqJRhP1pZ6k4G3ZVE8332az7jvcN1uGGjERZoUbZxGB+mbMCC
   217  GJwnwnNiI6/hAgMBAAEwDQYJKoZIhvcNAQELBQADggIBADNr6QMl57CdHEzNwc2M
   218  CSZsuOLakp8YiovVDOXJ/p/lykUIIcR1rI1iNfb8oOFTZmrndGZVAh76EExdMHYG
   219  m+4Vr2+z/73AZwvhhnLhftOKFFwkdjCfXouPlkc/zmhOORakIFGlLZFkuZRY6k2D
   220  Q8uIt7E5uXSVl11A1LxN5X8lhK2G4lxJZuj1AqEFj9QD44Qy+MdgX38lzGCEXd8c
   221  Y5K8zLJGbgXgYaFxqd0bImfjgjj82+Mui0OTV5PcRlczJX08ygKjcoAMVyvPHu72
   222  3zzxvoNcqUrvbptVvg9c7FSOpK95YZOe1LiyqZCwNJQl4fPRE++XQ4zDNdyiAp76
   223  a6BQg/M8gOpV/VBMTsNDr/yP/7eBqkfvU7jLfz7wKMDdcjeZnKom42f+/XOLEo6E
   224  hyDuHGdQh10bZD/Ukcs69+pA3ioic1A8pQzAElH3IuDBsMJg30x8tACLKNcUY8BE
   225  2eJgrCxWcvq88DeAT03W9AVpFZA8ZQUR3SHCquMBFogsmUDDMN+CoC0u5dBwHP+O
   226  9rmWOXn8gp/zBCKGwemgVV5vSNzJs7z3aoqIiAABl56LBaXxjKzRmXoB/SyUW5zl
   227  1zy4SQTE6SJYqqU6h2yRdT8n0oWN3AMy0VxbJTRq32kdYJVQK9cLKVqpxtCCtPnN
   228  3lV+HDsj7k+AJjHiu1F4O+sp
   229  -----END CERTIFICATE-----`
   230  	client_key = `-----BEGIN RSA PRIVATE KEY-----
   231  MIIEpAIBAAKCAQEAw9ZYu/9+UAv0+hQAkm7HdFpSJruNousPesH54AHxIG8+SKfi
   232  ANqyfBuSzR02GAqa/S5ZoWOs5rKB4AJH3+l8FJ2WnrV9NVJhj+Ag+A91LppEdbim
   233  OGwkjSJpud0mYHpTs56bKgFihM6LDKw3DgCSiUjeNdSsFc1srH0Qj8sb5ixE81PS
   234  hxQidaGN7dR82CAKqR7/bDErLXTR1t1+21hAFSgkDCjvq1nv8AIROIk1XZUYtNqE
   235  aEVklY+Nfp5OoyPCiTau9LLR3EEkk9AO0lGnD2CiVqiUYT9aWepOBt2VRPN99ms+
   236  473DdbhhoxEWaFG2cRgfpmzAghicJ8JzYiOv4QIDAQABAoIBADKcbZhAYjt7q5cJ
   237  nlA5svA9+2cpJ2SITRrTkKk0t0VDmpwaTw0bd+8dDSZXO0ihTQbLeLx9zwxb67ah
   238  wEN8yuVlCK0BiFdEcBRHvx18mTMvCSxHSSXhxNx4nUw8fBOI6aLNBZqoevaJjmP7
   239  CctjmHtESrEswkBsM36sX6BZxF8Kc4Q5Znuxqksnl6HNoxnjhmygJmYCFTToiTHa
   240  f2HWKBiZfgfxX7WEuHer3h6nmBbBCOX1/hcipBMBBVIqFl1ZSIF/B3lR8UV4/X+a
   241  SNMqggOqkEIuHKkSCKo1lNxEPP2p54EHrKkjepoqMzIFuYnn4qWesMznpmy+zBGB
   242  6PCjfzUCgYEA92etvRVQjBx8dHTSiyCNbS1ELgiCkzar8PGH+ytTIaj/TTF1LfAi
   243  UYRp5MtOKmQXxE3IRLDF8P8rEKC06aV12hVwhd2xfHjje+KZkwWZ2PIj+GbK7f1r
   244  MvKN5eE0NhGiSvu5SiFuks/SV8Qc4StFPmiWf33XKvJuAWNkCu+bUZsCgYEAyqQL
   245  nVNKTlgHNKDJKMHi/buZt8wtwGGXCxcv+w88PmEC0OCbH/V2niCPLvFmK1xDXpru
   246  k7z9FTc+QeasEMtxY/Gcs3IgUzxOHxAL7cn6KBM44uDhpIcv3BFWtR053acVU6S4
   247  IKuijWIJNJEk2qksgQTX7Mv/xq2uXvfZqajdKjMCgYEA3x+5F9s+Pm5+a4TkUSc1
   248  hS4a3C0+ncfjv7QEwCftnGDOhu7A0IJOYRg7bGVShHaq3JaNtC19BwEJ9MALCOD5
   249  bYqCZahvpmNcPeE6Qdb+TiLq/96sy4AOiu8nvBejv9Ode2SUUd/e2jbla9Ppe8VL
   250  eKJYgHicchYb0dKyag54FFsCgYEAuToEB9W3aS9bvsZtuZyooSfXFcND2sMZrqCO
   251  Uh2WAqroSQfVo/vaZiX623z62A2o4xQZmd+5MqhhdxmkFGHyDtouU3SxiYPpIMmp
   252  Lb1etT0E1ZWbi6mqnK0YpcrGNw5gFynMyMg6eKOxKGS33EuhC3ni6Wd7MB9X8ST6
   253  x/M73jMCgYBBge3/ugnZPE78TDL3DdefrjeYFaKhVc622eimS/MEPbkbdxh8azTM
   254  LAoibwDU1NC8/3MfOBYMe6Qklu3kjexOJrfdo0Z7Khgd9F8A4tKwslUndSSlAfKF
   255  2rjfqabVMZMLZ2XEbA4W5JTfaZS4YYGcrjY7+i7OsnSxoYG2sb+xlQ==
   256  -----END RSA PRIVATE KEY-----`
   257  )