Skip to content

crypto/x509: ParseCertificate allows unsorted SET values in RDNs #73743

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
printfn opened this issue May 16, 2025 · 3 comments
Open

crypto/x509: ParseCertificate allows unsorted SET values in RDNs #73743

printfn opened this issue May 16, 2025 · 3 comments
Labels
BugReport Issues describing a possible bug in the Go implementation. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.

Comments

@printfn
Copy link

printfn commented May 16, 2025

Go version

go version go1.24.3 linux/amd64

Output of go env in your module/workspace:

AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/user/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/user/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build2784876717=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/home/user/Code/go-test/go.mod'
GOMODCACHE='/home/user/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/user/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/user/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.3'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

Playground: https://go.dev/play/p/OoaeG_APMGI

What did you see happen?

Golang unmarshals incorrectly-sorted ASN.1 SET values. The example certificate has a multi-valued RDN that is incorrectly sorted. This is invalid DER and should not have been parsed.

What did you expect to see?

Golang should have errored when parsing the certificate.

See https://www.itu.int/rec/T-REC-X.690-202102-I/en, section 11.6:

The encodings of the component values of a set-of value shall appear in ascending order, the encodings being compared as
octet strings with the shorter components being padded at their trailing end with 0-octets.

@gabyhelp gabyhelp added the BugReport Issues describing a possible bug in the Go implementation. label May 16, 2025
@mateusz834
Copy link
Member

Looking at the example you provided, i think that this is more related to crypto/x509 since the x509 parser does not use encoding/asn1, but x/crypto/cryptobyte.

Looking at the parsing code for RDNs, it does not check the ordering of the SET values:

// parseName parses a DER encoded Name as defined in RFC 5280. We may
// want to export this function in the future for use in crypto/tls.
func parseName(raw cryptobyte.String) (*pkix.RDNSequence, error) {
if !raw.ReadASN1(&raw, cryptobyte_asn1.SEQUENCE) {
return nil, errors.New("x509: invalid RDNSequence")
}
var rdnSeq pkix.RDNSequence
for !raw.Empty() {
var rdnSet pkix.RelativeDistinguishedNameSET
var set cryptobyte.String
if !raw.ReadASN1(&set, cryptobyte_asn1.SET) {
return nil, errors.New("x509: invalid RDNSequence")
}
for !set.Empty() {
var atav cryptobyte.String
if !set.ReadASN1(&atav, cryptobyte_asn1.SEQUENCE) {
return nil, errors.New("x509: invalid RDNSequence: invalid attribute")
}
var attr pkix.AttributeTypeAndValue
if !atav.ReadASN1ObjectIdentifier(&attr.Type) {
return nil, errors.New("x509: invalid RDNSequence: invalid attribute type")
}
var rawValue cryptobyte.String
var valueTag cryptobyte_asn1.Tag
if !atav.ReadAnyASN1(&rawValue, &valueTag) {
return nil, errors.New("x509: invalid RDNSequence: invalid attribute value")
}
var err error
attr.Value, err = parseASN1String(valueTag, rawValue)
if err != nil {
return nil, fmt.Errorf("x509: invalid RDNSequence: invalid attribute value: %s", err)
}
rdnSet = append(rdnSet, attr)
}
rdnSeq = append(rdnSeq, rdnSet)
}
return &rdnSeq, nil
}

But is also seems like encoding/asn1 accepts such encoding:

func TestTest(t *testing.T) {
	const rdsSeq = "MBYxFDAIBgNVBAoMAUIwCAYDVQQKDAFB"
	bytes, err := base64.RawStdEncoding.DecodeString(rdsSeq)
	if err != nil {
		t.Fatal(err)
	}
	var rdns RDNSequence
	_, err = Unmarshal(bytes, &rdns)
	if err != nil {
		t.Fatal(err)
	}
	t.Log(rdns) // [[{2.5.4.10 B} {2.5.4.10 A}]]
}

@mateusz834 mateusz834 added NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. BugReport Issues describing a possible bug in the Go implementation. and removed BugReport Issues describing a possible bug in the Go implementation. labels May 16, 2025
@mateusz834 mateusz834 changed the title encoding/asn1: Unmarshal allows unsorted SET values crypto/x509: ParseCertificate allows unsorted SET values in RDNs May 16, 2025
@mateusz834
Copy link
Member

CC @rolandshoemaker

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BugReport Issues describing a possible bug in the Go implementation. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

3 participants