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. 4 5 package smtp 6 7 import ( 8 "bufio" 9 "bytes" 10 "crypto/tls" 11 "crypto/x509" 12 "io" 13 "net" 14 "net/textproto" 15 "strings" 16 "testing" 17 "time" 18 ) 19 20 type authTest struct { 21 auth Auth 22 challenges []string 23 name string 24 responses []string 25 } 26 27 var authTests = []authTest{ 28 {PlainAuth("", "user", "pass", "testserver"), []string{}, "PLAIN", []string{"\x00user\x00pass"}}, 29 {PlainAuth("foo", "bar", "baz", "testserver"), []string{}, "PLAIN", []string{"foo\x00bar\x00baz"}}, 30 {CRAMMD5Auth("user", "pass"), []string{"<123456.1322876914@testserver>"}, "CRAM-MD5", []string{"", "user 287eb355114cf5c471c26a875f1ca4ae"}}, 31 } 32 33 func TestAuth(t *testing.T) { 34 testLoop: 35 for i, test := range authTests { 36 name, resp, err := test.auth.Start(&ServerInfo{"testserver", true, nil}) 37 if name != test.name { 38 t.Errorf("#%d got name %s, expected %s", i, name, test.name) 39 } 40 if !bytes.Equal(resp, []byte(test.responses[0])) { 41 t.Errorf("#%d got response %s, expected %s", i, resp, test.responses[0]) 42 } 43 if err != nil { 44 t.Errorf("#%d error: %s", i, err) 45 } 46 for j := range test.challenges { 47 challenge := []byte(test.challenges[j]) 48 expected := []byte(test.responses[j+1]) 49 resp, err := test.auth.Next(challenge, true) 50 if err != nil { 51 t.Errorf("#%d error: %s", i, err) 52 continue testLoop 53 } 54 if !bytes.Equal(resp, expected) { 55 t.Errorf("#%d got %s, expected %s", i, resp, expected) 56 continue testLoop 57 } 58 } 59 } 60 } 61 62 func TestAuthPlain(t *testing.T) { 63 auth := PlainAuth("foo", "bar", "baz", "servername") 64 65 tests := []struct { 66 server *ServerInfo 67 err string 68 }{ 69 { 70 server: &ServerInfo{Name: "servername", TLS: true}, 71 }, 72 { 73 // Okay; explicitly advertised by server. 74 server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}}, 75 }, 76 { 77 server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}}, 78 err: "unencrypted connection", 79 }, 80 { 81 server: &ServerInfo{Name: "attacker", TLS: true}, 82 err: "wrong host name", 83 }, 84 } 85 for i, tt := range tests { 86 _, _, err := auth.Start(tt.server) 87 got := "" 88 if err != nil { 89 got = err.Error() 90 } 91 if got != tt.err { 92 t.Errorf("%d. got error = %q; want %q", i, got, tt.err) 93 } 94 } 95 } 96 97 type faker struct { 98 io.ReadWriter 99 } 100 101 func (f faker) Close() error { return nil } 102 func (f faker) LocalAddr() net.Addr { return nil } 103 func (f faker) RemoteAddr() net.Addr { return nil } 104 func (f faker) SetDeadline(time.Time) error { return nil } 105 func (f faker) SetReadDeadline(time.Time) error { return nil } 106 func (f faker) SetWriteDeadline(time.Time) error { return nil } 107 108 func TestBasic(t *testing.T) { 109 server := strings.Join(strings.Split(basicServer, "\n"), "\r\n") 110 client := strings.Join(strings.Split(basicClient, "\n"), "\r\n") 111 112 var cmdbuf bytes.Buffer 113 bcmdbuf := bufio.NewWriter(&cmdbuf) 114 var fake faker 115 fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(server)), bcmdbuf) 116 c := &Client{Text: textproto.NewConn(fake), localName: "localhost"} 117 118 if err := c.helo(); err != nil { 119 t.Fatalf("HELO failed: %s", err) 120 } 121 if err := c.ehlo(); err == nil { 122 t.Fatalf("Expected first EHLO to fail") 123 } 124 if err := c.ehlo(); err != nil { 125 t.Fatalf("Second EHLO failed: %s", err) 126 } 127 128 c.didHello = true 129 if ok, args := c.Extension("aUtH"); !ok || args != "LOGIN PLAIN" { 130 t.Fatalf("Expected AUTH supported") 131 } 132 if ok, _ := c.Extension("DSN"); ok { 133 t.Fatalf("Shouldn't support DSN") 134 } 135 136 if err := c.Mail("user (a] gmail.com"); err == nil { 137 t.Fatalf("MAIL should require authentication") 138 } 139 140 if err := c.Verify("user1 (a] gmail.com"); err == nil { 141 t.Fatalf("First VRFY: expected no verification") 142 } 143 if err := c.Verify("user2 (a] gmail.com"); err != nil { 144 t.Fatalf("Second VRFY: expected verification, got %s", err) 145 } 146 147 // fake TLS so authentication won't complain 148 c.tls = true 149 c.serverName = "smtp.google.com" 150 if err := c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")); err != nil { 151 t.Fatalf("AUTH failed: %s", err) 152 } 153 154 if err := c.Mail("user (a] gmail.com"); err != nil { 155 t.Fatalf("MAIL failed: %s", err) 156 } 157 if err := c.Rcpt("golang-nuts (a] googlegroups.com"); err != nil { 158 t.Fatalf("RCPT failed: %s", err) 159 } 160 msg := `From: user (a] gmail.com 161 To: golang-nuts (a] googlegroups.com 162 Subject: Hooray for Go 163 164 Line 1 165 .Leading dot line . 166 Goodbye.` 167 w, err := c.Data() 168 if err != nil { 169 t.Fatalf("DATA failed: %s", err) 170 } 171 if _, err := w.Write([]byte(msg)); err != nil { 172 t.Fatalf("Data write failed: %s", err) 173 } 174 if err := w.Close(); err != nil { 175 t.Fatalf("Bad data response: %s", err) 176 } 177 178 if err := c.Quit(); err != nil { 179 t.Fatalf("QUIT failed: %s", err) 180 } 181 182 bcmdbuf.Flush() 183 actualcmds := cmdbuf.String() 184 if client != actualcmds { 185 t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, client) 186 } 187 } 188 189 var basicServer = `250 mx.google.com at your service 190 502 Unrecognized command. 191 250-mx.google.com at your service 192 250-SIZE 35651584 193 250-AUTH LOGIN PLAIN 194 250 8BITMIME 195 530 Authentication required 196 252 Send some mail, I'll try my best 197 250 User is valid 198 235 Accepted 199 250 Sender OK 200 250 Receiver OK 201 354 Go ahead 202 250 Data OK 203 221 OK 204 ` 205 206 var basicClient = `HELO localhost 207 EHLO localhost 208 EHLO localhost 209 MAIL FROM:<user (a] gmail.com> BODY=8BITMIME 210 VRFY user1 (a] gmail.com 211 VRFY user2 (a] gmail.com 212 AUTH PLAIN AHVzZXIAcGFzcw== 213 MAIL FROM:<user (a] gmail.com> BODY=8BITMIME 214 RCPT TO:<golang-nuts (a] googlegroups.com> 215 DATA 216 From: user (a] gmail.com 217 To: golang-nuts (a] googlegroups.com 218 Subject: Hooray for Go 219 220 Line 1 221 ..Leading dot line . 222 Goodbye. 223 . 224 QUIT 225 ` 226 227 func TestNewClient(t *testing.T) { 228 server := strings.Join(strings.Split(newClientServer, "\n"), "\r\n") 229 client := strings.Join(strings.Split(newClientClient, "\n"), "\r\n") 230 231 var cmdbuf bytes.Buffer 232 bcmdbuf := bufio.NewWriter(&cmdbuf) 233 out := func() string { 234 bcmdbuf.Flush() 235 return cmdbuf.String() 236 } 237 var fake faker 238 fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(server)), bcmdbuf) 239 c, err := NewClient(fake, "fake.host") 240 if err != nil { 241 t.Fatalf("NewClient: %v\n(after %v)", err, out()) 242 } 243 defer c.Close() 244 if ok, args := c.Extension("aUtH"); !ok || args != "LOGIN PLAIN" { 245 t.Fatalf("Expected AUTH supported") 246 } 247 if ok, _ := c.Extension("DSN"); ok { 248 t.Fatalf("Shouldn't support DSN") 249 } 250 if err := c.Quit(); err != nil { 251 t.Fatalf("QUIT failed: %s", err) 252 } 253 254 actualcmds := out() 255 if client != actualcmds { 256 t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, client) 257 } 258 } 259 260 var newClientServer = `220 hello world 261 250-mx.google.com at your service 262 250-SIZE 35651584 263 250-AUTH LOGIN PLAIN 264 250 8BITMIME 265 221 OK 266 ` 267 268 var newClientClient = `EHLO localhost 269 QUIT 270 ` 271 272 func TestNewClient2(t *testing.T) { 273 server := strings.Join(strings.Split(newClient2Server, "\n"), "\r\n") 274 client := strings.Join(strings.Split(newClient2Client, "\n"), "\r\n") 275 276 var cmdbuf bytes.Buffer 277 bcmdbuf := bufio.NewWriter(&cmdbuf) 278 var fake faker 279 fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(server)), bcmdbuf) 280 c, err := NewClient(fake, "fake.host") 281 if err != nil { 282 t.Fatalf("NewClient: %v", err) 283 } 284 defer c.Close() 285 if ok, _ := c.Extension("DSN"); ok { 286 t.Fatalf("Shouldn't support DSN") 287 } 288 if err := c.Quit(); err != nil { 289 t.Fatalf("QUIT failed: %s", err) 290 } 291 292 bcmdbuf.Flush() 293 actualcmds := cmdbuf.String() 294 if client != actualcmds { 295 t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, client) 296 } 297 } 298 299 var newClient2Server = `220 hello world 300 502 EH? 301 250-mx.google.com at your service 302 250-SIZE 35651584 303 250-AUTH LOGIN PLAIN 304 250 8BITMIME 305 221 OK 306 ` 307 308 var newClient2Client = `EHLO localhost 309 HELO localhost 310 QUIT 311 ` 312 313 func TestHello(t *testing.T) { 314 315 if len(helloServer) != len(helloClient) { 316 t.Fatalf("Hello server and client size mismatch") 317 } 318 319 for i := 0; i < len(helloServer); i++ { 320 server := strings.Join(strings.Split(baseHelloServer+helloServer[i], "\n"), "\r\n") 321 client := strings.Join(strings.Split(baseHelloClient+helloClient[i], "\n"), "\r\n") 322 var cmdbuf bytes.Buffer 323 bcmdbuf := bufio.NewWriter(&cmdbuf) 324 var fake faker 325 fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(server)), bcmdbuf) 326 c, err := NewClient(fake, "fake.host") 327 if err != nil { 328 t.Fatalf("NewClient: %v", err) 329 } 330 defer c.Close() 331 c.localName = "customhost" 332 err = nil 333 334 switch i { 335 case 0: 336 err = c.Hello("customhost") 337 case 1: 338 err = c.StartTLS(nil) 339 if err.Error() == "502 Not implemented" { 340 err = nil 341 } 342 case 2: 343 err = c.Verify("test (a] example.com") 344 case 3: 345 c.tls = true 346 c.serverName = "smtp.google.com" 347 err = c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")) 348 case 4: 349 err = c.Mail("test (a] example.com") 350 case 5: 351 ok, _ := c.Extension("feature") 352 if ok { 353 t.Errorf("Expected FEATURE not to be supported") 354 } 355 case 6: 356 err = c.Reset() 357 case 7: 358 err = c.Quit() 359 case 8: 360 err = c.Verify("test (a] example.com") 361 if err != nil { 362 err = c.Hello("customhost") 363 if err != nil { 364 t.Errorf("Want error, got none") 365 } 366 } 367 default: 368 t.Fatalf("Unhandled command") 369 } 370 371 if err != nil { 372 t.Errorf("Command %d failed: %v", i, err) 373 } 374 375 bcmdbuf.Flush() 376 actualcmds := cmdbuf.String() 377 if client != actualcmds { 378 t.Errorf("Got:\n%s\nExpected:\n%s", actualcmds, client) 379 } 380 } 381 } 382 383 var baseHelloServer = `220 hello world 384 502 EH? 385 250-mx.google.com at your service 386 250 FEATURE 387 ` 388 389 var helloServer = []string{ 390 "", 391 "502 Not implemented\n", 392 "250 User is valid\n", 393 "235 Accepted\n", 394 "250 Sender ok\n", 395 "", 396 "250 Reset ok\n", 397 "221 Goodbye\n", 398 "250 Sender ok\n", 399 } 400 401 var baseHelloClient = `EHLO customhost 402 HELO customhost 403 ` 404 405 var helloClient = []string{ 406 "", 407 "STARTTLS\n", 408 "VRFY test (a] example.com\n", 409 "AUTH PLAIN AHVzZXIAcGFzcw==\n", 410 "MAIL FROM:<test (a] example.com>\n", 411 "", 412 "RSET\n", 413 "QUIT\n", 414 "VRFY test (a] example.com\n", 415 } 416 417 func TestSendMail(t *testing.T) { 418 server := strings.Join(strings.Split(sendMailServer, "\n"), "\r\n") 419 client := strings.Join(strings.Split(sendMailClient, "\n"), "\r\n") 420 var cmdbuf bytes.Buffer 421 bcmdbuf := bufio.NewWriter(&cmdbuf) 422 l, err := net.Listen("tcp", "127.0.0.1:0") 423 if err != nil { 424 t.Fatalf("Unable to to create listener: %v", err) 425 } 426 defer l.Close() 427 428 // prevent data race on bcmdbuf 429 var done = make(chan struct{}) 430 go func(data []string) { 431 432 defer close(done) 433 434 conn, err := l.Accept() 435 if err != nil { 436 t.Errorf("Accept error: %v", err) 437 return 438 } 439 defer conn.Close() 440 441 tc := textproto.NewConn(conn) 442 for i := 0; i < len(data) && data[i] != ""; i++ { 443 tc.PrintfLine(data[i]) 444 for len(data[i]) >= 4 && data[i][3] == '-' { 445 i++ 446 tc.PrintfLine(data[i]) 447 } 448 if data[i] == "221 Goodbye" { 449 return 450 } 451 read := false 452 for !read || data[i] == "354 Go ahead" { 453 msg, err := tc.ReadLine() 454 bcmdbuf.Write([]byte(msg + "\r\n")) 455 read = true 456 if err != nil { 457 t.Errorf("Read error: %v", err) 458 return 459 } 460 if data[i] == "354 Go ahead" && msg == "." { 461 break 462 } 463 } 464 } 465 }(strings.Split(server, "\r\n")) 466 467 err = SendMail(l.Addr().String(), nil, "test (a] example.com", []string{"other (a] example.com"}, []byte(strings.Replace(`From: test (a] example.com 468 To: other (a] example.com 469 Subject: SendMail test 470 471 SendMail is working for me. 472 `, "\n", "\r\n", -1))) 473 474 if err != nil { 475 t.Errorf("%v", err) 476 } 477 478 <-done 479 bcmdbuf.Flush() 480 actualcmds := cmdbuf.String() 481 if client != actualcmds { 482 t.Errorf("Got:\n%s\nExpected:\n%s", actualcmds, client) 483 } 484 } 485 486 var sendMailServer = `220 hello world 487 502 EH? 488 250 mx.google.com at your service 489 250 Sender ok 490 250 Receiver ok 491 354 Go ahead 492 250 Data ok 493 221 Goodbye 494 ` 495 496 var sendMailClient = `EHLO localhost 497 HELO localhost 498 MAIL FROM:<test (a] example.com> 499 RCPT TO:<other (a] example.com> 500 DATA 501 From: test (a] example.com 502 To: other (a] example.com 503 Subject: SendMail test 504 505 SendMail is working for me. 506 . 507 QUIT 508 ` 509 510 func TestAuthFailed(t *testing.T) { 511 server := strings.Join(strings.Split(authFailedServer, "\n"), "\r\n") 512 client := strings.Join(strings.Split(authFailedClient, "\n"), "\r\n") 513 var cmdbuf bytes.Buffer 514 bcmdbuf := bufio.NewWriter(&cmdbuf) 515 var fake faker 516 fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(server)), bcmdbuf) 517 c, err := NewClient(fake, "fake.host") 518 if err != nil { 519 t.Fatalf("NewClient: %v", err) 520 } 521 defer c.Close() 522 523 c.tls = true 524 c.serverName = "smtp.google.com" 525 err = c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")) 526 527 if err == nil { 528 t.Error("Auth: expected error; got none") 529 } else if err.Error() != "535 Invalid credentials\nplease see www.example.com" { 530 t.Errorf("Auth: got error: %v, want: %s", err, "535 Invalid credentials\nplease see www.example.com") 531 } 532 533 bcmdbuf.Flush() 534 actualcmds := cmdbuf.String() 535 if client != actualcmds { 536 t.Errorf("Got:\n%s\nExpected:\n%s", actualcmds, client) 537 } 538 } 539 540 var authFailedServer = `220 hello world 541 250-mx.google.com at your service 542 250 AUTH LOGIN PLAIN 543 535-Invalid credentials 544 535 please see www.example.com 545 221 Goodbye 546 ` 547 548 var authFailedClient = `EHLO localhost 549 AUTH PLAIN AHVzZXIAcGFzcw== 550 * 551 QUIT 552 ` 553 554 func TestTLSClient(t *testing.T) { 555 ln := newLocalListener(t) 556 defer ln.Close() 557 errc := make(chan error) 558 go func() { 559 errc <- sendMail(ln.Addr().String()) 560 }() 561 conn, err := ln.Accept() 562 if err != nil { 563 t.Fatalf("failed to accept connection: %v", err) 564 } 565 defer conn.Close() 566 if err := serverHandle(conn, t); err != nil { 567 t.Fatalf("failed to handle connection: %v", err) 568 } 569 if err := <-errc; err != nil { 570 t.Fatalf("client error: %v", err) 571 } 572 } 573 574 func TestTLSConnState(t *testing.T) { 575 ln := newLocalListener(t) 576 defer ln.Close() 577 clientDone := make(chan bool) 578 serverDone := make(chan bool) 579 go func() { 580 defer close(serverDone) 581 c, err := ln.Accept() 582 if err != nil { 583 t.Errorf("Server accept: %v", err) 584 return 585 } 586 defer c.Close() 587 if err := serverHandle(c, t); err != nil { 588 t.Errorf("server error: %v", err) 589 } 590 }() 591 go func() { 592 defer close(clientDone) 593 c, err := Dial(ln.Addr().String()) 594 if err != nil { 595 t.Errorf("Client dial: %v", err) 596 return 597 } 598 defer c.Quit() 599 cfg := &tls.Config{ServerName: "example.com"} 600 testHookStartTLS(cfg) // set the RootCAs 601 if err := c.StartTLS(cfg); err != nil { 602 t.Errorf("StartTLS: %v", err) 603 return 604 } 605 cs, ok := c.TLSConnectionState() 606 if !ok { 607 t.Errorf("TLSConnectionState returned ok == false; want true") 608 return 609 } 610 if cs.Version == 0 || !cs.HandshakeComplete { 611 t.Errorf("ConnectionState = %#v; expect non-zero Version and HandshakeComplete", cs) 612 } 613 }() 614 <-clientDone 615 <-serverDone 616 } 617 618 func newLocalListener(t *testing.T) net.Listener { 619 ln, err := net.Listen("tcp", "127.0.0.1:0") 620 if err != nil { 621 ln, err = net.Listen("tcp6", "[::1]:0") 622 } 623 if err != nil { 624 t.Fatal(err) 625 } 626 return ln 627 } 628 629 type smtpSender struct { 630 w io.Writer 631 } 632 633 func (s smtpSender) send(f string) { 634 s.w.Write([]byte(f + "\r\n")) 635 } 636 637 // smtp server, finely tailored to deal with our own client only! 638 func serverHandle(c net.Conn, t *testing.T) error { 639 send := smtpSender{c}.send 640 send("220 127.0.0.1 ESMTP service ready") 641 s := bufio.NewScanner(c) 642 for s.Scan() { 643 switch s.Text() { 644 case "EHLO localhost": 645 send("250-127.0.0.1 ESMTP offers a warm hug of welcome") 646 send("250-STARTTLS") 647 send("250 Ok") 648 case "STARTTLS": 649 send("220 Go ahead") 650 keypair, err := tls.X509KeyPair(localhostCert, localhostKey) 651 if err != nil { 652 return err 653 } 654 config := &tls.Config{Certificates: []tls.Certificate{keypair}} 655 c = tls.Server(c, config) 656 defer c.Close() 657 return serverHandleTLS(c, t) 658 default: 659 t.Fatalf("unrecognized command: %q", s.Text()) 660 } 661 } 662 return s.Err() 663 } 664 665 func serverHandleTLS(c net.Conn, t *testing.T) error { 666 send := smtpSender{c}.send 667 s := bufio.NewScanner(c) 668 for s.Scan() { 669 switch s.Text() { 670 case "EHLO localhost": 671 send("250 Ok") 672 case "MAIL FROM:<joe1 (a] example.com>": 673 send("250 Ok") 674 case "RCPT TO:<joe2 (a] example.com>": 675 send("250 Ok") 676 case "DATA": 677 send("354 send the mail data, end with .") 678 send("250 Ok") 679 case "Subject: test": 680 case "": 681 case "howdy!": 682 case ".": 683 case "QUIT": 684 send("221 127.0.0.1 Service closing transmission channel") 685 return nil 686 default: 687 t.Fatalf("unrecognized command during TLS: %q", s.Text()) 688 } 689 } 690 return s.Err() 691 } 692 693 func init() { 694 testRootCAs := x509.NewCertPool() 695 testRootCAs.AppendCertsFromPEM(localhostCert) 696 testHookStartTLS = func(config *tls.Config) { 697 config.RootCAs = testRootCAs 698 } 699 } 700 701 func sendMail(hostPort string) error { 702 host, _, err := net.SplitHostPort(hostPort) 703 if err != nil { 704 return err 705 } 706 auth := PlainAuth("", "", "", host) 707 from := "joe1 (a] example.com" 708 to := []string{"joe2 (a] example.com"} 709 return SendMail(hostPort, auth, from, to, []byte("Subject: test\n\nhowdy!")) 710 } 711 712 // (copied from net/http/httptest) 713 // localhostCert is a PEM-encoded TLS cert with SAN IPs 714 // "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end 715 // of ASN.1 time). 716 // generated from src/crypto/tls: 717 // go run generate_cert.go --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h 718 var localhostCert = []byte(`-----BEGIN CERTIFICATE----- 719 MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD 720 bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj 721 bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa 722 IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA 723 AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud 724 EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA 725 AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk 726 Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA== 727 -----END CERTIFICATE-----`) 728 729 // localhostKey is the private key for localhostCert. 730 var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY----- 731 MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0 732 0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV 733 NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d 734 AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW 735 MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD 736 EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA 737 1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE= 738 -----END RSA PRIVATE KEY-----`) 739