Description
What version of Go are you using (go version
)?
go1.13.1 darwin/amd64
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (go env
)?
go env
Output
GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/Users/paul.griffiths/Library/Caches/go-build" GOENV="/Users/paul.griffiths/Library/Application Support/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="darwin" GONOPROXY="" GONOSUMDB="" GOOS="darwin" GOPATH="/Users/paul.griffiths/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/usr/local/Cellar/go/1.13.1/libexec" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/usr/local/Cellar/go/1.13.1/libexec/pkg/tool/darwin_amd64" GCCGO="gccgo" AR="ar" CC="clang" CXX="clang++" CGO_ENABLED="1" GOMOD="" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/pd/c64q7jrx2fd_bw2h5td3vv6m0000gp/T/go-build590013081=/tmp/go-build -gno-record-gcc-switches -fno-common"
What did you do?
Attempted to verify a certificate against a CA certificate when the issuer name of the certificate and the subject name of the CA certificate are identical in every respect except in the former case the naming attribute values are encoded as ASN.1 PrintableString, and in the latter case the naming attribute values are encoded as ASN.1 UTF8String.
What did you expect to see?
The certificate should successfully verify.
Per RFC 5280, section 7.1:
Conforming implementations MUST use the LDAP StringPrep profile
(including insignificant space handling), as specified in [RFC4518],
as the basis for comparison of distinguished name attributes encoded
in either PrintableString or UTF8String.
...
Two naming attributes match if the attribute types are the same and
the values of the attributes are an exact match after processing with
the string preparation algorithm.
and per RFC 4518, section 2.1:
Each non-Unicode string value is transcoded to Unicode.
PrintableString [X.680] values are transcoded directly to Unicode.
UniversalString, UTF8String, and bmpString [X.680] values need not be
transcoded as they are Unicode-based strings
Therefore, name components represented as PrintableString should be transcoded to Unicode prior to comparison, and should compare equal with a UTF8String with an identical value.
What did you see instead?
The certificate does not successfully verify, and a CertificateInvalidError
with reason NameMismatch
is returned.
The second check of x509.isValid
is:
if len(currentChain) > 0 {
child := currentChain[len(currentChain)-1]
if !bytes.Equal(child.RawIssuer, c.RawSubject) {
return CertificateInvalidError{c, NameMismatch, ""}
}
}
By simply comparing the raw ASN.1 bytes of the issuer name with the raw ASN.1 bytes of the subject name of the parent certificate in the chain, the check is failing to use the LDAP StringPrep profile as the basis for comparison of distinguished name attributes, as RFC 5280 section 7.1 requires conforming implementations to do. Because the ASN.1 tag values for PrintableString and UTF8String are different, use of bytes.Equal
reports the names as different, when they should compare equal. As a result, x509.Certificate.Verify
is incorrectly failing to verify some certificates which should successfully verify.
A better approach may be to unmarshal both names into a pkix.RDNSequence
where both PrintableString and UTF8String will be converted to string
, and then compare the two for equality.
Activity
paulgriffiths commentedon Dec 6, 2019
Seems to be a dupe of #31440.