1package tls 2 3import ( 4 "crypto/tls" 5 "encoding/pem" 6 "fmt" 7 "io/ioutil" 8 "net/http" 9 "net/http/httptest" 10 "net/url" 11 "os" 12 "strings" 13 "testing" 14 "time" 15) 16 17const ( 18 httpContent = "Hello, TLS!" 19 20 certHash = "SHA256:1153aa0230ee0481b36bdd83ddb04b607340dbda35f3a4fff0615e4d9292d687" 21) 22 23var ( 24 certNotBefore = time.Unix(0, 0) 25 certNotAfter = certNotBefore.Add(1000000 * time.Hour) 26 27 // Generated with: 28 // go run crypto/tls/generate_cert.go --rsa-bits 2048 \ 29 // --host 127.0.0.1,::1,example.com --ca \ 30 // --start-date "Jan 1 00:00:00 1970" --duration=1000000h` 31 testServerCert = []byte(`-----BEGIN CERTIFICATE----- 32MIIDGTCCAgGgAwIBAgIRAJHZkrBTk/yTKT3L2Z+dgZcwDQYJKoZIhvcNAQELBQAw 33EjEQMA4GA1UEChMHQWNtZSBDbzAgFw03MDAxMDEwMDAwMDBaGA8yMDg0MDEyOTE2 34MDAwMFowEjEQMA4GA1UEChMHQWNtZSBDbzCCASIwDQYJKoZIhvcNAQEBBQADggEP 35ADCCAQoCggEBANxPCe2pafj2pWdA+hnN+Ne9Auh2YdoSPbQqIPQMVTT/3j6w9LlW 36JirXCLWNuoarOA2iCgVa4Y607O/f2FTN7cKY2lvhAkuftCUJzB/lJVH5bWZgSrks 373AaOBlBcyMKBajFoEOIgSMwHGAZO2XsWIvdbuQw3EKY50vfBvxQspjbMruhpZoKd 389tHx6XUBoYSf5t9X+FrG2UjihnfcfBcsKGq7lbujt3+3QvlU6w1ZGOX+f9b+3+yw 39RQkswxvkzKpfmgvr8GWWUm8w9wkImhAmA2UAhsM8OwnKVltvMih5mb9L2hw5+qBV 40W1V+CSR0tDI9D8eiL26B3dvOilpZjttp3fsCAwEAAaNoMGYwDgYDVR0PAQH/BAQD 41AgKkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wLgYDVR0R 42BCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZI 43hvcNAQELBQADggEBAA+tFyWOZLoUjN2SKcIXnN5zs4VZedybLFVZoJSDakgo8awS 44HPkD/1ReIOzT41Hmzjs/4CeVw6FSeKnYtEqTPOJoRVrXAIqyHGHJ2cEWpUXvg2b0 45u7lkFfElRqcBjsDZYr+rJUxkjlCa11ylCbgdwoDMIbKNldcJoLB0iwQWUE7j19xe 46CF32aISt/nGxCYcO81tn+ionwzZyf5zh5k/SmAqrPy4O/qxn8oEaox4Z7BfoZlAS 47gmPA2gedTWORfthamJdT2irz3rdHjV7NWxwTsgOAx9y+P3fqmMCyMwxFJkmP118W 48yM5xDRR+ldYKoRts5qkPR6LVtCw9kn+dJKQm0Bc= 49-----END CERTIFICATE-----`) 50 testServerKey = []byte(`-----BEGIN PRIVATE KEY----- 51MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDcTwntqWn49qVn 52QPoZzfjXvQLodmHaEj20KiD0DFU0/94+sPS5ViYq1wi1jbqGqzgNogoFWuGOtOzv 5339hUze3CmNpb4QJLn7QlCcwf5SVR+W1mYEq5LNwGjgZQXMjCgWoxaBDiIEjMBxgG 54Ttl7FiL3W7kMNxCmOdL3wb8ULKY2zK7oaWaCnfbR8el1AaGEn+bfV/haxtlI4oZ3 553HwXLChqu5W7o7d/t0L5VOsNWRjl/n/W/t/ssEUJLMMb5MyqX5oL6/BlllJvMPcJ 56CJoQJgNlAIbDPDsJylZbbzIoeZm/S9ocOfqgVVtVfgkkdLQyPQ/Hoi9ugd3bzopa 57WY7bad37AgMBAAECggEAKSmnbD1sLHVBIFK2qB2g8gZBxddgnxMrbj802wR24ykv 58iD0d7IcZKIX2/Z0WjdTt6zYscyWw4S4S2xrS272CQAq5OdOHz0NusEDtX8Q7vd5B 59v5AcRg8IqTzeFyPO6vCtO7/675UipORqa7tNzT6sl9UOdSbQuI4zSdFsd0OEZtZs 60oqKkv+jdvKaVJQ1vsoQSup23V0bvVCRydBNFZ2mQ3etZcRRYXyu1digJ7/oMyCHf 611F37lJmjPJ8WwsGJMk2ngJiUOQx21bbTZ22c/8sMMLJjhhC2qu984keVRanSsJwC 62Z80XcCxL/yoLF42A5ReMtutFs83rW7VX7VJGxoOaKQKBgQD91dCs9jGBVxHr4vxy 63NJC2n92R5/JpqXygXS3L6RDP+we6p/fmSd4/QllwIVeC9kepsFz4//ArmLOy9JHu 64rkXa7W9G+XbmYXSftmG78roLfAtvdudoytLQJg2bu8J3bzPVibRCUq0OORFyqOHR 65QGcQtvPxwFHctIkOjajbLpbL7QKBgQDeMAbvjzD8wU1gp2U8Bl5l5ohYgQpcs15R 66eBPS5DlRzICAeuQWi+BRjW5BPZVmTr3Ml3KiMWcalXMeH1TKoPON8RjmWgY2Fxvh 67nS7gV+rJm4H0T+bBEXNAraracwGYd6JgcH9BPD9znHRmyFR4pMPqkSa7o/OExH6W 68O32KqTMkhwKBgQCoX7wb/vK3qNnqbpal6thTS5fdwM276QESHrzSFbdhPlLSLbjy 69uO0DaS+KgZNa+6JtnN8PDDZztMb+XdyvRkpv/i9iFPgZuWtyxbfuxANEuvOa7HRz 70vpY4HAXK17EXKFxpuP4pQE4qsRAxznR8KQw0uib2pWunytlfHfhz62N7wQKBgQC+ 71+TTc74zBkzx42SiwYSD+IRoMSE2pxBpLmBQh7jw+TLIevIITxwJ11kRwGwiwuPl2 72Qq4rLp9aQB6EQ5XT3Ge7FwG57KLuFwrF7x59gdOymdEnNw414FPZwevae4Nhk2Kj 731c3rOmenbVC3j3TbhXNHyJ8sJQ2IjoPniRas+iWVPQKBgQDcZzKh6U+e9efYLAt0 74qdaKhm5MCAgzD9X/Tx2OvOqgWnSXt2Q2AhK2UsHnrGBn1SDNTNDGlniQy2OM2Ywn 75n71nH1QUmgoiwBrFUh0gLxv878vwgUATqfFRTlirmK9XxHuTX9Jh6elmRebjYWyc 76Oo0CJBeMABu71Y+VkCxURT1bzw== 77-----END PRIVATE KEY-----`) 78) 79 80type handshakeError string 81 82func (he handshakeError) Error() string { 83 return string(he) 84} 85 86// createCAFile writes a PEM encoded version of the certificate out to a 87// temporary file, for use by libtls. 88func createCAFile(cert []byte) (string, error) { 89 f, err := ioutil.TempFile("", "tls") 90 if err != nil { 91 return "", fmt.Errorf("failed to create file: %v", err) 92 } 93 defer f.Close() 94 block := &pem.Block{ 95 Type: "CERTIFICATE", 96 Bytes: cert, 97 } 98 if err := pem.Encode(f, block); err != nil { 99 return "", fmt.Errorf("failed to encode certificate: %v", err) 100 } 101 return f.Name(), nil 102} 103 104func newTestServer(tlsCfg *tls.Config) (*httptest.Server, *url.URL, string, error) { 105 ts := httptest.NewUnstartedServer( 106 http.HandlerFunc( 107 func(w http.ResponseWriter, r *http.Request) { 108 fmt.Fprintln(w, httpContent) 109 }, 110 ), 111 ) 112 if tlsCfg == nil { 113 tlsCfg = &tls.Config{} 114 } 115 if len(tlsCfg.Certificates) == 0 { 116 cert, err := tls.X509KeyPair(testServerCert, testServerKey) 117 if err != nil { 118 return nil, nil, "", fmt.Errorf("failed to load key pair: %v", err) 119 } 120 tlsCfg.Certificates = []tls.Certificate{cert} 121 } 122 ts.TLS = tlsCfg 123 ts.StartTLS() 124 125 u, err := url.Parse(ts.URL) 126 if err != nil { 127 return nil, nil, "", fmt.Errorf("failed to parse URL %q: %v", ts.URL, err) 128 } 129 130 caFile, err := createCAFile(ts.TLS.Certificates[0].Certificate[0]) 131 if err != nil { 132 return nil, nil, "", fmt.Errorf("failed to create CA file: %v", err) 133 } 134 135 return ts, u, caFile, nil 136} 137 138func handshakeVersionTest(tlsCfg *tls.Config) (ProtocolVersion, error) { 139 ts, u, caFile, err := newTestServer(tlsCfg) 140 if err != nil { 141 return 0, fmt.Errorf("failed to start test server: %v", err) 142 } 143 defer os.Remove(caFile) 144 defer ts.Close() 145 146 if err := Init(); err != nil { 147 return 0, err 148 } 149 150 cfg, err := NewConfig() 151 if err != nil { 152 return 0, err 153 } 154 defer cfg.Free() 155 if err := cfg.SetCAFile(caFile); err != nil { 156 return 0, err 157 } 158 if err := cfg.SetCiphers("compat"); err != nil { 159 return 0, err 160 } 161 if err := cfg.SetProtocols(ProtocolsAll); err != nil { 162 return 0, err 163 } 164 165 tls, err := NewClient(cfg) 166 if err != nil { 167 return 0, err 168 } 169 defer tls.Free() 170 171 if err := tls.Connect(u.Host, ""); err != nil { 172 return 0, err 173 } 174 if err := tls.Handshake(); err != nil { 175 return 0, handshakeError(err.Error()) 176 } 177 version, err := tls.ConnVersion() 178 if err != nil { 179 return 0, err 180 } 181 if err := tls.Close(); err != nil { 182 return 0, err 183 } 184 return version, nil 185} 186 187func TestTLSBasic(t *testing.T) { 188 ts, u, caFile, err := newTestServer(nil) 189 if err != nil { 190 t.Fatalf("Failed to start test server: %v", err) 191 } 192 defer os.Remove(caFile) 193 defer ts.Close() 194 195 if err := Init(); err != nil { 196 t.Fatal(err) 197 } 198 199 cfg, err := NewConfig() 200 if err != nil { 201 t.Fatal(err) 202 } 203 defer cfg.Free() 204 if err := cfg.SetCAFile(caFile); err != nil { 205 t.Fatal(err) 206 } 207 208 tls, err := NewClient(cfg) 209 if err != nil { 210 t.Fatal(err) 211 } 212 defer tls.Free() 213 214 t.Logf("Connecting to %s", u.Host) 215 216 if err := tls.Connect(u.Host, ""); err != nil { 217 t.Fatal(err) 218 } 219 defer func() { 220 if err := tls.Close(); err != nil { 221 t.Fatalf("Close failed: %v", err) 222 } 223 }() 224 225 n, err := tls.Write([]byte("GET / HTTP/1.0\n\n")) 226 if err != nil { 227 t.Fatal(err) 228 } 229 t.Logf("Wrote %d bytes...", n) 230 231 buf := make([]byte, 1024) 232 n, err = tls.Read(buf) 233 if err != nil { 234 t.Fatal(err) 235 } 236 t.Logf("Read %d bytes...", n) 237 238 if !strings.Contains(string(buf), httpContent) { 239 t.Errorf("Response does not contain %q", httpContent) 240 } 241} 242 243func TestTLSVersions(t *testing.T) { 244 tests := []struct { 245 minVersion uint16 246 maxVersion uint16 247 wantVersion ProtocolVersion 248 wantHandshakeErr bool 249 }{ 250 {tls.VersionTLS10, tls.VersionTLS13, ProtocolTLSv13, false}, 251 {tls.VersionSSL30, tls.VersionTLS12, ProtocolTLSv12, false}, 252 {tls.VersionTLS10, tls.VersionTLS12, ProtocolTLSv12, false}, 253 {tls.VersionTLS11, tls.VersionTLS12, ProtocolTLSv12, false}, 254 {tls.VersionSSL30, tls.VersionTLS11, ProtocolTLSv11, false}, 255 {tls.VersionSSL30, tls.VersionTLS10, ProtocolTLSv10, false}, 256 {tls.VersionSSL30, tls.VersionSSL30, 0, true}, 257 {tls.VersionTLS10, tls.VersionTLS10, ProtocolTLSv10, false}, 258 {tls.VersionTLS11, tls.VersionTLS11, ProtocolTLSv11, false}, 259 {tls.VersionTLS12, tls.VersionTLS12, ProtocolTLSv12, false}, 260 } 261 for i, test := range tests { 262 t.Logf("Testing handshake with protocols %x:%x", test.minVersion, test.maxVersion) 263 tlsCfg := &tls.Config{ 264 MinVersion: test.minVersion, 265 MaxVersion: test.maxVersion, 266 } 267 version, err := handshakeVersionTest(tlsCfg) 268 switch { 269 case test.wantHandshakeErr && err == nil: 270 t.Errorf("Test %d - handshake %x:%x succeeded, want handshake error", 271 i, test.minVersion, test.maxVersion) 272 case test.wantHandshakeErr && err != nil: 273 if _, ok := err.(handshakeError); !ok { 274 t.Errorf("Test %d - handshake %x:%x; got unknown error, want handshake error: %v", 275 i, test.minVersion, test.maxVersion, err) 276 } 277 case !test.wantHandshakeErr && err != nil: 278 t.Errorf("Test %d - handshake %x:%x failed: %v", i, test.minVersion, test.maxVersion, err) 279 case !test.wantHandshakeErr && err == nil: 280 if got, want := version, test.wantVersion; got != want { 281 t.Errorf("Test %d - handshake %x:%x; got protocol version %v, want %v", 282 i, test.minVersion, test.maxVersion, got, want) 283 } 284 } 285 } 286} 287 288func TestTLSSingleByteReadWrite(t *testing.T) { 289 ts, u, caFile, err := newTestServer(nil) 290 if err != nil { 291 t.Fatalf("Failed to start test server: %v", err) 292 } 293 defer os.Remove(caFile) 294 defer ts.Close() 295 296 if err := Init(); err != nil { 297 t.Fatal(err) 298 } 299 300 cfg, err := NewConfig() 301 if err != nil { 302 t.Fatal(err) 303 } 304 defer cfg.Free() 305 if err := cfg.SetCAFile(caFile); err != nil { 306 t.Fatal(err) 307 } 308 309 tls, err := NewClient(cfg) 310 if err != nil { 311 t.Fatal(err) 312 } 313 defer tls.Free() 314 315 t.Logf("Connecting to %s", u.Host) 316 317 if err := tls.Connect(u.Host, ""); err != nil { 318 t.Fatal(err) 319 } 320 defer func() { 321 if err := tls.Close(); err != nil { 322 t.Fatalf("Close failed: %v", err) 323 } 324 }() 325 326 for _, b := range []byte("GET / HTTP/1.0\n\n") { 327 n, err := tls.Write([]byte{b}) 328 if err != nil { 329 t.Fatal(err) 330 } 331 if n != 1 { 332 t.Fatalf("Wrote byte %v, got length %d, want 1", b, n) 333 } 334 } 335 336 var body []byte 337 for { 338 buf := make([]byte, 1) 339 n, err := tls.Read(buf) 340 if err != nil { 341 t.Fatal(err) 342 } 343 if n == 0 { 344 break 345 } 346 if n != 1 { 347 t.Fatalf("Read single byte, got length %d, want 1", n) 348 } 349 body = append(body, buf...) 350 } 351 352 if !strings.Contains(string(body), httpContent) { 353 t.Errorf("Response does not contain %q", httpContent) 354 } 355} 356 357func TestTLSInfo(t *testing.T) { 358 ts, u, caFile, err := newTestServer(nil) 359 if err != nil { 360 t.Fatalf("Failed to start test server: %v", err) 361 } 362 defer os.Remove(caFile) 363 defer ts.Close() 364 365 if err := Init(); err != nil { 366 t.Fatal(err) 367 } 368 369 cfg, err := NewConfig() 370 if err != nil { 371 t.Fatal(err) 372 } 373 defer cfg.Free() 374 if err := cfg.SetCAFile(caFile); err != nil { 375 t.Fatal(err) 376 } 377 378 tls, err := NewClient(cfg) 379 if err != nil { 380 t.Fatal(err) 381 } 382 defer tls.Free() 383 384 t.Logf("Connecting to %s", u.Host) 385 386 if err := tls.Connect(u.Host, ""); err != nil { 387 t.Fatal(err) 388 } 389 defer func() { 390 if err := tls.Close(); err != nil { 391 t.Fatalf("Close failed: %v", err) 392 } 393 }() 394 395 // All of these should fail since the handshake has not completed. 396 if _, err := tls.ConnVersion(); err == nil { 397 t.Error("ConnVersion() return nil error, want error") 398 } 399 if _, err := tls.ConnCipher(); err == nil { 400 t.Error("ConnCipher() return nil error, want error") 401 } 402 if _, err := tls.ConnCipherStrength(); err == nil { 403 t.Error("ConnCipherStrength() return nil error, want error") 404 } 405 406 if got, want := tls.PeerCertProvided(), false; got != want { 407 t.Errorf("PeerCertProvided() = %v, want %v", got, want) 408 } 409 for _, name := range []string{"127.0.0.1", "::1", "example.com"} { 410 if got, want := tls.PeerCertContainsName(name), false; got != want { 411 t.Errorf("PeerCertContainsName(%q) = %v, want %v", name, got, want) 412 } 413 } 414 415 if _, err := tls.PeerCertIssuer(); err == nil { 416 t.Error("PeerCertIssuer() returned nil error, want error") 417 } 418 if _, err := tls.PeerCertSubject(); err == nil { 419 t.Error("PeerCertSubject() returned nil error, want error") 420 } 421 if _, err := tls.PeerCertHash(); err == nil { 422 t.Error("PeerCertHash() returned nil error, want error") 423 } 424 if _, err := tls.PeerCertNotBefore(); err == nil { 425 t.Error("PeerCertNotBefore() returned nil error, want error") 426 } 427 if _, err := tls.PeerCertNotAfter(); err == nil { 428 t.Error("PeerCertNotAfter() returned nil error, want error") 429 } 430 431 // Complete the handshake... 432 if err := tls.Handshake(); err != nil { 433 t.Fatalf("Handshake failed: %v", err) 434 } 435 436 if version, err := tls.ConnVersion(); err != nil { 437 t.Errorf("ConnVersion() returned error: %v", err) 438 } else { 439 t.Logf("Protocol version: %v", version) 440 } 441 if cipher, err := tls.ConnCipher(); err != nil { 442 t.Errorf("ConnCipher() returned error: %v", err) 443 } else { 444 t.Logf("Cipher: %v", cipher) 445 } 446 if strength, err := tls.ConnCipherStrength(); err != nil { 447 t.Errorf("ConnCipherStrength() return ederror: %v", err) 448 } else { 449 t.Logf("Cipher Strength: %v bits", strength) 450 } 451 452 if got, want := tls.PeerCertProvided(), true; got != want { 453 t.Errorf("PeerCertProvided() = %v, want %v", got, want) 454 } 455 for _, name := range []string{"127.0.0.1", "::1", "example.com"} { 456 if got, want := tls.PeerCertContainsName(name), true; got != want { 457 t.Errorf("PeerCertContainsName(%q) = %v, want %v", name, got, want) 458 } 459 } 460 461 if issuer, err := tls.PeerCertIssuer(); err != nil { 462 t.Errorf("PeerCertIssuer() returned error: %v", err) 463 } else { 464 t.Logf("Issuer: %v", issuer) 465 } 466 if subject, err := tls.PeerCertSubject(); err != nil { 467 t.Errorf("PeerCertSubject() returned error: %v", err) 468 } else { 469 t.Logf("Subject: %v", subject) 470 } 471 if hash, err := tls.PeerCertHash(); err != nil { 472 t.Errorf("PeerCertHash() returned error: %v", err) 473 } else if hash != certHash { 474 t.Errorf("Got cert hash %q, want %q", hash, certHash) 475 } else { 476 t.Logf("Hash: %v", hash) 477 } 478 if notBefore, err := tls.PeerCertNotBefore(); err != nil { 479 t.Errorf("PeerCertNotBefore() returned error: %v", err) 480 } else if !certNotBefore.Equal(notBefore) { 481 t.Errorf("Got cert notBefore %v, want %v", notBefore.UTC(), certNotBefore.UTC()) 482 } else { 483 t.Logf("NotBefore: %v", notBefore.UTC()) 484 } 485 if notAfter, err := tls.PeerCertNotAfter(); err != nil { 486 t.Errorf("PeerCertNotAfter() returned error: %v", err) 487 } else if !certNotAfter.Equal(notAfter) { 488 t.Errorf("Got cert notAfter %v, want %v", notAfter.UTC(), certNotAfter.UTC()) 489 } else { 490 t.Logf("NotAfter: %v", notAfter.UTC()) 491 } 492} 493