From: Vijay Anusuri <[email protected]>

Upstream-Status: Backport from 
https://github.com/golang/go/commit/3a842bd5c6aa8eefa13c0174de3ab361e50bd672

Signed-off-by: Vijay Anusuri <[email protected]>
Signed-off-by: Steve Sakoman <[email protected]>
---
 meta/recipes-devtools/go/go-1.22.12.inc       |   1 +
 .../go/go/CVE-2025-61729.patch                | 174 ++++++++++++++++++
 2 files changed, 175 insertions(+)
 create mode 100644 meta/recipes-devtools/go/go/CVE-2025-61729.patch

diff --git a/meta/recipes-devtools/go/go-1.22.12.inc 
b/meta/recipes-devtools/go/go-1.22.12.inc
index 664ccf3edc..ca5016c2f5 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -30,6 +30,7 @@ SRC_URI += "\
     file://CVE-2025-61723.patch \
     file://CVE-2025-61724.patch \
     file://CVE-2025-61727.patch \
+    file://CVE-2025-61729.patch \
 "
 SRC_URI[main.sha256sum] = 
"012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
 
diff --git a/meta/recipes-devtools/go/go/CVE-2025-61729.patch 
b/meta/recipes-devtools/go/go/CVE-2025-61729.patch
new file mode 100644
index 0000000000..08859e5729
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2025-61729.patch
@@ -0,0 +1,174 @@
+From 3a842bd5c6aa8eefa13c0174de3ab361e50bd672 Mon Sep 17 00:00:00 2001
+From: "Nicholas S. Husin" <[email protected]>
+Date: Mon, 24 Nov 2025 14:56:23 -0500
+Subject: [PATCH] [release-branch.go1.24] crypto/x509: prevent
+ HostnameError.Error() from consuming excessive resource
+
+Constructing HostnameError.Error() takes O(N^2) runtime due to using a
+string concatenation in a loop. Additionally, there is no limit on how
+many names are included in the error message. As a result, a malicious
+attacker could craft a certificate with an infinite amount of names to
+unfairly consume resource.
+
+To remediate this, we will now use strings.Builder to construct the
+error message, preventing O(N^2) runtime. When a certificate has 100 or
+more names, we will also not print each name individually.
+
+Thanks to Philippe Antoine (Catena cyber) for reporting this issue.
+
+Updates #76445
+Fixes #76460
+Fixes CVE-2025-61729
+
+Change-Id: I6343776ec3289577abc76dad71766c491c1a7c81
+Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3000
+Reviewed-by: Neal Patel <[email protected]>
+Reviewed-by: Damien Neil <[email protected]>
+Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3220
+Reviewed-by: Roland Shoemaker <[email protected]>
+Reviewed-on: https://go-review.googlesource.com/c/go/+/725820
+Reviewed-by: Dmitri Shuralyov <[email protected]>
+TryBot-Bypass: Dmitri Shuralyov <[email protected]>
+Auto-Submit: Dmitri Shuralyov <[email protected]>
+Reviewed-by: Mark Freeman <[email protected]>
+
+Upstream-Status: Backport 
[https://github.com/golang/go/commit/3a842bd5c6aa8eefa13c0174de3ab361e50bd672]
+CVE: CVE-2025-61729
+Signed-off-by: Vijay Anusuri <[email protected]>
+---
+ src/crypto/x509/verify.go      | 21 ++++++++++-----
+ src/crypto/x509/verify_test.go | 47 ++++++++++++++++++++++++++++++++++
+ 2 files changed, 61 insertions(+), 7 deletions(-)
+
+diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
+index 3fdf65f..0ae8aef 100644
+--- a/src/crypto/x509/verify.go
++++ b/src/crypto/x509/verify.go
+@@ -100,31 +100,38 @@ type HostnameError struct {
+ 
+ func (h HostnameError) Error() string {
+       c := h.Certificate
++      maxNamesIncluded := 100
+ 
+       if !c.hasSANExtension() && matchHostnames(c.Subject.CommonName, h.Host) 
{
+               return "x509: certificate relies on legacy Common Name field, 
use SANs instead"
+       }
+ 
+-      var valid string
++      var valid strings.Builder
+       if ip := net.ParseIP(h.Host); ip != nil {
+               // Trying to validate an IP
+               if len(c.IPAddresses) == 0 {
+                       return "x509: cannot validate certificate for " + 
h.Host + " because it doesn't contain any IP SANs"
+               }
++              if len(c.IPAddresses) >= maxNamesIncluded {
++                      return fmt.Sprintf("x509: certificate is valid for %d 
IP SANs, but none matched %s", len(c.IPAddresses), h.Host)
++              }
+               for _, san := range c.IPAddresses {
+-                      if len(valid) > 0 {
+-                              valid += ", "
++                      if valid.Len() > 0 {
++                              valid.WriteString(", ")
+                       }
+-                      valid += san.String()
++                      valid.WriteString(san.String())
+               }
+       } else {
+-              valid = strings.Join(c.DNSNames, ", ")
++              if len(c.DNSNames) >= maxNamesIncluded {
++                      return fmt.Sprintf("x509: certificate is valid for %d 
names, but none matched %s", len(c.DNSNames), h.Host)
++              }
++              valid.WriteString(strings.Join(c.DNSNames, ", "))
+       }
+ 
+-      if len(valid) == 0 {
++      if valid.Len() == 0 {
+               return "x509: certificate is not valid for any names, but 
wanted to match " + h.Host
+       }
+-      return "x509: certificate is valid for " + valid + ", not " + h.Host
++      return "x509: certificate is valid for " + valid.String() + ", not " + 
h.Host
+ }
+ 
+ // UnknownAuthorityError results when the certificate issuer is unknown
+diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
+index df9b0a2..223c250 100644
+--- a/src/crypto/x509/verify_test.go
++++ b/src/crypto/x509/verify_test.go
+@@ -10,13 +10,16 @@ import (
+       "crypto/ecdsa"
+       "crypto/elliptic"
+       "crypto/rand"
++      "crypto/rsa"
+       "crypto/x509/pkix"
+       "encoding/asn1"
+       "encoding/pem"
+       "errors"
+       "fmt"
+       "internal/testenv"
++      "log"
+       "math/big"
++      "net"
+       "os/exec"
+       "reflect"
+       "runtime"
+@@ -89,6 +92,26 @@ var verifyTests = []verifyTest{
+ 
+               errorCallback: expectHostnameError("certificate is valid for"),
+       },
++      {
++              name:        "TooManyDNS",
++              leaf:        generatePEMCertWithRepeatSAN(1677615892, 200, 
"fake.dns"),
++              roots:       []string{generatePEMCertWithRepeatSAN(1677615892, 
200, "fake.dns")},
++              currentTime: 1677615892,
++              dnsName:     "www.example.com",
++              systemSkip:  true, // does not chain to a system root
++
++              errorCallback: expectHostnameError("certificate is valid for 
200 names, but none matched"),
++      },
++      {
++              name:        "TooManyIPs",
++              leaf:        generatePEMCertWithRepeatSAN(1677615892, 150, 
"4.3.2.1"),
++              roots:       []string{generatePEMCertWithRepeatSAN(1677615892, 
150, "4.3.2.1")},
++              currentTime: 1677615892,
++              dnsName:     "1.2.3.4",
++              systemSkip:  true, // does not chain to a system root
++
++              errorCallback: expectHostnameError("certificate is valid for 
150 IP SANs, but none matched"),
++      },
+       {
+               name:          "IPMissing",
+               leaf:          googleLeaf,
+@@ -595,6 +618,30 @@ func nameToKey(name *pkix.Name) string {
+       return strings.Join(name.Country, ",") + "/" + 
strings.Join(name.Organization, ",") + "/" + 
strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
+ }
+ 
++func generatePEMCertWithRepeatSAN(currentTime int64, count int, san string) 
string {
++      cert := Certificate{
++              NotBefore: time.Unix(currentTime, 0),
++              NotAfter:  time.Unix(currentTime, 0),
++      }
++      if ip := net.ParseIP(san); ip != nil {
++              cert.IPAddresses = slices.Repeat([]net.IP{ip}, count)
++      } else {
++              cert.DNSNames = slices.Repeat([]string{san}, count)
++      }
++      privKey, err := rsa.GenerateKey(rand.Reader, 4096)
++      if err != nil {
++              log.Fatal(err)
++      }
++      certBytes, err := CreateCertificate(rand.Reader, &cert, &cert, 
&privKey.PublicKey, privKey)
++      if err != nil {
++              log.Fatal(err)
++      }
++      return string(pem.EncodeToMemory(&pem.Block{
++              Type:  "CERTIFICATE",
++              Bytes: certBytes,
++      }))
++}
++
+ const gtsIntermediate = `-----BEGIN CERTIFICATE-----
+ MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw
+ CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
+-- 
+2.43.0
+
-- 
2.43.0

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#228626): 
https://lists.openembedded.org/g/openembedded-core/message/228626
Mute This Topic: https://lists.openembedded.org/mt/116991239/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to