summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArchana Polampalli <archana.polampalli@windriver.com>2025-11-28 21:37:56 +0530
committerSteve Sakoman <steve@sakoman.com>2025-12-05 06:56:34 -0800
commitdd0a2c24702152c76547b1db2690ff5af3d23f06 (patch)
tree0055e85c4556e6e554520994d0ed64852b8b4e35
parentc5794d82b0a6d985fbec5b50133a812c2c1dbb97 (diff)
downloadpoky-dd0a2c24702152c76547b1db2690ff5af3d23f06.tar.gz
go: fix CVE-2025-58187
Due to the design of the name constraint checking algorithm, the processing time of some inputs scale non-linearly with respect to the size of the certificate. This affects programs which validate arbitrary certificate chains. (From OE-Core rev: cea9fcf1b21b1b35b88986b676d712ab8ffa9d67) Signed-off-by: Archana Polampalli <archana.polampalli@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.18/CVE-2025-58187.patch349
2 files changed, 350 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 465f24e108..c5aa3f9786 100644
--- a/meta/recipes-devtools/go/go-1.17.13.inc
+++ b/meta/recipes-devtools/go/go-1.17.13.inc
@@ -69,6 +69,7 @@ SRC_URI = "https://golang.org/dl/go${PV}.src.tar.gz;name=main \
69 file://CVE-2025-47907.patch \ 69 file://CVE-2025-47907.patch \
70 file://CVE-2025-47906.patch \ 70 file://CVE-2025-47906.patch \
71 file://CVE-2024-24783.patch \ 71 file://CVE-2024-24783.patch \
72 file://CVE-2025-58187.patch \
72 " 73 "
73SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd" 74SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd"
74 75
diff --git a/meta/recipes-devtools/go/go-1.18/CVE-2025-58187.patch b/meta/recipes-devtools/go/go-1.18/CVE-2025-58187.patch
new file mode 100644
index 0000000000..810487674c
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.18/CVE-2025-58187.patch
@@ -0,0 +1,349 @@
1From f334417e71f8b078ad64035bddb6df7f8910da6c Mon Sep 17 00:00:00 2001
2From: Neal Patel <nealpatel@google.com>
3Date: Mon, 15 Sep 2025 16:31:22 -0400
4Subject: [PATCH] crypto/x509: improve domain name verification
5
6Don't use domainToReverseLabels to check if domain names are valid,
7since it is not particularly performant, and can contribute to DoS
8vectors. Instead just iterate over the name and enforce the properties
9we care about.
10
11This also enforces that DNS names, both in SANs and name constraints,
12are valid. We previously allowed invalid SANs, because some
13intermediates had these weird names (see #23995), but there are
14currently no trusted intermediates that have this property, and since we
15target the web PKI, supporting this particular case is not a high
16priority.
17
18Thank you to Jakub Ciolek for reporting this issue.
19
20Fixes CVE-2025-58187
21For #75681
22Fixes #75714
23
24Change-Id: I6ebce847dcbe5fc63ef2f9a74f53f11c4c56d3d1
25Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2820
26Reviewed-by: Damien Neil <dneil@google.com>
27Reviewed-by: Roland Shoemaker <bracewell@google.com>
28Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2982
29Reviewed-by: Nicholas Husin <husin@google.com>
30Reviewed-on: https://go-review.googlesource.com/c/go/+/709839
31Auto-Submit: Michael Pratt <mpratt@google.com>
32Reviewed-by: Carlos Amedee <carlos@golang.org>
33TryBot-Bypass: Michael Pratt <mpratt@google.com>
34
35CVE: CVE-2025-58187
36
37Upstream-Status: Backport [https://github.com/golang/go/commit/f334417e71f8b078ad64035bddb6df7f8910da6c]
38
39Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
40---
41 src/crypto/x509/name_constraints_test.go | 66 ++------------------
42 src/crypto/x509/parser.go | 77 ++++++++++++++----------
43 src/crypto/x509/parser_test.go | 43 +++++++++++++
44 src/crypto/x509/verify.go | 1 +
45 4 files changed, 95 insertions(+), 92 deletions(-)
46
47diff --git a/src/crypto/x509/name_constraints_test.go b/src/crypto/x509/name_constraints_test.go
48index c59a7dc..d4f7d41 100644
49--- a/src/crypto/x509/name_constraints_test.go
50+++ b/src/crypto/x509/name_constraints_test.go
51@@ -1452,63 +1452,7 @@ var nameConstraintsTests = []nameConstraintsTest{
52 requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
53 },
54
55- // An invalid DNS SAN should be detected only at validation time so
56- // that we can process CA certificates in the wild that have invalid SANs.
57- // See https://github.com/golang/go/issues/23995
58-
59- // #77: an invalid DNS or mail SAN will not be detected if name constraint
60- // checking is not triggered.
61- {
62- roots: make([]constraintsSpec, 1),
63- intermediates: [][]constraintsSpec{
64- {
65- {},
66- },
67- },
68- leaf: leafSpec{
69- sans: []string{"dns:this is invalid", "email:this @ is invalid"},
70- },
71- },
72-
73- // #78: an invalid DNS SAN will be detected if any name constraint checking
74- // is triggered.
75- {
76- roots: []constraintsSpec{
77- {
78- bad: []string{"uri:"},
79- },
80- },
81- intermediates: [][]constraintsSpec{
82- {
83- {},
84- },
85- },
86- leaf: leafSpec{
87- sans: []string{"dns:this is invalid"},
88- },
89- expectedError: "cannot parse dnsName",
90- },
91-
92- // #79: an invalid email SAN will be detected if any name constraint
93- // checking is triggered.
94- {
95- roots: []constraintsSpec{
96- {
97- bad: []string{"uri:"},
98- },
99- },
100- intermediates: [][]constraintsSpec{
101- {
102- {},
103- },
104- },
105- leaf: leafSpec{
106- sans: []string{"email:this @ is invalid"},
107- },
108- expectedError: "cannot parse rfc822Name",
109- },
110-
111- // #80: if several EKUs are requested, satisfying any of them is sufficient.
112+ // #77: if several EKUs are requested, satisfying any of them is sufficient.
113 {
114 roots: make([]constraintsSpec, 1),
115 intermediates: [][]constraintsSpec{
116@@ -1523,7 +1467,7 @@ var nameConstraintsTests = []nameConstraintsTest{
117 requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection},
118 },
119
120- // #81: EKUs that are not asserted in VerifyOpts are not required to be
121+ // #78: EKUs that are not asserted in VerifyOpts are not required to be
122 // nested.
123 {
124 roots: make([]constraintsSpec, 1),
125@@ -1542,7 +1486,7 @@ var nameConstraintsTests = []nameConstraintsTest{
126 },
127 },
128
129- // #82: a certificate without SANs and CN is accepted in a constrained chain.
130+ // #79: a certificate without SANs and CN is accepted in a constrained chain.
131 {
132 roots: []constraintsSpec{
133 {
134@@ -1559,7 +1503,7 @@ var nameConstraintsTests = []nameConstraintsTest{
135 },
136 },
137
138- // #83: a certificate without SANs and with a CN that does not parse as a
139+ // #80: a certificate without SANs and with a CN that does not parse as a
140 // hostname is accepted in a constrained chain.
141 {
142 roots: []constraintsSpec{
143@@ -1578,7 +1522,7 @@ var nameConstraintsTests = []nameConstraintsTest{
144 },
145 },
146
147- // #84: a certificate with SANs and CN is accepted in a constrained chain.
148+ // #81: a certificate with SANs and CN is accepted in a constrained chain.
149 {
150 roots: []constraintsSpec{
151 {
152diff --git a/src/crypto/x509/parser.go b/src/crypto/x509/parser.go
153index 635e74b..0788210 100644
154--- a/src/crypto/x509/parser.go
155+++ b/src/crypto/x509/parser.go
156@@ -391,10 +391,14 @@ func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string
157 if err := isIA5String(email); err != nil {
158 return errors.New("x509: SAN rfc822Name is malformed")
159 }
160+ parsed, ok := parseRFC2821Mailbox(email)
161+ if !ok || (ok && !domainNameValid(parsed.domain, false)) {
162+ return errors.New("x509: SAN rfc822Name is malformed")
163+ }
164 emailAddresses = append(emailAddresses, email)
165 case nameTypeDNS:
166 name := string(data)
167- if err := isIA5String(name); err != nil {
168+ if err := isIA5String(name); err != nil || (err == nil && !domainNameValid(name, false)) {
169 return errors.New("x509: SAN dNSName is malformed")
170 }
171 dnsNames = append(dnsNames, string(name))
172@@ -404,14 +408,9 @@ func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string
173 return errors.New("x509: SAN uniformResourceIdentifier is malformed")
174 }
175 uri, err := url.Parse(uriStr)
176- if err != nil {
177+ if err != nil || (err == nil && uri.Host != "" && !domainNameValid(uri.Host, false)) {
178 return fmt.Errorf("x509: cannot parse URI %q: %s", uriStr, err)
179 }
180- if len(uri.Host) > 0 {
181- if _, ok := domainToReverseLabels(uri.Host); !ok {
182- return fmt.Errorf("x509: cannot parse URI %q: invalid domain", uriStr)
183- }
184- }
185 uris = append(uris, uri)
186 case nameTypeIP:
187 switch len(data) {
188@@ -551,15 +550,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
189 return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
190 }
191
192- trimmedDomain := domain
193- if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' {
194- // constraints can have a leading
195- // period to exclude the domain
196- // itself, but that's not valid in a
197- // normal domain name.
198- trimmedDomain = trimmedDomain[1:]
199- }
200- if _, ok := domainToReverseLabels(trimmedDomain); !ok {
201+ if !domainNameValid(domain, true) {
202 return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain)
203 }
204 dnsNames = append(dnsNames, domain)
205@@ -600,12 +591,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
206 return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
207 }
208 } else {
209- // Otherwise it's a domain name.
210- domain := constraint
211- if len(domain) > 0 && domain[0] == '.' {
212- domain = domain[1:]
213- }
214- if _, ok := domainToReverseLabels(domain); !ok {
215+ if !domainNameValid(constraint, true) {
216 return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
217 }
218 }
219@@ -621,15 +607,7 @@ func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandle
220 return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain)
221 }
222
223- trimmedDomain := domain
224- if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' {
225- // constraints can have a leading
226- // period to exclude the domain itself,
227- // but that's not valid in a normal
228- // domain name.
229- trimmedDomain = trimmedDomain[1:]
230- }
231- if _, ok := domainToReverseLabels(trimmedDomain); !ok {
232+ if !domainNameValid(domain, true) {
233 return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain)
234 }
235 uriDomains = append(uriDomains, domain)
236@@ -1011,3 +989,40 @@ func ParseCertificates(der []byte) ([]*Certificate, error) {
237 }
238 return certs, nil
239 }
240+
241+// domainNameValid does minimal domain name validity checking. In particular it
242+// enforces the following properties:
243+// - names cannot have the trailing period
244+// - names can only have a leading period if constraint is true
245+// - names must be <= 253 characters
246+// - names cannot have empty labels
247+// - names cannot labels that are longer than 63 characters
248+//
249+// Note that this does not enforce the LDH requirements for domain names.
250+func domainNameValid(s string, constraint bool) bool {
251+ if len(s) == 0 && constraint {
252+ return true
253+ }
254+ if len(s) == 0 || (!constraint && s[0] == '.') || s[len(s)-1] == '.' || len(s) > 253 {
255+ return false
256+ }
257+ lastDot := -1
258+ if constraint && s[0] == '.' {
259+ s = s[1:]
260+ }
261+
262+ for i := 0; i <= len(s); i++ {
263+ if i == len(s) || s[i] == '.' {
264+ labelLen := i
265+ if lastDot >= 0 {
266+ labelLen -= lastDot + 1
267+ }
268+ if labelLen == 0 || labelLen > 63 {
269+ return false
270+ }
271+ lastDot = i
272+ }
273+ }
274+
275+ return true
276+}
277diff --git a/src/crypto/x509/parser_test.go b/src/crypto/x509/parser_test.go
278index d7cf7ea..95ed116 100644
279--- a/src/crypto/x509/parser_test.go
280+++ b/src/crypto/x509/parser_test.go
281@@ -5,6 +5,7 @@ package x509
282
283 import (
284 "encoding/asn1"
285+ "strings"
286 "testing"
287
288 cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
289@@ -100,3 +101,45 @@ func TestParseASN1String(t *testing.T) {
290 })
291 }
292 }
293+
294+func TestDomainNameValid(t *testing.T) {
295+ for _, tc := range []struct {
296+ name string
297+ dnsName string
298+ constraint bool
299+ valid bool
300+ }{
301+ {"empty name, name", "", false, false},
302+ {"empty name, constraint", "", true, true},
303+ {"empty label, name", "a..a", false, false},
304+ {"empty label, constraint", "a..a", true, false},
305+ {"period, name", ".", false, false},
306+ {"period, constraint", ".", true, false}, // TODO(roland): not entirely clear if this is a valid constraint (require at least one label?)
307+ {"valid, name", "a.b.c", false, true},
308+ {"valid, constraint", "a.b.c", true, true},
309+ {"leading period, name", ".a.b.c", false, false},
310+ {"leading period, constraint", ".a.b.c", true, true},
311+ {"trailing period, name", "a.", false, false},
312+ {"trailing period, constraint", "a.", true, false},
313+ {"bare label, name", "a", false, true},
314+ {"bare label, constraint", "a", true, true},
315+ {"254 char label, name", strings.Repeat("a.a", 84) + "aaa", false, false},
316+ {"254 char label, constraint", strings.Repeat("a.a", 84) + "aaa", true, false},
317+ {"253 char label, name", strings.Repeat("a.a", 84) + "aa", false, false},
318+ {"253 char label, constraint", strings.Repeat("a.a", 84) + "aa", true, false},
319+ {"64 char single label, name", strings.Repeat("a", 64), false, false},
320+ {"64 char single label, constraint", strings.Repeat("a", 64), true, false},
321+ {"63 char single label, name", strings.Repeat("a", 63), false, true},
322+ {"63 char single label, constraint", strings.Repeat("a", 63), true, true},
323+ {"64 char label, name", "a." + strings.Repeat("a", 64), false, false},
324+ {"64 char label, constraint", "a." + strings.Repeat("a", 64), true, false},
325+ {"63 char label, name", "a." + strings.Repeat("a", 63), false, true},
326+ {"63 char label, constraint", "a." + strings.Repeat("a", 63), true, true},
327+ } {
328+ t.Run(tc.name, func(t *testing.T) {
329+ if tc.valid != domainNameValid(tc.dnsName, tc.constraint) {
330+ t.Errorf("domainNameValid(%q, %t) = %v; want %v", tc.dnsName, tc.constraint, !tc.valid, tc.valid)
331+ }
332+ })
333+ }
334+}
335diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
336index 3e95808..fb2f4b2 100644
337--- a/src/crypto/x509/verify.go
338+++ b/src/crypto/x509/verify.go
339@@ -357,6 +357,7 @@ func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) {
340 // domainToReverseLabels converts a textual domain name like foo.example.com to
341 // the list of labels in reverse order, e.g. ["com", "example", "foo"].
342 func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) {
343+ reverseLabels = make([]string, 0, strings.Count(domain, ".")+1)
344 for len(domain) > 0 {
345 if i := strings.LastIndexByte(domain, '.'); i == -1 {
346 reverseLabels = append(reverseLabels, domain)
347--
3482.40.0
349