diff mbox series

[scarthgap] go: patch CVE-2026-27145

Message ID 20260619075118.716327-1-tgaige.opensource@witekio.com
State New
Headers show
Series [scarthgap] go: patch CVE-2026-27145 | expand

Commit Message

tgaige.opensource@witekio.com June 19, 2026, 7:51 a.m. UTC
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>

Backport patch from [1]

[1] https://go.dev/cl/783621

Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
---
 meta/recipes-devtools/go/go-1.22.12.inc       |  1 +
 .../go/go/CVE-2026-27145.patch                | 96 +++++++++++++++++++
 2 files changed, 97 insertions(+)
 create mode 100644 meta/recipes-devtools/go/go/CVE-2026-27145.patch
diff mbox series

Patch

diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index f67da3e078..cd03d67355 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -55,6 +55,7 @@  SRC_URI += "\
     file://CVE-2026-42501.patch \
     file://CVE-2026-42504.patch \
     file://CVE-2026-42507.patch \
+    file://CVE-2026-27145.patch \
 "
 SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
 
diff --git a/meta/recipes-devtools/go/go/CVE-2026-27145.patch b/meta/recipes-devtools/go/go/CVE-2026-27145.patch
new file mode 100644
index 0000000000..f231aab458
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-27145.patch
@@ -0,0 +1,96 @@ 
+From 612753600a0184c8b792425dea62e530170ca811 Mon Sep 17 00:00:00 2001
+From: Ian Alexander <jitsu@google.com>
+Date: Wed, 27 May 2026 04:22:31 -0400
+Subject: [PATCH] crypto/x509: split candidate hostname only once
+
+(*x509.Certificate).VerifyHostname previously called matchHostnames in a
+loop over all DNS Subject Alternative Name (SAN) entries. This caused
+strings.Split(host, ".") to execute repeatedly on the same input
+hostname.
+
+With a large DNS SAN list, verification costs scaled quadratically based
+on the number of SAN entries multiplied by the hostname's label count.
+Because x509.Verify validates hostnames before building the certificate
+chain, this overhead occurred even for untrusted certificates.
+
+Thanks to Jakub Ciolek <jakub@ciolek.dev> for reporting this issue.
+
+Fixes #79694
+Fixes CVE-2026-27145
+
+Change-Id: I2788b8ee22ffd28e45bcc7b0d860549084906a74
+Reviewed-on: https://go-review.googlesource.com/c/go/+/783621
+LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Reviewed-by: David Chase <drchase@google.com>
+Reviewed-by: Neal Patel <neal@golang.org>
+
+CVE: CVE-2026-27145
+Upstream-Status: Backport [https://github.com/golang/go/commit/d01955d5d50ccb5f46c215f88c1781742b3f117d]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ src/crypto/x509/verify.go | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
+index 1de06bc95b..4c423a5fca 100644
+--- a/src/crypto/x509/verify.go
++++ b/src/crypto/x509/verify.go
+@@ -102,7 +102,7 @@ func (h HostnameError) Error() string {
+ 	c := h.Certificate
+ 	maxNamesIncluded := 100
+ 
+-	if !c.hasSANExtension() && matchHostnames(c.Subject.CommonName, h.Host) {
++	if !c.hasSANExtension() && matchHostnames(c.Subject.CommonName, splitHostname(h.Host)) {
+ 		return "x509: certificate relies on legacy Common Name field, use SANs instead"
+ 	}
+ 
+@@ -1081,16 +1081,14 @@ func matchExactly(hostA, hostB string) bool {
+ 	return toLowerCaseASCII(hostA) == toLowerCaseASCII(hostB)
+ }
+ 
+-func matchHostnames(pattern, host string) bool {
++func matchHostnames(pattern string, hostParts []string) bool {
+ 	pattern = toLowerCaseASCII(pattern)
+-	host = toLowerCaseASCII(strings.TrimSuffix(host, "."))
+ 
+-	if len(pattern) == 0 || len(host) == 0 {
++	if len(pattern) == 0 || len(hostParts) == 0 {
+ 		return false
+ 	}
+ 
+ 	patternParts := strings.Split(pattern, ".")
+-	hostParts := strings.Split(host, ".")
+ 
+ 	if len(patternParts) != len(hostParts) {
+ 		return false
+@@ -1168,6 +1166,7 @@ func (c *Certificate) VerifyHostname(h string) error {
+ 
+ 	candidateName := toLowerCaseASCII(h) // Save allocations inside the loop.
+ 	validCandidateName := validHostnameInput(candidateName)
++	hostParts := splitHostname(candidateName)
+ 
+ 	for _, match := range c.DNSNames {
+ 		// Ideally, we'd only match valid hostnames according to RFC 6125 like
+@@ -1176,7 +1175,7 @@ func (c *Certificate) VerifyHostname(h string) error {
+ 		// always allow perfect matches, and only apply wildcard and trailing
+ 		// dot processing to valid hostnames.
+ 		if validCandidateName && validHostnamePattern(match) {
+-			if matchHostnames(match, candidateName) {
++			if matchHostnames(match, hostParts) {
+ 				return nil
+ 			}
+ 		} else {
+@@ -1189,6 +1188,10 @@ func (c *Certificate) VerifyHostname(h string) error {
+ 	return HostnameError{c, h}
+ }
+ 
++func splitHostname(host string) []string {
++	return strings.Split(toLowerCaseASCII(strings.TrimSuffix(host, ".")), ".")
++}
++
+ func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
+ 	usages := make([]ExtKeyUsage, len(keyUsages))
+ 	copy(usages, keyUsages)
+-- 
+2.43.0
+