mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-04 09:49:50 +00:00
Merge pull request #14889 from liggitt/honor-skip-validate
Auto commit by PR queue bot
This commit is contained in:
commit
1b653ce1b8
@ -332,6 +332,7 @@ type SimpleRESTStorage struct {
|
|||||||
// The id requested, and location to return for ResourceLocation
|
// The id requested, and location to return for ResourceLocation
|
||||||
requestedResourceLocationID string
|
requestedResourceLocationID string
|
||||||
resourceLocation *url.URL
|
resourceLocation *url.URL
|
||||||
|
resourceLocationTransport http.RoundTripper
|
||||||
expectedResourceNamespace string
|
expectedResourceNamespace string
|
||||||
|
|
||||||
// If non-nil, called inside the WorkFunc when answering update, delete, create.
|
// If non-nil, called inside the WorkFunc when answering update, delete, create.
|
||||||
@ -477,7 +478,7 @@ func (storage *SimpleRESTStorage) ResourceLocation(ctx api.Context, id string) (
|
|||||||
}
|
}
|
||||||
// Make a copy so the internal URL never gets mutated
|
// Make a copy so the internal URL never gets mutated
|
||||||
locationCopy := *storage.resourceLocation
|
locationCopy := *storage.resourceLocation
|
||||||
return &locationCopy, nil, nil
|
return &locationCopy, storage.resourceLocationTransport, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement Connecter
|
// Implement Connecter
|
||||||
|
@ -286,6 +286,11 @@ func dialURL(url *url.URL, transport http.RoundTripper) (net.Conn, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return if we were configured to skip validation
|
||||||
|
if tlsConfig != nil && tlsConfig.InsecureSkipVerify {
|
||||||
|
return tlsConn, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Verify
|
// Verify
|
||||||
host, _, _ := net.SplitHostPort(dialAddr)
|
host, _, _ := net.SplitHostPort(dialAddr)
|
||||||
if err := tlsConn.VerifyHostname(host); err != nil {
|
if err := tlsConn.VerifyHostname(host); err != nil {
|
||||||
|
@ -18,6 +18,8 @@ package apiserver
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -125,43 +127,97 @@ func TestProxy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestProxyUpgrade(t *testing.T) {
|
func TestProxyUpgrade(t *testing.T) {
|
||||||
backendServer := httptest.NewServer(websocket.Handler(func(ws *websocket.Conn) {
|
|
||||||
|
localhostPool := x509.NewCertPool()
|
||||||
|
if !localhostPool.AppendCertsFromPEM(localhostCert) {
|
||||||
|
t.Errorf("error setting up localhostCert pool")
|
||||||
|
}
|
||||||
|
|
||||||
|
testcases := map[string]struct {
|
||||||
|
ServerFunc func(http.Handler) *httptest.Server
|
||||||
|
ProxyTransport http.RoundTripper
|
||||||
|
}{
|
||||||
|
"http": {
|
||||||
|
ServerFunc: httptest.NewServer,
|
||||||
|
ProxyTransport: nil,
|
||||||
|
},
|
||||||
|
"https (invalid hostname + InsecureSkipVerify)": {
|
||||||
|
ServerFunc: func(h http.Handler) *httptest.Server {
|
||||||
|
cert, err := tls.X509KeyPair(exampleCert, exampleKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("https (invalid hostname): proxy_test: %v", err)
|
||||||
|
}
|
||||||
|
ts := httptest.NewUnstartedServer(h)
|
||||||
|
ts.TLS = &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
}
|
||||||
|
ts.StartTLS()
|
||||||
|
return ts
|
||||||
|
},
|
||||||
|
ProxyTransport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}},
|
||||||
|
},
|
||||||
|
"https (valid hostname + RootCAs)": {
|
||||||
|
ServerFunc: func(h http.Handler) *httptest.Server {
|
||||||
|
cert, err := tls.X509KeyPair(localhostCert, localhostKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("https (valid hostname): proxy_test: %v", err)
|
||||||
|
}
|
||||||
|
ts := httptest.NewUnstartedServer(h)
|
||||||
|
ts.TLS = &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
}
|
||||||
|
ts.StartTLS()
|
||||||
|
return ts
|
||||||
|
},
|
||||||
|
ProxyTransport: &http.Transport{TLSClientConfig: &tls.Config{RootCAs: localhostPool}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, tc := range testcases {
|
||||||
|
|
||||||
|
backendServer := tc.ServerFunc(websocket.Handler(func(ws *websocket.Conn) {
|
||||||
|
defer ws.Close()
|
||||||
|
body := make([]byte, 5)
|
||||||
|
ws.Read(body)
|
||||||
|
ws.Write([]byte("hello " + string(body)))
|
||||||
|
}))
|
||||||
|
defer backendServer.Close()
|
||||||
|
|
||||||
|
serverURL, _ := url.Parse(backendServer.URL)
|
||||||
|
simpleStorage := &SimpleRESTStorage{
|
||||||
|
errors: map[string]error{},
|
||||||
|
resourceLocation: serverURL,
|
||||||
|
resourceLocationTransport: tc.ProxyTransport,
|
||||||
|
expectedResourceNamespace: "myns",
|
||||||
|
}
|
||||||
|
|
||||||
|
namespaceHandler := handleNamespaced(map[string]rest.Storage{"foo": simpleStorage})
|
||||||
|
|
||||||
|
server := httptest.NewServer(namespaceHandler)
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
ws, err := websocket.Dial("ws://"+server.Listener.Addr().String()+"/api/version2/proxy/namespaces/myns/foo/123", "", "http://127.0.0.1/")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: websocket dial err: %s", k, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
defer ws.Close()
|
defer ws.Close()
|
||||||
body := make([]byte, 5)
|
|
||||||
ws.Read(body)
|
|
||||||
ws.Write([]byte("hello " + string(body)))
|
|
||||||
}))
|
|
||||||
defer backendServer.Close()
|
|
||||||
|
|
||||||
serverURL, _ := url.Parse(backendServer.URL)
|
if _, err := ws.Write([]byte("world")); err != nil {
|
||||||
simpleStorage := &SimpleRESTStorage{
|
t.Errorf("%s: write err: %s", k, err)
|
||||||
errors: map[string]error{},
|
continue
|
||||||
resourceLocation: serverURL,
|
}
|
||||||
expectedResourceNamespace: "myns",
|
|
||||||
}
|
|
||||||
|
|
||||||
namespaceHandler := handleNamespaced(map[string]rest.Storage{"foo": simpleStorage})
|
response := make([]byte, 20)
|
||||||
|
n, err := ws.Read(response)
|
||||||
server := httptest.NewServer(namespaceHandler)
|
if err != nil {
|
||||||
defer server.Close()
|
t.Errorf("%s: read err: %s", k, err)
|
||||||
|
continue
|
||||||
ws, err := websocket.Dial("ws://"+server.Listener.Addr().String()+"/api/version2/proxy/namespaces/myns/foo/123", "", "http://127.0.0.1/")
|
}
|
||||||
if err != nil {
|
if e, a := "hello world", string(response[0:n]); e != a {
|
||||||
t.Fatalf("websocket dial err: %s", err)
|
t.Errorf("%s: expected '%#v', got '%#v'", k, e, a)
|
||||||
}
|
continue
|
||||||
defer ws.Close()
|
}
|
||||||
|
|
||||||
if _, err := ws.Write([]byte("world")); err != nil {
|
|
||||||
t.Fatalf("write err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
response := make([]byte, 20)
|
|
||||||
n, err := ws.Read(response)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("read err: %s", err)
|
|
||||||
}
|
|
||||||
if e, a := "hello world", string(response[0:n]); e != a {
|
|
||||||
t.Fatalf("expected '%#v', got '%#v'", e, a)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,3 +281,50 @@ func TestRedirectOnMissingTrailingSlash(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// exampleCert was generated from crypto/tls/generate_cert.go with the following command:
|
||||||
|
// go run generate_cert.go --rsa-bits 512 --host example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
||||||
|
var exampleCert = []byte(`-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBcjCCAR6gAwIBAgIQBOUTYowZaENkZi0faI9DgTALBgkqhkiG9w0BAQswEjEQ
|
||||||
|
MA4GA1UEChMHQWNtZSBDbzAgFw03MDAxMDEwMDAwMDBaGA8yMDg0MDEyOTE2MDAw
|
||||||
|
MFowEjEQMA4GA1UEChMHQWNtZSBDbzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCZ
|
||||||
|
xfR3sgeHBraGFfF/24tTn4PRVAHOf2UOOxSQRs+aYjNqimFqf/SRIblQgeXdBJDR
|
||||||
|
gVK5F1Js2zwlehw0bHxRAgMBAAGjUDBOMA4GA1UdDwEB/wQEAwIApDATBgNVHSUE
|
||||||
|
DDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MBYGA1UdEQQPMA2CC2V4YW1w
|
||||||
|
bGUuY29tMAsGCSqGSIb3DQEBCwNBAI/mfBB8dm33IpUl+acSyWfL6gX5Wc0FFyVj
|
||||||
|
dKeesE1XBuPX1My/rzU6Oy/YwX7LOL4FaeNUS6bbL4axSLPKYSs=
|
||||||
|
-----END CERTIFICATE-----`)
|
||||||
|
|
||||||
|
var exampleKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIBOgIBAAJBAJnF9HeyB4cGtoYV8X/bi1Ofg9FUAc5/ZQ47FJBGz5piM2qKYWp/
|
||||||
|
9JEhuVCB5d0EkNGBUrkXUmzbPCV6HDRsfFECAwEAAQJBAJLH9yPuButniACTn5L5
|
||||||
|
IJQw1mWQt6zBw9eCo41YWkA0866EgjC53aPZaRjXMp0uNJGdIsys2V5rCOOLWN2C
|
||||||
|
ODECIQDICHsi8QQQ9wpuJy8X5l8MAfxHL+DIqI84wQTeVM91FQIhAMTME8A18/7h
|
||||||
|
1Ad6drdnxAkuC0tX6Sx0LDozrmen+HFNAiAlcEDrt0RVkIcpOrg7tuhPLQf0oudl
|
||||||
|
Zvb3Xlj069awSQIgcT15E/43w2+RASifzVNhQ2MCTr1sSA8lL+xzK+REmnUCIBhQ
|
||||||
|
j4139pf8Re1J50zBxS/JlQfgDQi9sO9pYeiHIxNs
|
||||||
|
-----END RSA PRIVATE KEY-----`)
|
||||||
|
|
||||||
|
// localhostCert was generated from crypto/tls/generate_cert.go with the following command:
|
||||||
|
// 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
|
||||||
|
var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
|
||||||
|
bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj
|
||||||
|
bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa
|
||||||
|
IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA
|
||||||
|
AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
|
||||||
|
EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk
|
||||||
|
Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA==
|
||||||
|
-----END CERTIFICATE-----`)
|
||||||
|
|
||||||
|
// localhostKey is the private key for localhostCert.
|
||||||
|
var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0
|
||||||
|
0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV
|
||||||
|
NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d
|
||||||
|
AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW
|
||||||
|
MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD
|
||||||
|
EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA
|
||||||
|
1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE=
|
||||||
|
-----END RSA PRIVATE KEY-----`)
|
||||||
|
@ -240,6 +240,11 @@ func (h *UpgradeAwareProxyHandler) dialURL() (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return if we were configured to skip validation
|
||||||
|
if tlsConfig != nil && tlsConfig.InsecureSkipVerify {
|
||||||
|
return tlsConn, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Verify
|
// Verify
|
||||||
host, _, _ := net.SplitHostPort(dialAddr)
|
host, _, _ := net.SplitHostPort(dialAddr)
|
||||||
if err := tlsConn.VerifyHostname(host); err != nil {
|
if err := tlsConn.VerifyHostname(host); err != nil {
|
||||||
|
@ -18,6 +18,8 @@ package rest
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -259,38 +261,88 @@ func TestServeHTTP(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestProxyUpgrade(t *testing.T) {
|
func TestProxyUpgrade(t *testing.T) {
|
||||||
backendServer := httptest.NewServer(websocket.Handler(func(ws *websocket.Conn) {
|
|
||||||
|
localhostPool := x509.NewCertPool()
|
||||||
|
if !localhostPool.AppendCertsFromPEM(localhostCert) {
|
||||||
|
t.Errorf("error setting up localhostCert pool")
|
||||||
|
}
|
||||||
|
|
||||||
|
testcases := map[string]struct {
|
||||||
|
ServerFunc func(http.Handler) *httptest.Server
|
||||||
|
ProxyTransport http.RoundTripper
|
||||||
|
}{
|
||||||
|
"http": {
|
||||||
|
ServerFunc: httptest.NewServer,
|
||||||
|
ProxyTransport: nil,
|
||||||
|
},
|
||||||
|
"https (invalid hostname + InsecureSkipVerify)": {
|
||||||
|
ServerFunc: func(h http.Handler) *httptest.Server {
|
||||||
|
cert, err := tls.X509KeyPair(exampleCert, exampleKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("https (invalid hostname): proxy_test: %v", err)
|
||||||
|
}
|
||||||
|
ts := httptest.NewUnstartedServer(h)
|
||||||
|
ts.TLS = &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
}
|
||||||
|
ts.StartTLS()
|
||||||
|
return ts
|
||||||
|
},
|
||||||
|
ProxyTransport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}},
|
||||||
|
},
|
||||||
|
"https (valid hostname + RootCAs)": {
|
||||||
|
ServerFunc: func(h http.Handler) *httptest.Server {
|
||||||
|
cert, err := tls.X509KeyPair(localhostCert, localhostKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("https (valid hostname): proxy_test: %v", err)
|
||||||
|
}
|
||||||
|
ts := httptest.NewUnstartedServer(h)
|
||||||
|
ts.TLS = &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
}
|
||||||
|
ts.StartTLS()
|
||||||
|
return ts
|
||||||
|
},
|
||||||
|
ProxyTransport: &http.Transport{TLSClientConfig: &tls.Config{RootCAs: localhostPool}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, tc := range testcases {
|
||||||
|
|
||||||
|
backendServer := tc.ServerFunc(websocket.Handler(func(ws *websocket.Conn) {
|
||||||
|
defer ws.Close()
|
||||||
|
body := make([]byte, 5)
|
||||||
|
ws.Read(body)
|
||||||
|
ws.Write([]byte("hello " + string(body)))
|
||||||
|
}))
|
||||||
|
defer backendServer.Close()
|
||||||
|
|
||||||
|
serverURL, _ := url.Parse(backendServer.URL)
|
||||||
|
proxyHandler := &UpgradeAwareProxyHandler{
|
||||||
|
Location: serverURL,
|
||||||
|
Transport: tc.ProxyTransport,
|
||||||
|
}
|
||||||
|
proxy := httptest.NewServer(proxyHandler)
|
||||||
|
defer proxy.Close()
|
||||||
|
|
||||||
|
ws, err := websocket.Dial("ws://"+proxy.Listener.Addr().String()+"/some/path", "", "http://127.0.0.1/")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s: websocket dial err: %s", k, err)
|
||||||
|
}
|
||||||
defer ws.Close()
|
defer ws.Close()
|
||||||
body := make([]byte, 5)
|
|
||||||
ws.Read(body)
|
|
||||||
ws.Write([]byte("hello " + string(body)))
|
|
||||||
}))
|
|
||||||
defer backendServer.Close()
|
|
||||||
|
|
||||||
serverURL, _ := url.Parse(backendServer.URL)
|
if _, err := ws.Write([]byte("world")); err != nil {
|
||||||
proxyHandler := &UpgradeAwareProxyHandler{
|
t.Fatalf("%s: write err: %s", k, err)
|
||||||
Location: serverURL,
|
}
|
||||||
}
|
|
||||||
proxy := httptest.NewServer(proxyHandler)
|
|
||||||
defer proxy.Close()
|
|
||||||
|
|
||||||
ws, err := websocket.Dial("ws://"+proxy.Listener.Addr().String()+"/some/path", "", "http://127.0.0.1/")
|
response := make([]byte, 20)
|
||||||
if err != nil {
|
n, err := ws.Read(response)
|
||||||
t.Fatalf("websocket dial err: %s", err)
|
if err != nil {
|
||||||
}
|
t.Fatalf("%s: read err: %s", k, err)
|
||||||
defer ws.Close()
|
}
|
||||||
|
if e, a := "hello world", string(response[0:n]); e != a {
|
||||||
if _, err := ws.Write([]byte("world")); err != nil {
|
t.Fatalf("%s: expected '%#v', got '%#v'", k, e, a)
|
||||||
t.Fatalf("write err: %s", err)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
response := make([]byte, 20)
|
|
||||||
n, err := ws.Read(response)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("read err: %s", err)
|
|
||||||
}
|
|
||||||
if e, a := "hello world", string(response[0:n]); e != a {
|
|
||||||
t.Fatalf("expected '%#v', got '%#v'", e, a)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,3 +401,50 @@ func TestDefaultProxyTransport(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// exampleCert was generated from crypto/tls/generate_cert.go with the following command:
|
||||||
|
// go run generate_cert.go --rsa-bits 512 --host example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
||||||
|
var exampleCert = []byte(`-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBcjCCAR6gAwIBAgIQBOUTYowZaENkZi0faI9DgTALBgkqhkiG9w0BAQswEjEQ
|
||||||
|
MA4GA1UEChMHQWNtZSBDbzAgFw03MDAxMDEwMDAwMDBaGA8yMDg0MDEyOTE2MDAw
|
||||||
|
MFowEjEQMA4GA1UEChMHQWNtZSBDbzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCZ
|
||||||
|
xfR3sgeHBraGFfF/24tTn4PRVAHOf2UOOxSQRs+aYjNqimFqf/SRIblQgeXdBJDR
|
||||||
|
gVK5F1Js2zwlehw0bHxRAgMBAAGjUDBOMA4GA1UdDwEB/wQEAwIApDATBgNVHSUE
|
||||||
|
DDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MBYGA1UdEQQPMA2CC2V4YW1w
|
||||||
|
bGUuY29tMAsGCSqGSIb3DQEBCwNBAI/mfBB8dm33IpUl+acSyWfL6gX5Wc0FFyVj
|
||||||
|
dKeesE1XBuPX1My/rzU6Oy/YwX7LOL4FaeNUS6bbL4axSLPKYSs=
|
||||||
|
-----END CERTIFICATE-----`)
|
||||||
|
|
||||||
|
var exampleKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIBOgIBAAJBAJnF9HeyB4cGtoYV8X/bi1Ofg9FUAc5/ZQ47FJBGz5piM2qKYWp/
|
||||||
|
9JEhuVCB5d0EkNGBUrkXUmzbPCV6HDRsfFECAwEAAQJBAJLH9yPuButniACTn5L5
|
||||||
|
IJQw1mWQt6zBw9eCo41YWkA0866EgjC53aPZaRjXMp0uNJGdIsys2V5rCOOLWN2C
|
||||||
|
ODECIQDICHsi8QQQ9wpuJy8X5l8MAfxHL+DIqI84wQTeVM91FQIhAMTME8A18/7h
|
||||||
|
1Ad6drdnxAkuC0tX6Sx0LDozrmen+HFNAiAlcEDrt0RVkIcpOrg7tuhPLQf0oudl
|
||||||
|
Zvb3Xlj069awSQIgcT15E/43w2+RASifzVNhQ2MCTr1sSA8lL+xzK+REmnUCIBhQ
|
||||||
|
j4139pf8Re1J50zBxS/JlQfgDQi9sO9pYeiHIxNs
|
||||||
|
-----END RSA PRIVATE KEY-----`)
|
||||||
|
|
||||||
|
// localhostCert was generated from crypto/tls/generate_cert.go with the following command:
|
||||||
|
// 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
|
||||||
|
var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
|
||||||
|
bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj
|
||||||
|
bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa
|
||||||
|
IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA
|
||||||
|
AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
|
||||||
|
EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk
|
||||||
|
Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA==
|
||||||
|
-----END CERTIFICATE-----`)
|
||||||
|
|
||||||
|
// localhostKey is the private key for localhostCert.
|
||||||
|
var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0
|
||||||
|
0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV
|
||||||
|
NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d
|
||||||
|
AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW
|
||||||
|
MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD
|
||||||
|
EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA
|
||||||
|
1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE=
|
||||||
|
-----END RSA PRIVATE KEY-----`)
|
||||||
|
@ -87,6 +87,11 @@ func (s *SpdyRoundTripper) dial(req *http.Request) (net.Conn, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return if we were configured to skip validation
|
||||||
|
if s.tlsConfig != nil && s.tlsConfig.InsecureSkipVerify {
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
host, _, err := net.SplitHostPort(dialAddr)
|
host, _, err := net.SplitHostPort(dialAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -17,64 +17,97 @@ limitations under the License.
|
|||||||
package spdy
|
package spdy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
|
||||||
"encoding/pem"
|
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/util/httpstream"
|
"k8s.io/kubernetes/pkg/util/httpstream"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRoundTripAndNewConnection(t *testing.T) {
|
func TestRoundTripAndNewConnection(t *testing.T) {
|
||||||
testCases := []struct {
|
|
||||||
|
localhostPool := x509.NewCertPool()
|
||||||
|
if !localhostPool.AppendCertsFromPEM(localhostCert) {
|
||||||
|
t.Errorf("error setting up localhostCert pool")
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := map[string]struct {
|
||||||
|
serverFunc func(http.Handler) *httptest.Server
|
||||||
|
clientTLS *tls.Config
|
||||||
serverConnectionHeader string
|
serverConnectionHeader string
|
||||||
serverUpgradeHeader string
|
serverUpgradeHeader string
|
||||||
useTLS bool
|
|
||||||
shouldError bool
|
shouldError bool
|
||||||
}{
|
}{
|
||||||
{
|
"no headers": {
|
||||||
|
serverFunc: httptest.NewServer,
|
||||||
serverConnectionHeader: "",
|
serverConnectionHeader: "",
|
||||||
serverUpgradeHeader: "",
|
serverUpgradeHeader: "",
|
||||||
shouldError: true,
|
shouldError: true,
|
||||||
},
|
},
|
||||||
{
|
"no upgrade header": {
|
||||||
|
serverFunc: httptest.NewServer,
|
||||||
serverConnectionHeader: "Upgrade",
|
serverConnectionHeader: "Upgrade",
|
||||||
serverUpgradeHeader: "",
|
serverUpgradeHeader: "",
|
||||||
shouldError: true,
|
shouldError: true,
|
||||||
},
|
},
|
||||||
{
|
"no connection header": {
|
||||||
|
serverFunc: httptest.NewServer,
|
||||||
serverConnectionHeader: "",
|
serverConnectionHeader: "",
|
||||||
serverUpgradeHeader: "SPDY/3.1",
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
shouldError: true,
|
shouldError: true,
|
||||||
},
|
},
|
||||||
{
|
"http": {
|
||||||
|
serverFunc: httptest.NewServer,
|
||||||
serverConnectionHeader: "Upgrade",
|
serverConnectionHeader: "Upgrade",
|
||||||
serverUpgradeHeader: "SPDY/3.1",
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
shouldError: false,
|
shouldError: false,
|
||||||
},
|
},
|
||||||
{
|
"https (invalid hostname + InsecureSkipVerify)": {
|
||||||
|
serverFunc: func(h http.Handler) *httptest.Server {
|
||||||
|
cert, err := tls.X509KeyPair(exampleCert, exampleKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("https (invalid hostname): proxy_test: %v", err)
|
||||||
|
}
|
||||||
|
ts := httptest.NewUnstartedServer(h)
|
||||||
|
ts.TLS = &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
}
|
||||||
|
ts.StartTLS()
|
||||||
|
return ts
|
||||||
|
},
|
||||||
|
clientTLS: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
serverConnectionHeader: "Upgrade",
|
||||||
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
|
shouldError: false,
|
||||||
|
},
|
||||||
|
"https (valid hostname + RootCAs)": {
|
||||||
|
serverFunc: func(h http.Handler) *httptest.Server {
|
||||||
|
cert, err := tls.X509KeyPair(localhostCert, localhostKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("https (valid hostname): proxy_test: %v", err)
|
||||||
|
}
|
||||||
|
ts := httptest.NewUnstartedServer(h)
|
||||||
|
ts.TLS = &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
}
|
||||||
|
ts.StartTLS()
|
||||||
|
return ts
|
||||||
|
},
|
||||||
|
clientTLS: &tls.Config{RootCAs: localhostPool},
|
||||||
serverConnectionHeader: "Upgrade",
|
serverConnectionHeader: "Upgrade",
|
||||||
serverUpgradeHeader: "SPDY/3.1",
|
serverUpgradeHeader: "SPDY/3.1",
|
||||||
useTLS: true,
|
|
||||||
shouldError: false,
|
shouldError: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, testCase := range testCases {
|
for k, testCase := range testCases {
|
||||||
server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
server := testCase.serverFunc(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
if testCase.shouldError {
|
if testCase.shouldError {
|
||||||
if e, a := httpstream.HeaderUpgrade, req.Header.Get(httpstream.HeaderConnection); e != a {
|
if e, a := httpstream.HeaderUpgrade, req.Header.Get(httpstream.HeaderConnection); e != a {
|
||||||
t.Fatalf("%d: Expected connection=upgrade header, got '%s", i, a)
|
t.Fatalf("%s: Expected connection=upgrade header, got '%s", k, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set(httpstream.HeaderConnection, testCase.serverConnectionHeader)
|
w.Header().Set(httpstream.HeaderConnection, testCase.serverConnectionHeader)
|
||||||
@ -92,102 +125,32 @@ func TestRoundTripAndNewConnection(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if spdyConn == nil {
|
if spdyConn == nil {
|
||||||
t.Fatalf("%d: unexpected nil spdyConn", i)
|
t.Fatalf("%s: unexpected nil spdyConn", k)
|
||||||
}
|
}
|
||||||
defer spdyConn.Close()
|
defer spdyConn.Close()
|
||||||
|
|
||||||
stream := <-streamCh
|
stream := <-streamCh
|
||||||
io.Copy(stream, stream)
|
io.Copy(stream, stream)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
clientTLS := &tls.Config{}
|
|
||||||
|
|
||||||
if testCase.useTLS {
|
|
||||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%d: error generating keypair: %s", i, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
notBefore := time.Now()
|
|
||||||
notAfter := notBefore.Add(1 * time.Hour)
|
|
||||||
|
|
||||||
template := x509.Certificate{
|
|
||||||
SerialNumber: big.NewInt(1),
|
|
||||||
Subject: pkix.Name{
|
|
||||||
Organization: []string{"Localhost Co"},
|
|
||||||
},
|
|
||||||
NotBefore: notBefore,
|
|
||||||
NotAfter: notAfter,
|
|
||||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
|
||||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
|
||||||
BasicConstraintsValid: true,
|
|
||||||
IsCA: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
host := "127.0.0.1"
|
|
||||||
if ip := net.ParseIP(host); ip != nil {
|
|
||||||
template.IPAddresses = append(template.IPAddresses, ip)
|
|
||||||
}
|
|
||||||
template.DNSNames = append(template.DNSNames, host)
|
|
||||||
|
|
||||||
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%d: error creating cert: %s", i, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cert, err := x509.ParseCertificate(derBytes)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%d: error parsing cert: %s", i, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
roots := x509.NewCertPool()
|
|
||||||
roots.AddCert(cert)
|
|
||||||
server.TLS = &tls.Config{
|
|
||||||
RootCAs: roots,
|
|
||||||
}
|
|
||||||
clientTLS.RootCAs = roots
|
|
||||||
|
|
||||||
certBuf := bytes.Buffer{}
|
|
||||||
err = pem.Encode(&certBuf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%d: error encoding cert: %s", i, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
keyBuf := bytes.Buffer{}
|
|
||||||
err = pem.Encode(&keyBuf, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%d: error encoding key: %s", i, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tlsCert, err := tls.X509KeyPair(certBuf.Bytes(), keyBuf.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%d: error calling tls.X509KeyPair: %s", i, err)
|
|
||||||
}
|
|
||||||
server.TLS.Certificates = []tls.Certificate{tlsCert}
|
|
||||||
clientTLS.Certificates = []tls.Certificate{tlsCert}
|
|
||||||
server.StartTLS()
|
|
||||||
} else {
|
|
||||||
server.Start()
|
|
||||||
}
|
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", server.URL, nil)
|
req, err := http.NewRequest("GET", server.URL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%d: Error creating request: %s", i, err)
|
t.Fatalf("%s: Error creating request: %s", k, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
spdyTransport := NewRoundTripper(clientTLS)
|
spdyTransport := NewRoundTripper(testCase.clientTLS)
|
||||||
client := &http.Client{Transport: spdyTransport}
|
client := &http.Client{Transport: spdyTransport}
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%d: unexpected error from client.Do: %s", i, err)
|
t.Fatalf("%s: unexpected error from client.Do: %s", k, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := spdyTransport.NewConnection(resp)
|
conn, err := spdyTransport.NewConnection(resp)
|
||||||
haveErr := err != nil
|
haveErr := err != nil
|
||||||
if e, a := testCase.shouldError, haveErr; e != a {
|
if e, a := testCase.shouldError, haveErr; e != a {
|
||||||
t.Fatalf("%d: shouldError=%t, got %t: %v", i, e, a, err)
|
t.Fatalf("%s: shouldError=%t, got %t: %v", k, e, a, err)
|
||||||
}
|
}
|
||||||
if testCase.shouldError {
|
if testCase.shouldError {
|
||||||
continue
|
continue
|
||||||
@ -195,32 +158,79 @@ func TestRoundTripAndNewConnection(t *testing.T) {
|
|||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusSwitchingProtocols {
|
if resp.StatusCode != http.StatusSwitchingProtocols {
|
||||||
t.Fatalf("%d: expected http 101 switching protocols, got %d", i, resp.StatusCode)
|
t.Fatalf("%s: expected http 101 switching protocols, got %d", k, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
stream, err := conn.CreateStream(http.Header{})
|
stream, err := conn.CreateStream(http.Header{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%d: error creating client stream: %s", i, err)
|
t.Fatalf("%s: error creating client stream: %s", k, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := stream.Write([]byte("hello"))
|
n, err := stream.Write([]byte("hello"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%d: error writing to stream: %s", i, err)
|
t.Fatalf("%s: error writing to stream: %s", k, err)
|
||||||
}
|
}
|
||||||
if n != 5 {
|
if n != 5 {
|
||||||
t.Fatalf("%d: Expected to write 5 bytes, but actually wrote %d", i, n)
|
t.Fatalf("%s: Expected to write 5 bytes, but actually wrote %d", k, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
b := make([]byte, 5)
|
b := make([]byte, 5)
|
||||||
n, err = stream.Read(b)
|
n, err = stream.Read(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%d: error reading from stream: %s", i, err)
|
t.Fatalf("%s: error reading from stream: %s", k, err)
|
||||||
}
|
}
|
||||||
if n != 5 {
|
if n != 5 {
|
||||||
t.Fatalf("%d: Expected to read 5 bytes, but actually read %d", i, n)
|
t.Fatalf("%s: Expected to read 5 bytes, but actually read %d", k, n)
|
||||||
}
|
}
|
||||||
if e, a := "hello", string(b[0:n]); e != a {
|
if e, a := "hello", string(b[0:n]); e != a {
|
||||||
t.Fatalf("%d: expected '%s', got '%s'", i, e, a)
|
t.Fatalf("%s: expected '%s', got '%s'", k, e, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// exampleCert was generated from crypto/tls/generate_cert.go with the following command:
|
||||||
|
// go run generate_cert.go --rsa-bits 512 --host example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
||||||
|
var exampleCert = []byte(`-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBcjCCAR6gAwIBAgIQBOUTYowZaENkZi0faI9DgTALBgkqhkiG9w0BAQswEjEQ
|
||||||
|
MA4GA1UEChMHQWNtZSBDbzAgFw03MDAxMDEwMDAwMDBaGA8yMDg0MDEyOTE2MDAw
|
||||||
|
MFowEjEQMA4GA1UEChMHQWNtZSBDbzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCZ
|
||||||
|
xfR3sgeHBraGFfF/24tTn4PRVAHOf2UOOxSQRs+aYjNqimFqf/SRIblQgeXdBJDR
|
||||||
|
gVK5F1Js2zwlehw0bHxRAgMBAAGjUDBOMA4GA1UdDwEB/wQEAwIApDATBgNVHSUE
|
||||||
|
DDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MBYGA1UdEQQPMA2CC2V4YW1w
|
||||||
|
bGUuY29tMAsGCSqGSIb3DQEBCwNBAI/mfBB8dm33IpUl+acSyWfL6gX5Wc0FFyVj
|
||||||
|
dKeesE1XBuPX1My/rzU6Oy/YwX7LOL4FaeNUS6bbL4axSLPKYSs=
|
||||||
|
-----END CERTIFICATE-----`)
|
||||||
|
|
||||||
|
var exampleKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIBOgIBAAJBAJnF9HeyB4cGtoYV8X/bi1Ofg9FUAc5/ZQ47FJBGz5piM2qKYWp/
|
||||||
|
9JEhuVCB5d0EkNGBUrkXUmzbPCV6HDRsfFECAwEAAQJBAJLH9yPuButniACTn5L5
|
||||||
|
IJQw1mWQt6zBw9eCo41YWkA0866EgjC53aPZaRjXMp0uNJGdIsys2V5rCOOLWN2C
|
||||||
|
ODECIQDICHsi8QQQ9wpuJy8X5l8MAfxHL+DIqI84wQTeVM91FQIhAMTME8A18/7h
|
||||||
|
1Ad6drdnxAkuC0tX6Sx0LDozrmen+HFNAiAlcEDrt0RVkIcpOrg7tuhPLQf0oudl
|
||||||
|
Zvb3Xlj069awSQIgcT15E/43w2+RASifzVNhQ2MCTr1sSA8lL+xzK+REmnUCIBhQ
|
||||||
|
j4139pf8Re1J50zBxS/JlQfgDQi9sO9pYeiHIxNs
|
||||||
|
-----END RSA PRIVATE KEY-----`)
|
||||||
|
|
||||||
|
// localhostCert was generated from crypto/tls/generate_cert.go with the following command:
|
||||||
|
// 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
|
||||||
|
var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
|
||||||
|
bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj
|
||||||
|
bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa
|
||||||
|
IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA
|
||||||
|
AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
|
||||||
|
EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA
|
||||||
|
AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk
|
||||||
|
Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA==
|
||||||
|
-----END CERTIFICATE-----`)
|
||||||
|
|
||||||
|
// localhostKey is the private key for localhostCert.
|
||||||
|
var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0
|
||||||
|
0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV
|
||||||
|
NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d
|
||||||
|
AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW
|
||||||
|
MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD
|
||||||
|
EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA
|
||||||
|
1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE=
|
||||||
|
-----END RSA PRIVATE KEY-----`)
|
||||||
|
Loading…
Reference in New Issue
Block a user