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