Repository: go
Issue: crypto/x509: pkix.Name.String() does not preserve correct order 
Labels: NeedsInvestigation

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version go1.18.1 linux/amd64
</pre>

### Does this issue reproduce with the latest release?
Yes, produces with go version go1.18.1


### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GOARCH="amd64"
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOVERSION="go1.18.1"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build281192732=/tmp/go-build -gno-record-gcc-switches"
</pre></details>

### What did you do?

Create three ceritificates with openssl:
<pre>
openssl req -new -x509 -subj '/CN=foo/O=bar/C=FI/' -nodes -outform DER -out cert1.crt
openssl req -new -x509 -subj '/O=bar/CN=foo/C=FI/' -nodes -outform DER -out cert2.crt
openssl req -new -x509 -multivalue-rdn -subj '/CN=foo+UID=1234/O=bar/C=FI/' -nodes -outform DER -out cert3.crt
</pre>
<!--
If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on go.dev/play is best.
-->

Read in and print the subject name of each certificates with the following program:

```go
package main

import (
	"crypto/x509"
	"fmt"
	"os"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Println("need path to cert")
		os.Exit(1)
	}
	f, err := os.Open(os.Args[1])
	if err != nil {
		panic(err)
	}
	certBytes := make([]byte, 2000)
	n, err := f.Read(certBytes)
	if err != nil {
		panic(err)
	}
	f.Close()
	cert, err := x509.ParseCertificate(certBytes[:n])
	if err != nil {
		panic(err)
	}

	fmt.Println(cert.Subject.String())
}
```

### What did you expect to see?
cert1.crt:  `CN=foo,O=bar,C=FI`

cert2.crt: `O=bar,CN=foo,C=FI`

cert3.crt: `CN=foo+0.9.2342.19200300.100.1.1=#130431323334,O=bar,C=FI`

(Or actually for cert3.crt: `CN=foo+0.9.2342.19200300.100.1.1=1234,O=bar,C=FI`, but that is another issue, see https://github.com/golang/go/issues/33093.)


### What did you see instead?

cert1.crt: `CN=foo,O=bar,C=FI` (as expected)

cert2.crt: `CN=foo,O=bar,C=FI` (order is not maintained)

cert3.crt : `CN=foo,O=bar,C=FI,0.9.2342.19200300.100.1.1=#130431323334` (order is not mainainted, multi value RDN lost)


To be fair, the documentation for pkix.Name.String() says:

> String returns the string form of n, roughly following the [RFC 2253](https://rfc-editor.org/rfc/rfc2253.html) Distinguished Names syntax.

But I think the "roughly" is a little too liberally interpretted.

RFC2253 2.1 says:

> the output consists of the string encodings of each
>  RelativeDistinguishedName in the RDNSequence (according to 2.2),
>  starting with the last element of the sequence and moving backwards
>  toward the first.

So the ordering should be mainainted. 

Looking at https://github.com/golang/go/issues/39924 I suspect there is a misinterpretation where @FiloSottile says:

> RFC 2253 lets us pick any order we like.

However, the quoted text is related to the individual RDN parts, so both the following would be correct for cert3.crt:

<pre>
CN=foo+0.9.2342.19200300.100.1.1=#130431323334,O=bar,C=FI
0.9.2342.19200300.100.1.1=#130431323334+CN=foo,O=bar,C=FI
</pre>

But not:

<pre>
CN=foo,O=bar,C=FI,0.9.2342.19200300.100.1.1=#130431323334
</pre>

Further and for clarity, looking at the ASN.1 structure of the Subject DN of cert3.crt:

<pre>
SEQUENCE (3 elem)
      SET (2 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.4.3 commonName
          UTF8String foo
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 0.9.2342.19200300.100.1.1 userID
          UTF8String 1234
      SET (1 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.4.10 organizationName
          UTF8String bar
      SET (1 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 2.5.4.6 countryName
          PrintableString FI
</pre>

You can see that each RDN is in a sequence (order should be maintained) but the multivalue RDN is a set (order does not matter. you can pick any order). The same goes for cert2.crt where the String() method throws the RDNs around in a fixed orderd and places unrecognized RDNs last.  

In addition to this, it looks the String() method prints the sequence in reverse to what RFC 2253 says "starting with the last element of the sequence and moving backwards toward the first", which would suggest cert1.crt should actually print as (contrary to what I said in "What did you expect to see?"):

<pre>
C=FI,O=bar,CN=foo
</pre>

_countryName_ is the last element and _commonName_ is the first. RFC 2253 shows examples where the countryName is last, but it does not show the corresponding ASN.1 structure, so that cannot be used as a reference. The ASN.1 sequence in RFC 2253 is probably in reverse to what this example shows.