-
Notifications
You must be signed in to change notification settings - Fork 567
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: jslobodzian <[email protected]>
- Loading branch information
1 parent
c1b9c78
commit 5bc0e1c
Showing
4 changed files
with
458 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,375 @@ | ||
From 7497e402bf9885dfcffdd8235a6c16e134a50c1c Mon Sep 17 00:00:00 2001 | ||
From: Kanishk Bansal <[email protected]> | ||
Date: Tue, 4 Feb 2025 13:32:55 +0000 | ||
Subject: [PATCH] Address CVE-2024-45336 | ||
|
||
--- | ||
src/net/http/client.go | 65 ++++++------ | ||
src/net/http/client_test.go | 111 +++++++++++++++------ | ||
src/net/http/internal/testcert/testcert.go | 84 ++++++++-------- | ||
3 files changed, 154 insertions(+), 106 deletions(-) | ||
|
||
diff --git a/src/net/http/client.go b/src/net/http/client.go | ||
index 8fc348f..23f4d81 100644 | ||
--- a/src/net/http/client.go | ||
+++ b/src/net/http/client.go | ||
@@ -612,8 +612,9 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { | ||
reqBodyClosed = false // have we closed the current req.Body? | ||
|
||
// Redirect behavior: | ||
- redirectMethod string | ||
- includeBody bool | ||
+ redirectMethod string | ||
+ includeBody = true | ||
+ stripSensitiveHeaders = false | ||
) | ||
uerr := func(err error) error { | ||
// the body may have been closed already by c.send() | ||
@@ -680,7 +681,12 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { | ||
// in case the user set Referer on their first request. | ||
// If they really want to override, they can do it in | ||
// their CheckRedirect func. | ||
- copyHeaders(req) | ||
+ if !stripSensitiveHeaders && reqs[0].URL.Host != req.URL.Host { | ||
+ if !shouldCopyHeaderOnRedirect(reqs[0].URL, req.URL) { | ||
+ stripSensitiveHeaders = true | ||
+ } | ||
+ } | ||
+ copyHeaders(req, stripSensitiveHeaders) | ||
|
||
// Add the Referer header from the most recent | ||
// request URL to the new one, if it's not https->http: | ||
@@ -746,7 +752,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { | ||
// makeHeadersCopier makes a function that copies headers from the | ||
// initial Request, ireq. For every redirect, this function must be called | ||
// so that it can copy headers into the upcoming Request. | ||
-func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { | ||
+func (c *Client) makeHeadersCopier(ireq *Request) func(req *Request, stripSensitiveHeaders bool) { | ||
// The headers to copy are from the very initial request. | ||
// We use a closured callback to keep a reference to these original headers. | ||
var ( | ||
@@ -760,8 +766,7 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { | ||
} | ||
} | ||
|
||
- preq := ireq // The previous request | ||
- return func(req *Request) { | ||
+ return func(req *Request, stripSensitiveHeaders bool) { | ||
// If Jar is present and there was some initial cookies provided | ||
// via the request header, then we may need to alter the initial | ||
// cookies as we follow redirects since each redirect may end up | ||
@@ -798,12 +803,15 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { | ||
// Copy the initial request's Header values | ||
// (at least the safe ones). | ||
for k, vv := range ireqhdr { | ||
- if shouldCopyHeaderOnRedirect(k, preq.URL, req.URL) { | ||
+ sensitive := false | ||
+ switch CanonicalHeaderKey(k) { | ||
+ case "Authorization", "Www-Authenticate", "Cookie", "Cookie2": | ||
+ sensitive = true | ||
+ } | ||
+ if !(sensitive && stripSensitiveHeaders) { | ||
req.Header[k] = vv | ||
} | ||
} | ||
- | ||
- preq = req // Update previous Request with the current request | ||
} | ||
} | ||
|
||
@@ -982,28 +990,23 @@ func (b *cancelTimerBody) Close() error { | ||
return err | ||
} | ||
|
||
-func shouldCopyHeaderOnRedirect(headerKey string, initial, dest *url.URL) bool { | ||
- switch CanonicalHeaderKey(headerKey) { | ||
- case "Authorization", "Www-Authenticate", "Cookie", "Cookie2": | ||
- // Permit sending auth/cookie headers from "foo.com" | ||
- // to "sub.foo.com". | ||
- | ||
- // Note that we don't send all cookies to subdomains | ||
- // automatically. This function is only used for | ||
- // Cookies set explicitly on the initial outgoing | ||
- // client request. Cookies automatically added via the | ||
- // CookieJar mechanism continue to follow each | ||
- // cookie's scope as set by Set-Cookie. But for | ||
- // outgoing requests with the Cookie header set | ||
- // directly, we don't know their scope, so we assume | ||
- // it's for *.domain.com. | ||
- | ||
- ihost := idnaASCIIFromURL(initial) | ||
- dhost := idnaASCIIFromURL(dest) | ||
- return isDomainOrSubdomain(dhost, ihost) | ||
- } | ||
- // All other headers are copied: | ||
- return true | ||
+func shouldCopyHeaderOnRedirect(initial, dest *url.URL) bool { | ||
+ // Permit sending auth/cookie headers from "foo.com" | ||
+ // to "sub.foo.com". | ||
+ | ||
+ // Note that we don't send all cookies to subdomains | ||
+ // automatically. This function is only used for | ||
+ // Cookies set explicitly on the initial outgoing | ||
+ // client request. Cookies automatically added via the | ||
+ // CookieJar mechanism continue to follow each | ||
+ // cookie's scope as set by Set-Cookie. But for | ||
+ // outgoing requests with the Cookie header set | ||
+ // directly, we don't know their scope, so we assume | ||
+ // it's for *.domain.com. | ||
+ | ||
+ ihost := idnaASCIIFromURL(initial) | ||
+ dhost := idnaASCIIFromURL(dest) | ||
+ return isDomainOrSubdomain(dhost, ihost) | ||
} | ||
|
||
// isDomainOrSubdomain reports whether sub is a subdomain (or exact | ||
diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go | ||
index e2a1cbb..641d7ff 100644 | ||
--- a/src/net/http/client_test.go | ||
+++ b/src/net/http/client_test.go | ||
@@ -1530,6 +1530,55 @@ func testClientCopyHeadersOnRedirect(t *testing.T, mode testMode) { | ||
} | ||
} | ||
|
||
+// Issue #70530: Once we strip a header on a redirect to a different host, | ||
+// the header should stay stripped across any further redirects. | ||
+func TestClientStripHeadersOnRepeatedRedirect(t *testing.T) { | ||
+ run(t, testClientStripHeadersOnRepeatedRedirect) | ||
+} | ||
+func testClientStripHeadersOnRepeatedRedirect(t *testing.T, mode testMode) { | ||
+ var proto string | ||
+ ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { | ||
+ if r.Host+r.URL.Path != "a.example.com/" { | ||
+ if h := r.Header.Get("Authorization"); h != "" { | ||
+ t.Errorf("on request to %v%v, Authorization=%q, want no header", r.Host, r.URL.Path, h) | ||
+ } | ||
+ } | ||
+ // Follow a chain of redirects from a to b and back to a. | ||
+ // The Authorization header is stripped on the first redirect to b, | ||
+ // and stays stripped even if we're sent back to a. | ||
+ switch r.Host + r.URL.Path { | ||
+ case "a.example.com/": | ||
+ Redirect(w, r, proto+"://b.example.com/", StatusFound) | ||
+ case "b.example.com/": | ||
+ Redirect(w, r, proto+"://b.example.com/redirect", StatusFound) | ||
+ case "b.example.com/redirect": | ||
+ Redirect(w, r, proto+"://a.example.com/redirect", StatusFound) | ||
+ case "a.example.com/redirect": | ||
+ w.Header().Set("X-Done", "true") | ||
+ default: | ||
+ t.Errorf("unexpected request to %v", r.URL) | ||
+ } | ||
+ })).ts | ||
+ proto, _, _ = strings.Cut(ts.URL, ":") | ||
+ | ||
+ c := ts.Client() | ||
+ c.Transport.(*Transport).Dial = func(_ string, _ string) (net.Conn, error) { | ||
+ return net.Dial("tcp", ts.Listener.Addr().String()) | ||
+ } | ||
+ | ||
+ req, _ := NewRequest("GET", proto+"://a.example.com/", nil) | ||
+ req.Header.Add("Cookie", "foo=bar") | ||
+ req.Header.Add("Authorization", "secretpassword") | ||
+ res, err := c.Do(req) | ||
+ if err != nil { | ||
+ t.Fatal(err) | ||
+ } | ||
+ defer res.Body.Close() | ||
+ if res.Header.Get("X-Done") != "true" { | ||
+ t.Fatalf("response missing expected header: X-Done=true") | ||
+ } | ||
+} | ||
+ | ||
// Issue 22233: copy host when Client follows a relative redirect. | ||
func TestClientCopyHostOnRedirect(t *testing.T) { run(t, testClientCopyHostOnRedirect) } | ||
func testClientCopyHostOnRedirect(t *testing.T, mode testMode) { | ||
@@ -1696,43 +1745,39 @@ func testClientAltersCookiesOnRedirect(t *testing.T, mode testMode) { | ||
// Part of Issue 4800 | ||
func TestShouldCopyHeaderOnRedirect(t *testing.T) { | ||
tests := []struct { | ||
- header string | ||
initialURL string | ||
destURL string | ||
want bool | ||
}{ | ||
- {"User-Agent", "http://foo.com/", "http://bar.com/", true}, | ||
- {"X-Foo", "http://foo.com/", "http://bar.com/", true}, | ||
- | ||
// Sensitive headers: | ||
- {"cookie", "http://foo.com/", "http://bar.com/", false}, | ||
- {"cookie2", "http://foo.com/", "http://bar.com/", false}, | ||
- {"authorization", "http://foo.com/", "http://bar.com/", false}, | ||
- {"authorization", "http://foo.com/", "https://foo.com/", true}, | ||
- {"authorization", "http://foo.com:1234/", "http://foo.com:4321/", true}, | ||
- {"www-authenticate", "http://foo.com/", "http://bar.com/", false}, | ||
- {"authorization", "http://foo.com/", "http://[::1%25.foo.com]/", false}, | ||
+ {"http://foo.com/", "http://bar.com/", false}, | ||
+ {"http://foo.com/", "http://bar.com/", false}, | ||
+ {"http://foo.com/", "http://bar.com/", false}, | ||
+ {"http://foo.com/", "https://foo.com/", true}, | ||
+ {"http://foo.com:1234/", "http://foo.com:4321/", true}, | ||
+ {"http://foo.com/", "http://bar.com/", false}, | ||
+ {"http://foo.com/", "http://[::1%25.foo.com]/", false}, | ||
|
||
// But subdomains should work: | ||
- {"www-authenticate", "http://foo.com/", "http://foo.com/", true}, | ||
- {"www-authenticate", "http://foo.com/", "http://sub.foo.com/", true}, | ||
- {"www-authenticate", "http://foo.com/", "http://notfoo.com/", false}, | ||
- {"www-authenticate", "http://foo.com/", "https://foo.com/", true}, | ||
- {"www-authenticate", "http://foo.com:80/", "http://foo.com/", true}, | ||
- {"www-authenticate", "http://foo.com:80/", "http://sub.foo.com/", true}, | ||
- {"www-authenticate", "http://foo.com:443/", "https://foo.com/", true}, | ||
- {"www-authenticate", "http://foo.com:443/", "https://sub.foo.com/", true}, | ||
- {"www-authenticate", "http://foo.com:1234/", "http://foo.com/", true}, | ||
- | ||
- {"authorization", "http://foo.com/", "http://foo.com/", true}, | ||
- {"authorization", "http://foo.com/", "http://sub.foo.com/", true}, | ||
- {"authorization", "http://foo.com/", "http://notfoo.com/", false}, | ||
- {"authorization", "http://foo.com/", "https://foo.com/", true}, | ||
- {"authorization", "http://foo.com:80/", "http://foo.com/", true}, | ||
- {"authorization", "http://foo.com:80/", "http://sub.foo.com/", true}, | ||
- {"authorization", "http://foo.com:443/", "https://foo.com/", true}, | ||
- {"authorization", "http://foo.com:443/", "https://sub.foo.com/", true}, | ||
- {"authorization", "http://foo.com:1234/", "http://foo.com/", true}, | ||
+ {"http://foo.com/", "http://foo.com/", true}, | ||
+ {"http://foo.com/", "http://sub.foo.com/", true}, | ||
+ {"http://foo.com/", "http://notfoo.com/", false}, | ||
+ {"http://foo.com/", "https://foo.com/", true}, | ||
+ {"http://foo.com:80/", "http://foo.com/", true}, | ||
+ {"http://foo.com:80/", "http://sub.foo.com/", true}, | ||
+ {"http://foo.com:443/", "https://foo.com/", true}, | ||
+ {"http://foo.com:443/", "https://sub.foo.com/", true}, | ||
+ {"http://foo.com:1234/", "http://foo.com/", true}, | ||
+ | ||
+ {"http://foo.com/", "http://foo.com/", true}, | ||
+ {"http://foo.com/", "http://sub.foo.com/", true}, | ||
+ {"http://foo.com/", "http://notfoo.com/", false}, | ||
+ {"http://foo.com/", "https://foo.com/", true}, | ||
+ {"http://foo.com:80/", "http://foo.com/", true}, | ||
+ {"http://foo.com:80/", "http://sub.foo.com/", true}, | ||
+ {"http://foo.com:443/", "https://foo.com/", true}, | ||
+ {"http://foo.com:443/", "https://sub.foo.com/", true}, | ||
+ {"http://foo.com:1234/", "http://foo.com/", true}, | ||
} | ||
for i, tt := range tests { | ||
u0, err := url.Parse(tt.initialURL) | ||
@@ -1745,10 +1790,10 @@ func TestShouldCopyHeaderOnRedirect(t *testing.T) { | ||
t.Errorf("%d. dest URL %q parse error: %v", i, tt.destURL, err) | ||
continue | ||
} | ||
- got := Export_shouldCopyHeaderOnRedirect(tt.header, u0, u1) | ||
+ got := Export_shouldCopyHeaderOnRedirect(u0, u1) | ||
if got != tt.want { | ||
- t.Errorf("%d. shouldCopyHeaderOnRedirect(%q, %q => %q) = %v; want %v", | ||
- i, tt.header, tt.initialURL, tt.destURL, got, tt.want) | ||
+ t.Errorf("%d. shouldCopyHeaderOnRedirect(%q => %q) = %v; want %v", | ||
+ i, tt.initialURL, tt.destURL, got, tt.want) | ||
} | ||
} | ||
} | ||
diff --git a/src/net/http/internal/testcert/testcert.go b/src/net/http/internal/testcert/testcert.go | ||
index d510e79..78ce42e 100644 | ||
--- a/src/net/http/internal/testcert/testcert.go | ||
+++ b/src/net/http/internal/testcert/testcert.go | ||
@@ -10,56 +10,56 @@ import "strings" | ||
// LocalhostCert is a PEM-encoded TLS cert with SAN IPs | ||
// "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT. | ||
// generated from src/crypto/tls: | ||
-// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h | ||
+// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com,*.example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h | ||
var LocalhostCert = []byte(`-----BEGIN CERTIFICATE----- | ||
-MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS | ||
+MIIDSDCCAjCgAwIBAgIQEP/md970HysdBTpuzDOf0DANBgkqhkiG9w0BAQsFADAS | ||
MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw | ||
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A | ||
-MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r | ||
-bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U | ||
-aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P | ||
-YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk | ||
-POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu | ||
-h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE | ||
+MIIBCgKCAQEAxcl69ROJdxjN+MJZnbFrYxyQooADCsJ6VDkuMyNQIix/Hk15Nk/u | ||
+FyBX1Me++aEpGmY3RIY4fUvELqT/srvAHsTXwVVSttMcY8pcAFmXSqo3x4MuUTG/ | ||
+jCX3Vftj0r3EM5M8ImY1rzA/jqTTLJg00rD+DmuDABcqQvoXw/RV8w1yTRi5BPoH | ||
+DFD/AWTt/YgMvk1l2Yq/xI8VbMUIpjBoGXxWsSevQ5i2s1mk9/yZzu0Ysp1tTlzD | ||
+qOPa4ysFjBitdXiwfxjxtv5nXqOCP5rheKO0sWLk0fetMp1OV5JSJMAJw6c2ZMkl | ||
+U2WMqAEpRjdE/vHfIuNg+yGaRRqI07NZRQIDAQABo4GXMIGUMA4GA1UdDwEB/wQE | ||
AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud | ||
-DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv | ||
-bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI | ||
-5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv | ||
-cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2 | ||
-+tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B | ||
-grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK | ||
-5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/ | ||
-WkBKOclmOV2xlTVuPw== | ||
+DgQWBBQR5QIzmacmw78ZI1C4MXw7Q0wJ1jA9BgNVHREENjA0ggtleGFtcGxlLmNv | ||
+bYINKi5leGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG | ||
+9w0BAQsFAAOCAQEACrRNgiioUDzxQftd0fwOa6iRRcPampZRDtuaF68yNHoNWbOu | ||
+LUwc05eOWxRq3iABGSk2xg+FXM3DDeW4HhAhCFptq7jbVZ+4Jj6HeJG9mYRatAxR | ||
+Y/dEpa0D0EHhDxxVg6UzKOXB355n0IetGE/aWvyTV9SiDs6QsaC57Q9qq1/mitx5 | ||
+2GFBoapol9L5FxCc77bztzK8CpLujkBi25Vk6GAFbl27opLfpyxkM+rX/T6MXCPO | ||
+6/YBacNZ7ff1/57Etg4i5mNA6ubCpuc4Gi9oYqCNNohftr2lkJr7REdDR6OW0lsL | ||
+rF7r4gUnKeC7mYIH1zypY7laskopiLFAfe96Kg== | ||
-----END CERTIFICATE-----`) | ||
|
||
// LocalhostKey is the private key for LocalhostCert. | ||
var LocalhostKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY----- | ||
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi | ||
-4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS | ||
-gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW | ||
-URnoU85w+W6aLI2bNSq3AaE771p3VbkGolpEjo9h+i42TBHo1rhPNKPkGupR8/QX | ||
-AOLMpInRdeaHyDwb2a3DE5I3dG7VAVzrVfJ6W6Q84YoFX+rpEE2SVM17SAjy6xQy | ||
-VjKgLvK2mk0xbtfa+h0B6VK7bmODHZqeP18NVm6HsBcXn7iclLgAC3SfWU1jucZK | ||
-x1lqzw9tAgMBAAECggEABWzxS1Y2wckblnXY57Z+sl6YdmLV+gxj2r8Qib7g4ZIk | ||
-lIlWR1OJNfw7kU4eryib4fc6nOh6O4AWZyYqAK6tqNQSS/eVG0LQTLTTEldHyVJL | ||
-dvBe+MsUQOj4nTndZW+QvFzbcm2D8lY5n2nBSxU5ypVoKZ1EqQzytFcLZpTN7d89 | ||
-EPj0qDyrV4NZlWAwL1AygCwnlwhMQjXEalVF1ylXwU3QzyZ/6MgvF6d3SSUlh+sq | ||
-XefuyigXw484cQQgbzopv6niMOmGP3of+yV4JQqUSb3IDmmT68XjGd2Dkxl4iPki | ||
-6ZwXf3CCi+c+i/zVEcufgZ3SLf8D99kUGE7v7fZ6AQKBgQD1ZX3RAla9hIhxCf+O | ||
-3D+I1j2LMrdjAh0ZKKqwMR4JnHX3mjQI6LwqIctPWTU8wYFECSh9klEclSdCa64s | ||
-uI/GNpcqPXejd0cAAdqHEEeG5sHMDt0oFSurL4lyud0GtZvwlzLuwEweuDtvT9cJ | ||
-Wfvl86uyO36IW8JdvUprYDctrQKBgQDycZ697qutBieZlGkHpnYWUAeImVA878sJ | ||
-w44NuXHvMxBPz+lbJGAg8Cn8fcxNAPqHIraK+kx3po8cZGQywKHUWsxi23ozHoxo | ||
-+bGqeQb9U661TnfdDspIXia+xilZt3mm5BPzOUuRqlh4Y9SOBpSWRmEhyw76w4ZP | ||
-OPxjWYAgwQKBgA/FehSYxeJgRjSdo+MWnK66tjHgDJE8bYpUZsP0JC4R9DL5oiaA | ||
-brd2fI6Y+SbyeNBallObt8LSgzdtnEAbjIH8uDJqyOmknNePRvAvR6mP4xyuR+Bv | ||
-m+Lgp0DMWTw5J9CKpydZDItc49T/mJ5tPhdFVd+am0NAQnmr1MCZ6nHxAoGABS3Y | ||
-LkaC9FdFUUqSU8+Chkd/YbOkuyiENdkvl6t2e52jo5DVc1T7mLiIrRQi4SI8N9bN | ||
-/3oJWCT+uaSLX2ouCtNFunblzWHBrhxnZzTeqVq4SLc8aESAnbslKL4i8/+vYZlN | ||
-s8xtiNcSvL+lMsOBORSXzpj/4Ot8WwTkn1qyGgECgYBKNTypzAHeLE6yVadFp3nQ | ||
-Ckq9yzvP/ib05rvgbvrne00YeOxqJ9gtTrzgh7koqJyX1L4NwdkEza4ilDWpucn0 | ||
-xiUZS4SoaJq6ZvcBYS62Yr1t8n09iG47YL8ibgtmH3L+svaotvpVxVK+d7BLevA/ | ||
-ZboOWVe3icTy64BT3OQhmg== | ||
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFyXr1E4l3GM34 | ||
+wlmdsWtjHJCigAMKwnpUOS4zI1AiLH8eTXk2T+4XIFfUx775oSkaZjdEhjh9S8Qu | ||
+pP+yu8AexNfBVVK20xxjylwAWZdKqjfHgy5RMb+MJfdV+2PSvcQzkzwiZjWvMD+O | ||
+pNMsmDTSsP4Oa4MAFypC+hfD9FXzDXJNGLkE+gcMUP8BZO39iAy+TWXZir/EjxVs | ||
+xQimMGgZfFaxJ69DmLazWaT3/JnO7RiynW1OXMOo49rjKwWMGK11eLB/GPG2/mde | ||
+o4I/muF4o7SxYuTR960ynU5XklIkwAnDpzZkySVTZYyoASlGN0T+8d8i42D7IZpF | ||
+GojTs1lFAgMBAAECggEAIYthUi1lFBDd5gG4Rzlu+BlBIn5JhcqkCqLEBiJIFfOr | ||
+/4yuMRrvS3bNzqWt6xJ9MSAC4ZlN/VobRLnxL/QNymoiGYUKCT3Ww8nvPpPzR9OE | ||
+sE68TUL9tJw/zZJcRMKwgvrGqSLimfq53MxxkE+kLdOc0v9C8YH8Re26mB5ZcWYa | ||
+7YFyZQpKsQYnsmu/05cMbpOQrQWhtmIqRoyn8mG/par2s3NzjtpSE9NINyz26uFc | ||
+k/3ovFJQIHkUmTS7KHD3BgY5vuCqP98HramYnOysJ0WoYgvSDNCWw3037s5CCwJT | ||
+gCKuM+Ow6liFrj83RrdKBpm5QUGjfNpYP31o+QNP4QKBgQDSrUQ2XdgtAnibAV7u | ||
+7kbxOxro0EhIKso0Y/6LbDQgcXgxLqltkmeqZgG8nC3Z793lhlSasz2snhzzooV5 | ||
+5fTy1y8ikXqjhG0nNkInFyOhsI0auE28CFoDowaQd+5cmCatpN4Grqo5PNRXxm1w | ||
+HktfPEgoP11NNCFHvvN5fEKbbQKBgQDwVlOaV20IvW3IPq7cXZyiyabouFF9eTRo | ||
+VJka1Uv+JtyvL2P0NKkjYHOdN8gRblWqxQtJoTNk020rVA4UP1heiXALy50gvj/p | ||
+hMcybPTLYSPOhAGx838KIcvGR5oskP1aUCmFbFQzGELxhJ9diVVjxUtbG2DuwPKd | ||
+tD9TLxT2OQKBgQCcdlHSjp+dzdgERmBa0ludjGfPv9/uuNizUBAbO6D690psPFtY | ||
+JQMYaemgSd1DngEOFVWADt4e9M5Lose+YCoqr+UxpxmNlyv5kzJOFcFAs/4XeglB | ||
+PHKdgNW/NVKxMc6H54l9LPr+x05sYdGlEtqnP/3W5jhEvhJ5Vjc8YiyVgQKBgQCl | ||
+zwjyrGo+42GACy7cPYE5FeIfIDqoVByB9guC5bD98JXEDu/opQQjsgFRcBCJZhOY | ||
+M0UsURiB8ROaFu13rpQq9KrmmF0ZH+g8FSzQbzcbsTLg4VXCDXmR5esOKowFPypr | ||
+Sm667BfTAGP++D5ya7MLmCv6+RKQ5XD8uEQQAaV2kQKBgAD8qeJuWIXZT0VKkQrn | ||
+nIhgtzGERF/6sZdQGW2LxTbUDWG74AfFkkEbeBfwEkCZXY/xmnYqYABhvlSex8jU | ||
+supU6Eea21esIxIub2zv/Np0ojUb6rlqTPS4Ox1E27D787EJ3VOXpriSD10vyNnZ | ||
+jel6uj2FOP9g54s+GzlSVg/T | ||
-----END RSA TESTING KEY-----`)) | ||
|
||
func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") } | ||
-- | ||
2.43.0 | ||
|
Oops, something went wrong.