-
Notifications
You must be signed in to change notification settings - Fork 18.3k
Description
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"