diff --git a/0071-CVE-2024-45341-crypto-x509-properly-check-for-IPv6-h.patch b/0071-CVE-2024-45341-crypto-x509-properly-check-for-IPv6-h.patch new file mode 100644 index 0000000000000000000000000000000000000000..e03ac94813dcbcf8dbb806b86d1dfbe43804e3ae --- /dev/null +++ b/0071-CVE-2024-45341-crypto-x509-properly-check-for-IPv6-h.patch @@ -0,0 +1,92 @@ +From 468fad45a27db0ec1fff4ae397d3670795b3f977 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker +Date: Mon, 09 Dec 2024 11:31:22 -0800 +Subject: [PATCH] [release-branch.go1.24] crypto/x509: properly check for IPv6 hosts in URIs + +When checking URI constraints, use netip.ParseAddr, which understands +zones, unlike net.ParseIP which chokes on them. This prevents zone IDs +from mistakenly satisfying URI constraints. + +Thanks to Juho Forsén of Mattermost for reporting this issue. + +For #71156 +Fixes #71209 +Fixes CVE-2024-45341 + +Change-Id: Iecac2529f3605382d257996e0fb6d6983547e400 +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1700 +Reviewed-by: Tatiana Bradley +Reviewed-by: Damien Neil +(cherry picked from commit 22ca55d396ba801e6ae9b2bd67a059fcb30562fd) +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1800 +Commit-Queue: Roland Shoemaker +Reviewed-by: Roland Shoemaker +Reviewed-on: https://go-review.googlesource.com/c/go/+/643099 +LUCI-TryBot-Result: Go LUCI +Auto-Submit: Michael Knyszek +Reviewed-by: Michael Pratt +--- + +diff --git a/src/crypto/x509/name_constraints_test.go b/src/crypto/x509/name_constraints_test.go +index 008c702..a585184 100644 +--- a/src/crypto/x509/name_constraints_test.go ++++ b/src/crypto/x509/name_constraints_test.go +@@ -1607,6 +1607,23 @@ + cn: "foo.bar", + }, + }, ++ // #86: URIs with IPv6 addresses with zones and ports are rejected ++ { ++ roots: []constraintsSpec{ ++ { ++ ok: []string{"uri:example.com"}, ++ }, ++ }, ++ intermediates: [][]constraintsSpec{ ++ { ++ {}, ++ }, ++ }, ++ leaf: leafSpec{ ++ sans: []string{"uri:http://[2006:abcd::1%25.example.com]:16/"}, ++ }, ++ expectedError: "URI with IP", ++ }, + } + + func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) { +diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go +index d2384f5..5fe93c6 100644 +--- a/src/crypto/x509/verify.go ++++ b/src/crypto/x509/verify.go +@@ -15,6 +15,7 @@ + "strings" + "time" + "unicode/utf8" ++ _ "unsafe" + ) + + type InvalidReason int +@@ -427,14 +428,20 @@ + } + } + +- if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") || +- net.ParseIP(host) != nil { ++ // parseIPZone will reject the URI IPv6 literal form "[...]", so we ++ // check if _either_ the string parses as an IP, or if it is enclosed in ++ // square brackets. ++ ipaddr, _ := parseIPZone(host) ++ if ipaddr != nil || (strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]")) { + return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String()) + } + + return matchDomainConstraint(host, constraint) + } + ++//go:linkname parseIPZone net.parseIPZone ++func parseIPZone(s string) (net.IP, string) ++ + func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) { + if len(ip) != len(constraint.IP) { + return false, nil diff --git a/0072-CVE-2024-45336-net-http-persist-header-stripping-acr.patch b/0072-CVE-2024-45336-net-http-persist-header-stripping-acr.patch new file mode 100644 index 0000000000000000000000000000000000000000..4ae9cff1b79b4b15eb8e1ac38bf8b01292d3bcd9 --- /dev/null +++ b/0072-CVE-2024-45336-net-http-persist-header-stripping-acr.patch @@ -0,0 +1,388 @@ +From 6b605505047416bbbf513bba1540220a8897f3f6 Mon Sep 17 00:00:00 2001 +From: Damien Neil +Date: Fri, 22 Nov 2024 12:34:11 -0800 +Subject: [PATCH] [release-branch.go1.24] net/http: persist header stripping across repeated redirects + +When an HTTP redirect changes the host of a request, we drop +sensitive headers such as Authorization from the redirected request. +Fix a bug where a chain of redirects could result in sensitive +headers being sent to the wrong host: + + 1. request to a.tld with Authorization header + 2. a.tld redirects to b.tld + 3. request to b.tld with no Authorization header + 4. b.tld redirects to b.tld + 3. request to b.tld with Authorization header restored + +Thanks to Kyle Seely for reporting this issue. + +For #70530 +Fixes #71212 +Fixes CVE-2024-45336 + +Change-Id: Ia58a2e10d33d6b0cc7220935e771450e5c34de72 +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1641 +Reviewed-by: Roland Shoemaker +Reviewed-by: Tatiana Bradley +Commit-Queue: Roland Shoemaker +(cherry picked from commit 2889169b87a61f1218a02994feb80fd3d8bfa87c) +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1766 +Reviewed-on: https://go-review.googlesource.com/c/go/+/643100 +Auto-Submit: Michael Knyszek +LUCI-TryBot-Result: Go LUCI +Reviewed-by: Michael Pratt +--- + +diff --git a/src/net/http/client.go b/src/net/http/client.go +index fda7815..9231f63 100644 +--- a/src/net/http/client.go ++++ b/src/net/http/client.go +@@ -615,8 +615,9 @@ + 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() +@@ -681,7 +682,12 @@ + // 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: +@@ -747,7 +753,7 @@ + // 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 ( +@@ -761,8 +767,7 @@ + } + } + +- 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 +@@ -799,12 +804,15 @@ + // 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 + } + } + +@@ -984,28 +984,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 429b8f1..1ce9539 100644 +--- a/src/net/http/client_test.go ++++ b/src/net/http/client_test.go +@@ -1525,6 +1525,63 @@ func TestClientCopyHeadersOnRedirect(t *testing.T) { + } + } + ++// 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_h1(t *testing.T) { ++ testClientStripHeadersOnRepeatedRedirect(t, h1Mode) ++} ++func TestClientStripHeadersOnRepeatedRedirect_h2(t *testing.T) { ++ testClientStripHeadersOnRepeatedRedirect(t, h2Mode) ++} ++func testClientStripHeadersOnRepeatedRedirect(t *testing.T, mode bool) { ++ setParallel(t) ++ defer afterTest(t) ++ var proto string ++ cst := 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) ++ } ++ })) ++ defer cst.close() ++ ++ ts := cst.ts ++ proto = strings.Split(ts.URL, ":")[0] ++ ++ 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) { + // Virtual hostname: should not receive any request. +@@ -1696,43 +1753,39 @@ func TestClientAltersCookiesOnRedirect(t *testing.T) { + // 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 +1798,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,37 +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 1024 --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----- +-MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS ++MIIDSDCCAjCgAwIBAgIQFgSNW7Q203yuk2HUM4z0GDANBgkqhkiG9w0BAQsFADAS + MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw +-MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +-iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4 +-iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul +-rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO +-BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw +-AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA +-AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9 +-tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs +-h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM +-fblo6RBxUQ== ++MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A ++MIIBCgKCAQEAqspE6oCu4tLTgAca17wS9FecmXBWM2+qzz5dmvQAI25qf4xo0vKC ++/apwhh8pHO0S3IOHcILAy8j9e/cs1V8k0Dre7KGNqqZyNCc7950ZQtt/CRN1H8MF ++vAh20qsXC7BQjfE0Ga522d1UTUU0rAAhQk9Ityp4hy5f7RjXMbEJphgmtg1qZBnS +++Uahsiky1L6hmUdjWMKZYaS14X+N3MhGWjR2R2hiP/QMEb7Y9ReCd2sRqWTjKyXJ ++i5JD1+tVJgUeBJp4+38naVT3LG/VviIOE9xo4WhrtsnX9adm6ctcxPIFrPRWIhyV ++RSfQwHo26mJiGH2KsmM3gggX/W9E0ft6UQIDAQABo4GXMIGUMA4GA1UdDwEB/wQE ++AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud ++DgQWBBT46lXgr7Azh/gy8zDLaq8oCpGCmzA9BgNVHREENjA0ggtleGFtcGxlLmNv ++bYINKi5leGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG ++9w0BAQsFAAOCAQEATM2XXLR3gTagL5MXK29RloJRD/vyZNiKL3Fuj/EOaU53Mpm2 ++MJ7b7WTz4Kft285UaFqeSSTnOkDmlSPmccI2v7Ridp7gO3RimPz5Ofd1zLw12zEx ++4ZzFjU6vuLUwfw+1lw8xnS7cn1j2Q5AoWmfJxnQKCnkX487m/16szda49ydTestc ++s4g18dV/OGhWOQpLA2Z75DAu2rmE1oLKTrmYc36xjGXqMqSB33QU0sHgtkopuWdC ++C1TGa/ZwgQLdNPZfbdrYqtJQrnlyxSLx9R/ZZH00zse2N1eY0qPje2yXjNkD10Lp ++DXa5YlHo2skMtBMQ8uq+nQ+gWhRu5CJ2OYajVg== + -----END CERTIFICATE-----`) + + // LocalhostKey is the private key for LocalhostCert. + var LocalhostKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY----- +-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 ++WlHTZvq5FrvuRL63przviPPw + -----END RSA TESTING KEY-----`)) + + func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") } + diff --git a/0073-crypto-tls-fix-Config.Time-in-tests-using-expir.patch b/0073-crypto-tls-fix-Config.Time-in-tests-using-expir.patch new file mode 100644 index 0000000000000000000000000000000000000000..b7ff95ed964cca92cbba6a56e35a24ab4d7785cf --- /dev/null +++ b/0073-crypto-tls-fix-Config.Time-in-tests-using-expir.patch @@ -0,0 +1,217 @@ +From b01fddf727a610033e03814d5b96abceab71c989 Mon Sep 17 00:00:00 2001 +From: wujichao +Date: Mon, 24 Feb 2025 15:09:33 +0800 +Subject: [PATCH] 0027-crypto-tls-fix-Config.Time-in-tests-using-expired-ce + +--- + src/crypto/tls/handshake_client_test.go | 30 ++++++++++++++----------- + src/crypto/tls/handshake_server_test.go | 2 ++ + src/crypto/tls/handshake_test.go | 5 +++++ + src/crypto/tls/tls_test.go | 4 +--- + 4 files changed, 25 insertions(+), 16 deletions(-) + +diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go +index d581cb1..5538202 100644 +--- a/src/crypto/tls/handshake_client_test.go ++++ b/src/crypto/tls/handshake_client_test.go +@@ -881,6 +881,7 @@ func testResumption(t *testing.T, version uint16) { + MaxVersion: version, + CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA}, + Certificates: testConfig.Certificates, ++ Time: testTime, + } + + issuer, err := x509.ParseCertificate(testRSACertificateIssuer) +@@ -897,6 +898,7 @@ func testResumption(t *testing.T, version uint16) { + ClientSessionCache: NewLRUClientSessionCache(32), + RootCAs: rootCAs, + ServerName: "example.golang", ++ Time: testTime, + } + + testResumeState := func(test string, didResume bool) { +@@ -944,20 +946,20 @@ func testResumption(t *testing.T, version uint16) { + } + + // An old session ticket can resume, but the server will provide a ticket encrypted with a fresh key. +- serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) } ++ serverConfig.Time = func() time.Time { return testTime().Add(24*time.Hour + time.Minute) } + testResumeState("ResumeWithOldTicket", true) + if bytes.Equal(ticket[:ticketKeyNameLen], getTicket()[:ticketKeyNameLen]) { + t.Fatal("old first ticket matches the fresh one") + } + + // Now the session tickey key is expired, so a full handshake should occur. +- serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) } ++ serverConfig.Time = func() time.Time { return testTime().Add(24*8*time.Hour + time.Minute) } + testResumeState("ResumeWithExpiredTicket", false) + if bytes.Equal(ticket, getTicket()) { + t.Fatal("expired first ticket matches the fresh one") + } + +- serverConfig.Time = func() time.Time { return time.Now() } // reset the time back ++ serverConfig.Time = testTime // reset the time back + key1 := randomKey() + serverConfig.SetSessionTicketKeys([][32]byte{key1}) + +@@ -974,11 +976,11 @@ func testResumption(t *testing.T, version uint16) { + testResumeState("KeyChangeFinish", true) + + // Age the session ticket a bit, but not yet expired. +- serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) } ++ serverConfig.Time = func() time.Time { return testTime().Add(24*time.Hour + time.Minute) } + testResumeState("OldSessionTicket", true) + ticket = getTicket() + // Expire the session ticket, which would force a full handshake. +- serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) } ++ serverConfig.Time = func() time.Time { return testTime().Add(24*8*time.Hour + 2*time.Minute) } + testResumeState("ExpiredSessionTicket", false) + if bytes.Equal(ticket, getTicket()) { + t.Fatal("new ticket wasn't provided after old ticket expired") +@@ -988,15 +990,15 @@ func testResumption(t *testing.T, version uint16) { + d := 0 * time.Hour + for i := 0; i < 13; i++ { + d += 12 * time.Hour +- serverConfig.Time = func() time.Time { return time.Now().Add(d) } ++ serverConfig.Time = func() time.Time { return testTime().Add(d) } + testResumeState("OldSessionTicket", true) + } + // Expire it (now a little more than 7 days) and make sure a full + // handshake occurs for TLS 1.2. Resumption should still occur for + // TLS 1.3 since the client should be using a fresh ticket sent over + // by the server. +- d += 12 * time.Hour +- serverConfig.Time = func() time.Time { return time.Now().Add(d) } ++ d += 12*time.Hour + time.Minute ++ serverConfig.Time = func() time.Time { return testTime().Add(d) } + if version == VersionTLS13 { + testResumeState("ExpiredSessionTicket", true) + } else { +@@ -1012,6 +1014,7 @@ func testResumption(t *testing.T, version uint16) { + MaxVersion: version, + CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA}, + Certificates: testConfig.Certificates, ++ Time: testTime, + } + serverConfig.SetSessionTicketKeys([][32]byte{key2}) + +@@ -1698,6 +1701,7 @@ func testVerifyConnection(t *testing.T, version uint16) { + serverConfig := &Config{ + MaxVersion: version, + Certificates: []Certificate{testConfig.Certificates[0]}, ++ Time: testTime, + ClientCAs: rootCAs, + NextProtos: []string{"protocol1"}, + } +@@ -1711,6 +1715,7 @@ func testVerifyConnection(t *testing.T, version uint16) { + RootCAs: rootCAs, + ServerName: "example.golang", + Certificates: []Certificate{testConfig.Certificates[0]}, ++ Time: testTime, + NextProtos: []string{"protocol1"}, + } + test.configureClient(clientConfig, &clientCalled) +@@ -1753,8 +1758,6 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) { + rootCAs := x509.NewCertPool() + rootCAs.AddCert(issuer) + +- now := func() time.Time { return time.Unix(1476984729, 0) } +- + sentinelErr := errors.New("TestVerifyPeerCertificate") + + verifyPeerCertificateCallback := func(called *bool, rawCerts [][]byte, validatedChains [][]*x509.Certificate) error { +@@ -2000,7 +2003,7 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) { + config.ServerName = "example.golang" + config.ClientAuth = RequireAndVerifyClientCert + config.ClientCAs = rootCAs +- config.Time = now ++ config.Time = testTime + config.MaxVersion = version + config.Certificates = make([]Certificate, 1) + config.Certificates[0].Certificate = [][]byte{testRSACertificate} +@@ -2017,7 +2020,7 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) { + config := testConfig.Clone() + config.ServerName = "example.golang" + config.RootCAs = rootCAs +- config.Time = now ++ config.Time = testTime + config.MaxVersion = version + test.configureClient(config, &clientCalled) + clientErr := Client(c, config).Handshake() +@@ -2330,7 +2333,7 @@ func testGetClientCertificate(t *testing.T, version uint16) { + serverConfig.RootCAs = x509.NewCertPool() + serverConfig.RootCAs.AddCert(issuer) + serverConfig.ClientCAs = serverConfig.RootCAs +- serverConfig.Time = func() time.Time { return time.Unix(1476984729, 0) } ++ serverConfig.Time = testTime + serverConfig.MaxVersion = version + + clientConfig := testConfig.Clone() +@@ -2501,6 +2504,7 @@ func testResumptionKeepsOCSPAndSCT(t *testing.T, ver uint16) { + ClientSessionCache: NewLRUClientSessionCache(32), + ServerName: "example.golang", + RootCAs: roots, ++ Time: testTime, + } + serverConfig := testConfig.Clone() + serverConfig.MaxVersion = ver +diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go +index 3d23b3f..72f0327 100644 +--- a/src/crypto/tls/handshake_server_test.go ++++ b/src/crypto/tls/handshake_server_test.go +@@ -481,12 +481,14 @@ func testCrossVersionResume(t *testing.T, version uint16) { + serverConfig := &Config{ + CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, + Certificates: testConfig.Certificates, ++ Time: testTime, + } + clientConfig := &Config{ + CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, + InsecureSkipVerify: true, + ClientSessionCache: NewLRUClientSessionCache(1), + ServerName: "servername", ++ Time: testTime, + } + + // Establish a session at TLS 1.1. +diff --git a/src/crypto/tls/handshake_test.go b/src/crypto/tls/handshake_test.go +index 9bfb117..988c2e3 100644 +--- a/src/crypto/tls/handshake_test.go ++++ b/src/crypto/tls/handshake_test.go +@@ -428,6 +428,11 @@ func fromHex(s string) []byte { + return b + } + ++// testTime is 2016-10-20T17:32:09.000Z, which is within the validity period of ++// [testRSACertificate], [testRSACertificateIssuer], [testRSA2048Certificate], ++// [testRSA2048CertificateIssuer], and [testECDSACertificate]. ++var testTime = func() time.Time { return time.Unix(1476984729, 0) } ++ + var testRSACertificate = fromHex("3082024b308201b4a003020102020900e8f09d3fe25beaa6300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301a310b3009060355040a1302476f310b300906035504031302476f30819f300d06092a864886f70d010101050003818d0030818902818100db467d932e12270648bc062821ab7ec4b6a25dfe1e5245887a3647a5080d92425bc281c0be97799840fb4f6d14fd2b138bc2a52e67d8d4099ed62238b74a0b74732bc234f1d193e596d9747bf3589f6c613cc0b041d4d92b2b2423775b1c3bbd755dce2054cfa163871d1e24c4f31d1a508baab61443ed97a77562f414c852d70203010001a38193308190300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff0402300030190603551d0e041204109f91161f43433e49a6de6db680d79f60301b0603551d230414301280104813494d137e1631bba301d5acab6e7b30190603551d1104123010820e6578616d706c652e676f6c616e67300d06092a864886f70d01010b0500038181009d30cc402b5b50a061cbbae55358e1ed8328a9581aa938a495a1ac315a1a84663d43d32dd90bf297dfd320643892243a00bccf9c7db74020015faad3166109a276fd13c3cce10c5ceeb18782f16c04ed73bbb343778d0c1cf10fa1d8408361c94c722b9daedb4606064df4c1b33ec0d1bd42d4dbfe3d1360845c21d33be9fae7") + + var testRSACertificateIssuer = fromHex("3082021930820182a003020102020900ca5e4e811a965964300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f7430819f300d06092a864886f70d010101050003818d0030818902818100d667b378bb22f34143b6cd2008236abefaf2852adf3ab05e01329e2c14834f5105df3f3073f99dab5442d45ee5f8f57b0111c8cb682fbb719a86944eebfffef3406206d898b8c1b1887797c9c5006547bb8f00e694b7a063f10839f269f2c34fff7a1f4b21fbcd6bfdfb13ac792d1d11f277b5c5b48600992203059f2a8f8cc50203010001a35d305b300e0603551d0f0101ff040403020204301d0603551d250416301406082b0601050507030106082b06010505070302300f0603551d130101ff040530030101ff30190603551d0e041204104813494d137e1631bba301d5acab6e7b300d06092a864886f70d01010b050003818100c1154b4bab5266221f293766ae4138899bd4c5e36b13cee670ceeaa4cbdf4f6679017e2fe649765af545749fe4249418a56bd38a04b81e261f5ce86b8d5c65413156a50d12449554748c59a30c515bc36a59d38bddf51173e899820b282e40aa78c806526fd184fb6b4cf186ec728edffa585440d2b3225325f7ab580e87dd76") +diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go +index d8a43ad..5fa6e90 100644 +--- a/src/crypto/tls/tls_test.go ++++ b/src/crypto/tls/tls_test.go +@@ -1058,8 +1058,6 @@ func TestConnectionState(t *testing.T) { + rootCAs := x509.NewCertPool() + rootCAs.AddCert(issuer) + +- now := func() time.Time { return time.Unix(1476984729, 0) } +- + const alpnProtocol = "golang" + const serverName = "example.golang" + var scts = [][]byte{[]byte("dummy sct 1"), []byte("dummy sct 2")} +@@ -1075,7 +1073,7 @@ func TestConnectionState(t *testing.T) { + } + t.Run(name, func(t *testing.T) { + config := &Config{ +- Time: now, ++ Time: testTime, + Rand: zeroSource{}, + Certificates: make([]Certificate, 1), + MaxVersion: v, +-- +2.33.0 + diff --git a/golang.spec b/golang.spec index 8198a186192f7f0b3b0e2acd746e7060a6148eb0..bcddb79afdf5c9e19a729b5d7953c5b52b94f37a 100644 --- a/golang.spec +++ b/golang.spec @@ -63,7 +63,7 @@ Name: golang Version: 1.17.3 -Release: 37 +Release: 38 Summary: The Go Programming Language License: BSD and Public Domain URL: https://golang.org/ @@ -220,6 +220,9 @@ Patch6067: 0067-Backport-net-http-send-body-or-close-connection-on-e.patch Patch6068: 0068-Backport-go-parser-track-depth-in-nested-element-lis.patch Patch6069: 0069-Backport-encoding-gob-cover-missed-cases-when-checki.patch Patch6070: 0070-Backport-go-build-constraint-add-parsing-limits.patch +Patch6071: 0071-CVE-2024-45341-crypto-x509-properly-check-for-IPv6-h.patch +Patch6072: 0072-CVE-2024-45336-net-http-persist-header-stripping-acr.patch +Patch6073: 0073-crypto-tls-fix-Config.Time-in-tests-using-expir.patch ExclusiveArch: %{golang_arches} @@ -458,6 +461,12 @@ fi %files devel -f go-tests.list -f go-misc.list -f go-src.list %changelog +* Fri Feb 21 2025 wujichao - 1.17.3-38 +- Type:CVE +- CVE:CVE-2024-45341 CVE-2024-45336 +- SUG:NA +- DESC:fix CVE-2024-45341 CVE-2024-45336 + * Tue Oct 22 2024 hanchao - 1.17.3-37 - Type:CVE - CVE:CVE-2024-34156,CVE-2024-34158