From afebf4cb4efb2b854282e03160da67120707f8f7 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Fri, 8 May 2026 11:37:29 -0400 Subject: [PATCH] x509roots/fallback/bundle: make subjectsEqual stricter on Go 1.27+ This gradual step towards removing/inlining subjectsEqual can happen after Go 1.27.0 is released and the bundle starts being generated with it. Change-Id: Ib315bae69c45922c3f0aac5d2c0155fb5d94229f Reviewed-on: https://go-review.googlesource.com/c/crypto/+/775782 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Cherry Mui Auto-Submit: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov Reviewed-by: Daniel McCarney --- x509roots/fallback/bundle/bundle126_test.go | 47 +++++++++++++++++++++ x509roots/fallback/bundle/bundle127_test.go | 21 +++++++++ x509roots/fallback/bundle/bundle_test.go | 33 --------------- 3 files changed, 68 insertions(+), 33 deletions(-) create mode 100644 x509roots/fallback/bundle/bundle126_test.go create mode 100644 x509roots/fallback/bundle/bundle127_test.go diff --git a/x509roots/fallback/bundle/bundle126_test.go b/x509roots/fallback/bundle/bundle126_test.go new file mode 100644 index 0000000..5e18bc7 --- /dev/null +++ b/x509roots/fallback/bundle/bundle126_test.go @@ -0,0 +1,47 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !go1.27 + +package bundle + +import ( + "encoding/asn1" + "encoding/hex" + "regexp" +) + +// subjectsEqual reports whether two RFC 2253 DN strings match. +// +// When testing with Go 1.27 or newer, it requires subjects to match exactly. +// When testing with Go 1.26, it tolerates the rendering difference introduced in Go 1.27, +// where string-typed attribute values for OIDs outside attributeTypeNames are rendered +// as strings rather than hex-encoded DER (see Go CL 773800). +// +// When Go 1.26 is no longer supported, +// the Go 1.26 version can be removed and +// the Go 1.27+ version can be inlined. +func subjectsEqual(a, b string) bool { + return a == b || normalizeHexValues(a) == normalizeHexValues(b) +} + +// normalizeHexValues rewrites any "oid=#hex" to the equivalent "oid=value" +// rendering produced by Go 1.27+. +func normalizeHexValues(s string) string { + return hexAttrRE.ReplaceAllStringFunc(s, func(match string) string { + m := hexAttrRE.FindStringSubmatch(match) + der, err := hex.DecodeString(m[2]) + if err != nil { + return match + } + var v string + if rest, err := asn1.Unmarshal(der, &v); err != nil || len(rest) != 0 { + return match + } + return m[1] + "=" + v + }) +} + +// hexAttrRE matches a "oid=#hex" attribute value in an RFC 2253 DN string. +var hexAttrRE = regexp.MustCompile(`([\d.]+)=#([[:xdigit:]]+)`) diff --git a/x509roots/fallback/bundle/bundle127_test.go b/x509roots/fallback/bundle/bundle127_test.go new file mode 100644 index 0000000..d965aa3 --- /dev/null +++ b/x509roots/fallback/bundle/bundle127_test.go @@ -0,0 +1,21 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.27 + +package bundle + +// subjectsEqual reports whether two RFC 2253 DN strings match. +// +// When testing with Go 1.27 or newer, it requires subjects to match exactly. +// When testing with Go 1.26, it tolerates the rendering difference introduced in Go 1.27, +// where string-typed attribute values for OIDs outside attributeTypeNames are rendered +// as strings rather than hex-encoded DER (see Go CL 773800). +// +// When Go 1.26 is no longer supported, +// the Go 1.26 version can be removed and +// the Go 1.27+ version can be inlined. +func subjectsEqual(a, b string) bool { + return a == b +} diff --git a/x509roots/fallback/bundle/bundle_test.go b/x509roots/fallback/bundle/bundle_test.go index 222e76c..f2ef97d 100644 --- a/x509roots/fallback/bundle/bundle_test.go +++ b/x509roots/fallback/bundle/bundle_test.go @@ -7,9 +7,7 @@ package bundle import ( "crypto/sha256" "crypto/x509" - "encoding/asn1" "encoding/hex" - "regexp" "testing" ) @@ -32,34 +30,3 @@ func TestBundle(t *testing.T) { } } } - -// subjectsEqual reports whether two RFC 2253 DN strings match. -// -// It tolerates the rendering difference introduced in Go 1.27, where -// string-typed attribute values for OIDs outside attributeTypeNames are -// rendered as strings rather than hex-encoded DER (see Go CL 773800). -// -// This can be removed when Go 1.25/1.26 are no longer supported. -func subjectsEqual(a, b string) bool { - return a == b || normalizeHexValues(a) == normalizeHexValues(b) -} - -// normalizeHexValues rewrites any "oid=#hex" to the equivalent "oid=value" -// rendering produced by Go 1.27+. -func normalizeHexValues(s string) string { - return hexAttrRE.ReplaceAllStringFunc(s, func(match string) string { - m := hexAttrRE.FindStringSubmatch(match) - der, err := hex.DecodeString(m[2]) - if err != nil { - return match - } - var v string - if rest, err := asn1.Unmarshal(der, &v); err != nil || len(rest) != 0 { - return match - } - return m[1] + "=" + v - }) -} - -// hexAttrRE matches a "oid=#hex" attribute value in an RFC 2253 DN string. -var hexAttrRE = regexp.MustCompile(`([\d.]+)=#([[:xdigit:]]+)`)