x509roots/fallback/bundle: fix bundle test with Go 1.27+ In Go 1.27 we've updated crypto/x509/pkix to avoid hex-encoding attribute values that are string-typed. However, in TestBundle() we assert the parsed certificate subject CN matches expected and now the parsed value differs based on Go version. This commit introduces some small helpers that on Go 1.25/1.26 replicate the Go 1.27 behavior, decoding hex-encoded attribute values before making the comparison. In this way the test continues to pass without losing any coverage, or introducing duplicated per-version bundles. In the future when only Go 1.27+ are supported we can revert this extra machinery. Change-Id: I66bf6439e421169c0f9c750f88116b73ec5188fe Reviewed-on: https://go-review.googlesource.com/c/crypto/+/775760 Reviewed-by: Roland Shoemaker <roland@golang.org> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Auto-Submit: Daniel McCarney <daniel@binaryparadox.net>
diff --git a/x509roots/fallback/bundle/bundle_test.go b/x509roots/fallback/bundle/bundle_test.go index 3eafe15..222e76c 100644 --- a/x509roots/fallback/bundle/bundle_test.go +++ b/x509roots/fallback/bundle/bundle_test.go
@@ -7,7 +7,9 @@ import ( "crypto/sha256" "crypto/x509" + "encoding/asn1" "encoding/hex" + "regexp" "testing" ) @@ -19,7 +21,7 @@ continue } - if unparsed.cn != cert.Subject.String() { + if !subjectsEqual(unparsed.cn, cert.Subject.String()) { t.Errorf("unparsedCertificates[%v].cn = %q; want = %q", i, unparsed.cn, cert.Subject.String()) } @@ -30,3 +32,34 @@ } } } + +// 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:]]+)`)