Skip to content
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

crypto/x509: certificate verification does not correctly compare subject and issuer names for equality #36027

Closed
paulgriffiths opened this issue Dec 6, 2019 · 1 comment

Comments

@paulgriffiths
Copy link

@paulgriffiths paulgriffiths commented Dec 6, 2019

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.

@paulgriffiths
Copy link
Author

@paulgriffiths paulgriffiths commented Dec 6, 2019

Seems to be a dupe of #31440.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
1 participant
You can’t perform that action at this time.