Skip to content

Commit 5bc0e1c

Browse files
Patch golang for CVE-2024-45336, CVE-2024-45341 [High] (#12212)
Co-authored-by: jslobodzian <[email protected]>
1 parent c1b9c78 commit 5bc0e1c

File tree

4 files changed

+458
-4
lines changed

4 files changed

+458
-4
lines changed

SPECS/golang/CVE-2024-45336.patch

Lines changed: 375 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,375 @@
1+
From 7497e402bf9885dfcffdd8235a6c16e134a50c1c Mon Sep 17 00:00:00 2001
2+
From: Kanishk Bansal <[email protected]>
3+
Date: Tue, 4 Feb 2025 13:32:55 +0000
4+
Subject: [PATCH] Address CVE-2024-45336
5+
6+
---
7+
src/net/http/client.go | 65 ++++++------
8+
src/net/http/client_test.go | 111 +++++++++++++++------
9+
src/net/http/internal/testcert/testcert.go | 84 ++++++++--------
10+
3 files changed, 154 insertions(+), 106 deletions(-)
11+
12+
diff --git a/src/net/http/client.go b/src/net/http/client.go
13+
index 8fc348f..23f4d81 100644
14+
--- a/src/net/http/client.go
15+
+++ b/src/net/http/client.go
16+
@@ -612,8 +612,9 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) {
17+
reqBodyClosed = false // have we closed the current req.Body?
18+
19+
// Redirect behavior:
20+
- redirectMethod string
21+
- includeBody bool
22+
+ redirectMethod string
23+
+ includeBody = true
24+
+ stripSensitiveHeaders = false
25+
)
26+
uerr := func(err error) error {
27+
// the body may have been closed already by c.send()
28+
@@ -680,7 +681,12 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) {
29+
// in case the user set Referer on their first request.
30+
// If they really want to override, they can do it in
31+
// their CheckRedirect func.
32+
- copyHeaders(req)
33+
+ if !stripSensitiveHeaders && reqs[0].URL.Host != req.URL.Host {
34+
+ if !shouldCopyHeaderOnRedirect(reqs[0].URL, req.URL) {
35+
+ stripSensitiveHeaders = true
36+
+ }
37+
+ }
38+
+ copyHeaders(req, stripSensitiveHeaders)
39+
40+
// Add the Referer header from the most recent
41+
// request URL to the new one, if it's not https->http:
42+
@@ -746,7 +752,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) {
43+
// makeHeadersCopier makes a function that copies headers from the
44+
// initial Request, ireq. For every redirect, this function must be called
45+
// so that it can copy headers into the upcoming Request.
46+
-func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) {
47+
+func (c *Client) makeHeadersCopier(ireq *Request) func(req *Request, stripSensitiveHeaders bool) {
48+
// The headers to copy are from the very initial request.
49+
// We use a closured callback to keep a reference to these original headers.
50+
var (
51+
@@ -760,8 +766,7 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) {
52+
}
53+
}
54+
55+
- preq := ireq // The previous request
56+
- return func(req *Request) {
57+
+ return func(req *Request, stripSensitiveHeaders bool) {
58+
// If Jar is present and there was some initial cookies provided
59+
// via the request header, then we may need to alter the initial
60+
// cookies as we follow redirects since each redirect may end up
61+
@@ -798,12 +803,15 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) {
62+
// Copy the initial request's Header values
63+
// (at least the safe ones).
64+
for k, vv := range ireqhdr {
65+
- if shouldCopyHeaderOnRedirect(k, preq.URL, req.URL) {
66+
+ sensitive := false
67+
+ switch CanonicalHeaderKey(k) {
68+
+ case "Authorization", "Www-Authenticate", "Cookie", "Cookie2":
69+
+ sensitive = true
70+
+ }
71+
+ if !(sensitive && stripSensitiveHeaders) {
72+
req.Header[k] = vv
73+
}
74+
}
75+
-
76+
- preq = req // Update previous Request with the current request
77+
}
78+
}
79+
80+
@@ -982,28 +990,23 @@ func (b *cancelTimerBody) Close() error {
81+
return err
82+
}
83+
84+
-func shouldCopyHeaderOnRedirect(headerKey string, initial, dest *url.URL) bool {
85+
- switch CanonicalHeaderKey(headerKey) {
86+
- case "Authorization", "Www-Authenticate", "Cookie", "Cookie2":
87+
- // Permit sending auth/cookie headers from "foo.com"
88+
- // to "sub.foo.com".
89+
-
90+
- // Note that we don't send all cookies to subdomains
91+
- // automatically. This function is only used for
92+
- // Cookies set explicitly on the initial outgoing
93+
- // client request. Cookies automatically added via the
94+
- // CookieJar mechanism continue to follow each
95+
- // cookie's scope as set by Set-Cookie. But for
96+
- // outgoing requests with the Cookie header set
97+
- // directly, we don't know their scope, so we assume
98+
- // it's for *.domain.com.
99+
-
100+
- ihost := idnaASCIIFromURL(initial)
101+
- dhost := idnaASCIIFromURL(dest)
102+
- return isDomainOrSubdomain(dhost, ihost)
103+
- }
104+
- // All other headers are copied:
105+
- return true
106+
+func shouldCopyHeaderOnRedirect(initial, dest *url.URL) bool {
107+
+ // Permit sending auth/cookie headers from "foo.com"
108+
+ // to "sub.foo.com".
109+
+
110+
+ // Note that we don't send all cookies to subdomains
111+
+ // automatically. This function is only used for
112+
+ // Cookies set explicitly on the initial outgoing
113+
+ // client request. Cookies automatically added via the
114+
+ // CookieJar mechanism continue to follow each
115+
+ // cookie's scope as set by Set-Cookie. But for
116+
+ // outgoing requests with the Cookie header set
117+
+ // directly, we don't know their scope, so we assume
118+
+ // it's for *.domain.com.
119+
+
120+
+ ihost := idnaASCIIFromURL(initial)
121+
+ dhost := idnaASCIIFromURL(dest)
122+
+ return isDomainOrSubdomain(dhost, ihost)
123+
}
124+
125+
// isDomainOrSubdomain reports whether sub is a subdomain (or exact
126+
diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go
127+
index e2a1cbb..641d7ff 100644
128+
--- a/src/net/http/client_test.go
129+
+++ b/src/net/http/client_test.go
130+
@@ -1530,6 +1530,55 @@ func testClientCopyHeadersOnRedirect(t *testing.T, mode testMode) {
131+
}
132+
}
133+
134+
+// Issue #70530: Once we strip a header on a redirect to a different host,
135+
+// the header should stay stripped across any further redirects.
136+
+func TestClientStripHeadersOnRepeatedRedirect(t *testing.T) {
137+
+ run(t, testClientStripHeadersOnRepeatedRedirect)
138+
+}
139+
+func testClientStripHeadersOnRepeatedRedirect(t *testing.T, mode testMode) {
140+
+ var proto string
141+
+ ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
142+
+ if r.Host+r.URL.Path != "a.example.com/" {
143+
+ if h := r.Header.Get("Authorization"); h != "" {
144+
+ t.Errorf("on request to %v%v, Authorization=%q, want no header", r.Host, r.URL.Path, h)
145+
+ }
146+
+ }
147+
+ // Follow a chain of redirects from a to b and back to a.
148+
+ // The Authorization header is stripped on the first redirect to b,
149+
+ // and stays stripped even if we're sent back to a.
150+
+ switch r.Host + r.URL.Path {
151+
+ case "a.example.com/":
152+
+ Redirect(w, r, proto+"://b.example.com/", StatusFound)
153+
+ case "b.example.com/":
154+
+ Redirect(w, r, proto+"://b.example.com/redirect", StatusFound)
155+
+ case "b.example.com/redirect":
156+
+ Redirect(w, r, proto+"://a.example.com/redirect", StatusFound)
157+
+ case "a.example.com/redirect":
158+
+ w.Header().Set("X-Done", "true")
159+
+ default:
160+
+ t.Errorf("unexpected request to %v", r.URL)
161+
+ }
162+
+ })).ts
163+
+ proto, _, _ = strings.Cut(ts.URL, ":")
164+
+
165+
+ c := ts.Client()
166+
+ c.Transport.(*Transport).Dial = func(_ string, _ string) (net.Conn, error) {
167+
+ return net.Dial("tcp", ts.Listener.Addr().String())
168+
+ }
169+
+
170+
+ req, _ := NewRequest("GET", proto+"://a.example.com/", nil)
171+
+ req.Header.Add("Cookie", "foo=bar")
172+
+ req.Header.Add("Authorization", "secretpassword")
173+
+ res, err := c.Do(req)
174+
+ if err != nil {
175+
+ t.Fatal(err)
176+
+ }
177+
+ defer res.Body.Close()
178+
+ if res.Header.Get("X-Done") != "true" {
179+
+ t.Fatalf("response missing expected header: X-Done=true")
180+
+ }
181+
+}
182+
+
183+
// Issue 22233: copy host when Client follows a relative redirect.
184+
func TestClientCopyHostOnRedirect(t *testing.T) { run(t, testClientCopyHostOnRedirect) }
185+
func testClientCopyHostOnRedirect(t *testing.T, mode testMode) {
186+
@@ -1696,43 +1745,39 @@ func testClientAltersCookiesOnRedirect(t *testing.T, mode testMode) {
187+
// Part of Issue 4800
188+
func TestShouldCopyHeaderOnRedirect(t *testing.T) {
189+
tests := []struct {
190+
- header string
191+
initialURL string
192+
destURL string
193+
want bool
194+
}{
195+
- {"User-Agent", "http://foo.com/", "http://bar.com/", true},
196+
- {"X-Foo", "http://foo.com/", "http://bar.com/", true},
197+
-
198+
// Sensitive headers:
199+
- {"cookie", "http://foo.com/", "http://bar.com/", false},
200+
- {"cookie2", "http://foo.com/", "http://bar.com/", false},
201+
- {"authorization", "http://foo.com/", "http://bar.com/", false},
202+
- {"authorization", "http://foo.com/", "https://foo.com/", true},
203+
- {"authorization", "http://foo.com:1234/", "http://foo.com:4321/", true},
204+
- {"www-authenticate", "http://foo.com/", "http://bar.com/", false},
205+
- {"authorization", "http://foo.com/", "http://[::1%25.foo.com]/", false},
206+
+ {"http://foo.com/", "http://bar.com/", false},
207+
+ {"http://foo.com/", "http://bar.com/", false},
208+
+ {"http://foo.com/", "http://bar.com/", false},
209+
+ {"http://foo.com/", "https://foo.com/", true},
210+
+ {"http://foo.com:1234/", "http://foo.com:4321/", true},
211+
+ {"http://foo.com/", "http://bar.com/", false},
212+
+ {"http://foo.com/", "http://[::1%25.foo.com]/", false},
213+
214+
// But subdomains should work:
215+
- {"www-authenticate", "http://foo.com/", "http://foo.com/", true},
216+
- {"www-authenticate", "http://foo.com/", "http://sub.foo.com/", true},
217+
- {"www-authenticate", "http://foo.com/", "http://notfoo.com/", false},
218+
- {"www-authenticate", "http://foo.com/", "https://foo.com/", true},
219+
- {"www-authenticate", "http://foo.com:80/", "http://foo.com/", true},
220+
- {"www-authenticate", "http://foo.com:80/", "http://sub.foo.com/", true},
221+
- {"www-authenticate", "http://foo.com:443/", "https://foo.com/", true},
222+
- {"www-authenticate", "http://foo.com:443/", "https://sub.foo.com/", true},
223+
- {"www-authenticate", "http://foo.com:1234/", "http://foo.com/", true},
224+
-
225+
- {"authorization", "http://foo.com/", "http://foo.com/", true},
226+
- {"authorization", "http://foo.com/", "http://sub.foo.com/", true},
227+
- {"authorization", "http://foo.com/", "http://notfoo.com/", false},
228+
- {"authorization", "http://foo.com/", "https://foo.com/", true},
229+
- {"authorization", "http://foo.com:80/", "http://foo.com/", true},
230+
- {"authorization", "http://foo.com:80/", "http://sub.foo.com/", true},
231+
- {"authorization", "http://foo.com:443/", "https://foo.com/", true},
232+
- {"authorization", "http://foo.com:443/", "https://sub.foo.com/", true},
233+
- {"authorization", "http://foo.com:1234/", "http://foo.com/", true},
234+
+ {"http://foo.com/", "http://foo.com/", true},
235+
+ {"http://foo.com/", "http://sub.foo.com/", true},
236+
+ {"http://foo.com/", "http://notfoo.com/", false},
237+
+ {"http://foo.com/", "https://foo.com/", true},
238+
+ {"http://foo.com:80/", "http://foo.com/", true},
239+
+ {"http://foo.com:80/", "http://sub.foo.com/", true},
240+
+ {"http://foo.com:443/", "https://foo.com/", true},
241+
+ {"http://foo.com:443/", "https://sub.foo.com/", true},
242+
+ {"http://foo.com:1234/", "http://foo.com/", true},
243+
+
244+
+ {"http://foo.com/", "http://foo.com/", true},
245+
+ {"http://foo.com/", "http://sub.foo.com/", true},
246+
+ {"http://foo.com/", "http://notfoo.com/", false},
247+
+ {"http://foo.com/", "https://foo.com/", true},
248+
+ {"http://foo.com:80/", "http://foo.com/", true},
249+
+ {"http://foo.com:80/", "http://sub.foo.com/", true},
250+
+ {"http://foo.com:443/", "https://foo.com/", true},
251+
+ {"http://foo.com:443/", "https://sub.foo.com/", true},
252+
+ {"http://foo.com:1234/", "http://foo.com/", true},
253+
}
254+
for i, tt := range tests {
255+
u0, err := url.Parse(tt.initialURL)
256+
@@ -1745,10 +1790,10 @@ func TestShouldCopyHeaderOnRedirect(t *testing.T) {
257+
t.Errorf("%d. dest URL %q parse error: %v", i, tt.destURL, err)
258+
continue
259+
}
260+
- got := Export_shouldCopyHeaderOnRedirect(tt.header, u0, u1)
261+
+ got := Export_shouldCopyHeaderOnRedirect(u0, u1)
262+
if got != tt.want {
263+
- t.Errorf("%d. shouldCopyHeaderOnRedirect(%q, %q => %q) = %v; want %v",
264+
- i, tt.header, tt.initialURL, tt.destURL, got, tt.want)
265+
+ t.Errorf("%d. shouldCopyHeaderOnRedirect(%q => %q) = %v; want %v",
266+
+ i, tt.initialURL, tt.destURL, got, tt.want)
267+
}
268+
}
269+
}
270+
diff --git a/src/net/http/internal/testcert/testcert.go b/src/net/http/internal/testcert/testcert.go
271+
index d510e79..78ce42e 100644
272+
--- a/src/net/http/internal/testcert/testcert.go
273+
+++ b/src/net/http/internal/testcert/testcert.go
274+
@@ -10,56 +10,56 @@ import "strings"
275+
// LocalhostCert is a PEM-encoded TLS cert with SAN IPs
276+
// "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT.
277+
// generated from src/crypto/tls:
278+
-// 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
279+
+// 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
280+
var LocalhostCert = []byte(`-----BEGIN CERTIFICATE-----
281+
-MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS
282+
+MIIDSDCCAjCgAwIBAgIQEP/md970HysdBTpuzDOf0DANBgkqhkiG9w0BAQsFADAS
283+
MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
284+
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
285+
-MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r
286+
-bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U
287+
-aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P
288+
-YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk
289+
-POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu
290+
-h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE
291+
+MIIBCgKCAQEAxcl69ROJdxjN+MJZnbFrYxyQooADCsJ6VDkuMyNQIix/Hk15Nk/u
292+
+FyBX1Me++aEpGmY3RIY4fUvELqT/srvAHsTXwVVSttMcY8pcAFmXSqo3x4MuUTG/
293+
+jCX3Vftj0r3EM5M8ImY1rzA/jqTTLJg00rD+DmuDABcqQvoXw/RV8w1yTRi5BPoH
294+
+DFD/AWTt/YgMvk1l2Yq/xI8VbMUIpjBoGXxWsSevQ5i2s1mk9/yZzu0Ysp1tTlzD
295+
+qOPa4ysFjBitdXiwfxjxtv5nXqOCP5rheKO0sWLk0fetMp1OV5JSJMAJw6c2ZMkl
296+
+U2WMqAEpRjdE/vHfIuNg+yGaRRqI07NZRQIDAQABo4GXMIGUMA4GA1UdDwEB/wQE
297+
AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
298+
-DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv
299+
-bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI
300+
-5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv
301+
-cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2
302+
-+tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B
303+
-grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK
304+
-5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/
305+
-WkBKOclmOV2xlTVuPw==
306+
+DgQWBBQR5QIzmacmw78ZI1C4MXw7Q0wJ1jA9BgNVHREENjA0ggtleGFtcGxlLmNv
307+
+bYINKi5leGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG
308+
+9w0BAQsFAAOCAQEACrRNgiioUDzxQftd0fwOa6iRRcPampZRDtuaF68yNHoNWbOu
309+
+LUwc05eOWxRq3iABGSk2xg+FXM3DDeW4HhAhCFptq7jbVZ+4Jj6HeJG9mYRatAxR
310+
+Y/dEpa0D0EHhDxxVg6UzKOXB355n0IetGE/aWvyTV9SiDs6QsaC57Q9qq1/mitx5
311+
+2GFBoapol9L5FxCc77bztzK8CpLujkBi25Vk6GAFbl27opLfpyxkM+rX/T6MXCPO
312+
+6/YBacNZ7ff1/57Etg4i5mNA6ubCpuc4Gi9oYqCNNohftr2lkJr7REdDR6OW0lsL
313+
+rF7r4gUnKeC7mYIH1zypY7laskopiLFAfe96Kg==
314+
-----END CERTIFICATE-----`)
315+
316+
// LocalhostKey is the private key for LocalhostCert.
317+
var LocalhostKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY-----
318+
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi
319+
-4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS
320+
-gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW
321+
-URnoU85w+W6aLI2bNSq3AaE771p3VbkGolpEjo9h+i42TBHo1rhPNKPkGupR8/QX
322+
-AOLMpInRdeaHyDwb2a3DE5I3dG7VAVzrVfJ6W6Q84YoFX+rpEE2SVM17SAjy6xQy
323+
-VjKgLvK2mk0xbtfa+h0B6VK7bmODHZqeP18NVm6HsBcXn7iclLgAC3SfWU1jucZK
324+
-x1lqzw9tAgMBAAECggEABWzxS1Y2wckblnXY57Z+sl6YdmLV+gxj2r8Qib7g4ZIk
325+
-lIlWR1OJNfw7kU4eryib4fc6nOh6O4AWZyYqAK6tqNQSS/eVG0LQTLTTEldHyVJL
326+
-dvBe+MsUQOj4nTndZW+QvFzbcm2D8lY5n2nBSxU5ypVoKZ1EqQzytFcLZpTN7d89
327+
-EPj0qDyrV4NZlWAwL1AygCwnlwhMQjXEalVF1ylXwU3QzyZ/6MgvF6d3SSUlh+sq
328+
-XefuyigXw484cQQgbzopv6niMOmGP3of+yV4JQqUSb3IDmmT68XjGd2Dkxl4iPki
329+
-6ZwXf3CCi+c+i/zVEcufgZ3SLf8D99kUGE7v7fZ6AQKBgQD1ZX3RAla9hIhxCf+O
330+
-3D+I1j2LMrdjAh0ZKKqwMR4JnHX3mjQI6LwqIctPWTU8wYFECSh9klEclSdCa64s
331+
-uI/GNpcqPXejd0cAAdqHEEeG5sHMDt0oFSurL4lyud0GtZvwlzLuwEweuDtvT9cJ
332+
-Wfvl86uyO36IW8JdvUprYDctrQKBgQDycZ697qutBieZlGkHpnYWUAeImVA878sJ
333+
-w44NuXHvMxBPz+lbJGAg8Cn8fcxNAPqHIraK+kx3po8cZGQywKHUWsxi23ozHoxo
334+
-+bGqeQb9U661TnfdDspIXia+xilZt3mm5BPzOUuRqlh4Y9SOBpSWRmEhyw76w4ZP
335+
-OPxjWYAgwQKBgA/FehSYxeJgRjSdo+MWnK66tjHgDJE8bYpUZsP0JC4R9DL5oiaA
336+
-brd2fI6Y+SbyeNBallObt8LSgzdtnEAbjIH8uDJqyOmknNePRvAvR6mP4xyuR+Bv
337+
-m+Lgp0DMWTw5J9CKpydZDItc49T/mJ5tPhdFVd+am0NAQnmr1MCZ6nHxAoGABS3Y
338+
-LkaC9FdFUUqSU8+Chkd/YbOkuyiENdkvl6t2e52jo5DVc1T7mLiIrRQi4SI8N9bN
339+
-/3oJWCT+uaSLX2ouCtNFunblzWHBrhxnZzTeqVq4SLc8aESAnbslKL4i8/+vYZlN
340+
-s8xtiNcSvL+lMsOBORSXzpj/4Ot8WwTkn1qyGgECgYBKNTypzAHeLE6yVadFp3nQ
341+
-Ckq9yzvP/ib05rvgbvrne00YeOxqJ9gtTrzgh7koqJyX1L4NwdkEza4ilDWpucn0
342+
-xiUZS4SoaJq6ZvcBYS62Yr1t8n09iG47YL8ibgtmH3L+svaotvpVxVK+d7BLevA/
343+
-ZboOWVe3icTy64BT3OQhmg==
344+
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFyXr1E4l3GM34
345+
+wlmdsWtjHJCigAMKwnpUOS4zI1AiLH8eTXk2T+4XIFfUx775oSkaZjdEhjh9S8Qu
346+
+pP+yu8AexNfBVVK20xxjylwAWZdKqjfHgy5RMb+MJfdV+2PSvcQzkzwiZjWvMD+O
347+
+pNMsmDTSsP4Oa4MAFypC+hfD9FXzDXJNGLkE+gcMUP8BZO39iAy+TWXZir/EjxVs
348+
+xQimMGgZfFaxJ69DmLazWaT3/JnO7RiynW1OXMOo49rjKwWMGK11eLB/GPG2/mde
349+
+o4I/muF4o7SxYuTR960ynU5XklIkwAnDpzZkySVTZYyoASlGN0T+8d8i42D7IZpF
350+
+GojTs1lFAgMBAAECggEAIYthUi1lFBDd5gG4Rzlu+BlBIn5JhcqkCqLEBiJIFfOr
351+
+/4yuMRrvS3bNzqWt6xJ9MSAC4ZlN/VobRLnxL/QNymoiGYUKCT3Ww8nvPpPzR9OE
352+
+sE68TUL9tJw/zZJcRMKwgvrGqSLimfq53MxxkE+kLdOc0v9C8YH8Re26mB5ZcWYa
353+
+7YFyZQpKsQYnsmu/05cMbpOQrQWhtmIqRoyn8mG/par2s3NzjtpSE9NINyz26uFc
354+
+k/3ovFJQIHkUmTS7KHD3BgY5vuCqP98HramYnOysJ0WoYgvSDNCWw3037s5CCwJT
355+
+gCKuM+Ow6liFrj83RrdKBpm5QUGjfNpYP31o+QNP4QKBgQDSrUQ2XdgtAnibAV7u
356+
+7kbxOxro0EhIKso0Y/6LbDQgcXgxLqltkmeqZgG8nC3Z793lhlSasz2snhzzooV5
357+
+5fTy1y8ikXqjhG0nNkInFyOhsI0auE28CFoDowaQd+5cmCatpN4Grqo5PNRXxm1w
358+
+HktfPEgoP11NNCFHvvN5fEKbbQKBgQDwVlOaV20IvW3IPq7cXZyiyabouFF9eTRo
359+
+VJka1Uv+JtyvL2P0NKkjYHOdN8gRblWqxQtJoTNk020rVA4UP1heiXALy50gvj/p
360+
+hMcybPTLYSPOhAGx838KIcvGR5oskP1aUCmFbFQzGELxhJ9diVVjxUtbG2DuwPKd
361+
+tD9TLxT2OQKBgQCcdlHSjp+dzdgERmBa0ludjGfPv9/uuNizUBAbO6D690psPFtY
362+
+JQMYaemgSd1DngEOFVWADt4e9M5Lose+YCoqr+UxpxmNlyv5kzJOFcFAs/4XeglB
363+
+PHKdgNW/NVKxMc6H54l9LPr+x05sYdGlEtqnP/3W5jhEvhJ5Vjc8YiyVgQKBgQCl
364+
+zwjyrGo+42GACy7cPYE5FeIfIDqoVByB9guC5bD98JXEDu/opQQjsgFRcBCJZhOY
365+
+M0UsURiB8ROaFu13rpQq9KrmmF0ZH+g8FSzQbzcbsTLg4VXCDXmR5esOKowFPypr
366+
+Sm667BfTAGP++D5ya7MLmCv6+RKQ5XD8uEQQAaV2kQKBgAD8qeJuWIXZT0VKkQrn
367+
+nIhgtzGERF/6sZdQGW2LxTbUDWG74AfFkkEbeBfwEkCZXY/xmnYqYABhvlSex8jU
368+
+supU6Eea21esIxIub2zv/Np0ojUb6rlqTPS4Ox1E27D787EJ3VOXpriSD10vyNnZ
369+
+jel6uj2FOP9g54s+GzlSVg/T
370+
-----END RSA TESTING KEY-----`))
371+
372+
func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }
373+
--
374+
2.43.0
375+

0 commit comments

Comments
 (0)