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 MIIFYDCCA0igAwIBAgIJAPpBgIvtQb1EMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV 177 BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX 178 aWRnaXRzIFB0eSBMdGQwHhcNMTgwMjEzMjAxNjA3WhcNMTkwMjEzMjAxNjA3WjBF 179 MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 180 ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC 181 CgKCAgEAr4xgdmB4DaEh8zRFmg/1ZxYhQZMUP0iQX/Y8nDWxNlcd42p3TgpY1biz 182 jrq58ln9Om4U/GAn2RmtBAynSBXIlR5oVa44JeMM8Ka8R/dMKyHpF0Nj2EJB9unb 183 TC33PfzOlnKQxATwevnnhI6tGluWmwvxXUi7WnX0di+nQg9HrIVom3KrmRr2/41y 184 g497ccYUuNnKE6sewGdGzw045oWZpMDA2Us+MFo1IywOurjaM9bueRhPTcIiQ8RE 185 h7qb+FRwfxaj9ynZA2PCM7WMSSWCiZJV0uj/pshYF2lvtJcJef4dhwnsYBpc+mgx 186 2q9qcUBeo3ZHbi1/PRqjwSmcW3yY5cQRbpYp6xFmgmX3oHQkVXS0UlpNVZ+morcS 187 HEpaK8b76fCFcL5yFsAJkPPfny1IKU+CfaVq60dM/mxbEW6J4mZT/uAiqrCilMC+ 188 FyiATCZur8Ks7p47eZy700DllLod7gWTiuZTgHeQFVoX+jxbCZKlFn5Xspu8ALoK 189 Mla/q83mICRVy3+eMUsD7DNvoWYpCAYy/oMk0VWfrQ48JkCGbBW2PW/dU2nmqVhY 190 /11rurkr+1TUvYodnajANtXvUjW1DPOLb4dES4Qc4b7Fw8eFXrARhl5mXiL5HFKR 191 /VnRshiJ+QwTVkxl+KkZHEm/WS8QD+Zd8leAxh9MCoaU/XrBUBkCAwEAAaNTMFEw 192 HQYDVR0OBBYEFKUinuD1xRvcNd2Wti/PnBJp7On1MB8GA1UdIwQYMBaAFKUinuD1 193 xRvcNd2Wti/PnBJp7On1MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD 194 ggIBAJdJrNBftqkTs2HyuJ3x5RIsTxYh85hJYwNOdFLyzVG6HER9jRCnvmNTjG0O 195 I5wz5hQvDpwXs4BCCXHQZrTLAi3BEjq3AjrmR/XeGHulbWh3eh8LVu7MiLRgt+Ys 196 GnL2IaERrbkje24nCCMNPbI3fGDQEhTIYmmX8RJp+5BOJgCycKk6pFgfrjJv2C+d 197 78pcjlYII6M4vPnr/a08M49Bq6b5ADvIfe5G2KrUvD/+vwoAwv6d/daymHCQ2rY5 198 kmdVk9VUp3Q4uKoeej4ENJSAUNTV7oTu346oc7q9sJffB5OltqbrE7ichak7lL+v 199 EjArZHElAhKNFXRZViCMvGDs+7JztqbsfT8Xb6Z27e+WyudB2bOUGm3hKuTIl06D 200 bA7yUskwEhmkd1CJqO5RLEJjKitOqe6Ye0/GsmPQNDK8GvyXTyGQK5OqBuzEexF0 201 mlPoIhpSVH3K9SkRTTHvvcbdYlaQLi6gKq2uhbk4PnS2nfBtXqYIy9mxcgBJzLiB 202 /ydfLcf3GClwgvO1JHp6qAl4CO7oe8jqHpoGuznwi1aqkTyNkQWh0OXq3MS+dyqB 203 2yXFCFIeKCx18TE1OtuTD3ppBDjpyd0o/a6kYR3FDmdks/J33bGwLsLH3lbN6VjF 204 PNfNkaE1tfkpSGYsuT1DPxX8aAT4JLUfZ1Si6iO+E0Sj9LXA 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 )