Skip to content

crypto/x509: multi-value RDN sequence is not properly DER-ordered #24254

Description

@mrogers950

RFC 5280 defines RelativeDistinguishedName as:
RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue

With RDN being a ‘SET OF’ AttributeTypeAndValue this means that RDNSequence should be encoded as an ordered sequence.

According to the DER ITU-T text:
https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#%5B%7B%22num%22%3A77%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22FitH%22%7D%2C421%5D

11.6 Set-of components
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. NOTE – The padding octets are for comparison purposes only and do not appear in the encodings.

Note while this rule is not stating explicitly length-ordered, it ends up being firstly ordered by length since the length octet will be the first differing octect to be compared, and the shorter length will be a lower value.

The RDNSequence supporting functions (ToRDNSequence() and appendRDNs()) currently do not perform any ordering by length or otherwise and accept RDNs in the provided order.

https://play.golang.org/p/bnWPNJ_xCTu
Output:

00000000  30 2c 31 1b 30 0d 06 03  55 04 0a 13 06 66 6f 6f  |0,1.0...U....foo|
00000010  62 61 72 30 0a 06 03 55  04 0a 13 03 66 6f 6f 31  |bar0...U....foo1|
00000020  0d 30 0b 06 03 55 04 03  13 04 75 73 65 72        |.0...U....user|

The correctly ordered encoding would look like:

00000000  30 2c 31 1b 30 0a 06 03  55 04 0a 13 03 66 6f 6f  |0,1.0...U....foo|
00000010  30 0d 06 03 55 04 0a 13  06 66 6f 6f 62 61 72 31  |0...U....foobar1|
00000020  0d 30 0b 06 03 55 04 03  13 04 75 73 65 72        |.0...U....user|

This can become an issue when using golang-created certificates containing multi-value RDNs against implementations that adhere to the SET OF encoding rules (like GnuTLS/libtasn1). In the case of GnuTLS, it performs a re-encoding of the certificate when acting as a TLS client, resulting in the “fixing” of the subject RDNs into an ordered set, leading to a changed certificate and thus signature invalidation.

$ go version
go version go1.9 linux/amd64
$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/mrogers/go"
GORACE=""
GOROOT="/usr/lib/golang"
GOTOOLDIR="/usr/lib/golang/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build850546982=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.early-in-cycleA change that should be done early in the 3 month dev cycle.release-blocker

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions