What version of Go are you using (go version)?

$ go version
go version go1.12.6 linux/amd64

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/jrittner/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/jrittner/go-workspace"
GOPROXY=""
GORACE=""
GOROOT="/home/jrittner/go"
GOTMPDIR=""
GOTOOLDIR="/home/jrittner/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
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 -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build691331496=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I created a pkix.Name containing a custom ExtraName, and converted it to a string.

https://play.golang.org/p/1hyqwP_RTBs

What did you expect to see?

1.2.3.4=sample,CN=foobar

What did you see instead?

1.2.3.4=#130673616d706c65,CN=foobar

This is because Go always hex-encodes the asn.1 encoding of the value, even though RFC 2253 states that the value is supposed to just be used as its own string encoding. https://tools.ietf.org/html/rfc2253#section-2.4

Otherwise, if the AttributeValue is of a type which has a string representation, the value is converted first to a UTF-8 string according to its syntax specification (see for example section 6 of [4]).

Note that OpenSSL gives the expected output when viewing a certificate or CSR with a custom name.

Comment From: dmitshur

/cc @FiloSottile

Comment From: FiloSottile

I read the previous spec paragraph as saying that this is the correct form when the type is unknown and expressed as a dotted decimal.

   If the AttributeValue is of a type which does not have a string
   representation defined for it, then it is simply encoded as an
   octothorpe character ('#' ASCII 35) followed by the hexadecimal
   representation of each of the bytes of the BER encoding of the X.500
   AttributeValue.  This form SHOULD be used if the AttributeType is of
   the dotted-decimal form.

There is even an example for it in Section 5.

   1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB

Can you provide an example certificate?

Comment From: rittneje

Here is a sample CSR:

-----BEGIN CERTIFICATE REQUEST-----
MIIBYTCBywIBADAiMQ8wDQYDVQQDEwZmb29iYXIxDzANBgMqAwQTBnNhbXBsZTCB
nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtDs1ygEixq27qFrGGh4pXIbg5Q6U
kzNRLRVo4STAkYl6looxjPf7u77/6TwYAVnu6zT6VULf+lyk4g7l2AwnxfQ+a6V/
KBqvnMhNI8NbPfouqnqvJekTNUGhnAwfCgthZXuYywlJASsBKcudHwkk+MNJWBUQ
kCU1JyXsFyHdr1sCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4GBAHF/6Hin8itNP/Uv
JW3tvUCkxaFXmL2UjA6Ed+UM4AXnPqSpGXx3hgccOcRJD63uQnl/yUbcpo7xIdFk
i/m6v0HX/8aRHBFM6o8zO8ellcidP0a4K5TzBhbJv6Dpy4HJOPkHZ9Mzi6Dprwj2
0gX/y4r5wM5d0/oOXPHS5N1DgEiK
-----END CERTIFICATE REQUEST-----

OpenSSL shows the custom distinguished name as a string:

$ openssl req -in sample.csr -subject -noout
subject=/CN=foobar/1.2.3.4=sample

The OpenSSL output is preferable over the current Go output because it is human readable.

Comment From: rittneje

@FiloSottile Wanted to follow up on this.

The example you copied is specifically for an "octet string", hence the 04 prefix. However, the custom DN in my example is actually a "printable string", hence the 13 prefix. It should thus be used as its own string representation

Comment From: rittneje

ping @FiloSottile

Comment From: rittneje

@FiloSottile Is this something you will consider fixing, given what I mentioned?

Comment From: rittneje

@FiloSottile is there someone else I should CC?

Comment From: bjanders

I agree with @rittneje . Here is a simple example. Create a certificate with openssl:

openssl req -new -x509 -subj '/UID=foobar/' -nodes -outform DER -out cert.crt

The ASN.1 structure of the Subject DN in cert.crt:

SEQUENCE (1 elem)
      SET (1 elem)
        SEQUENCE (2 elem)
          OBJECT IDENTIFIER 0.9.2342.19200300.100.1.1 userID
          UTF8String foobar

The type is UTF8String (not for example an octect string). Requoting @rittneje from RFC 2253:

Otherwise, if the AttributeValue is of a type which has a string representation, the value is converted first to a UTF-8 string according to its syntax specification (see for example section 6 of [4]).

UTF8String has a string representation and does not even need conversion, so it should be printed as:

0.9.2342.19200300.100.1.1=foobar

Not like go1.18.1 does:

0.9.2342.19200300.100.1.1=#1306666f6f626172

In https://github.com/golang/go/issues/39924 @FiloSottile says:

Unfortunately, we are bound to the RFC 2253 format by the docs and that format requires any non-standard attribute to be printed as a dotted OID and hex-encoded value.

But this is not what RFC 2253 says. RFC 2253 does not mention "non-standard attributes"; it says "does not have a string representation" which is a different thing:

If the AttributeValue is of a type which does not have a string representation defined for it, then it is simply encoded as an octothorpe character ('#' ASCII 35) followed by the hexadecimal representation

Comment From: rittneje

cc @rolandshoemaker

Comment From: rittneje

ping @FiloSottile

Comment From: bjanders

ping @FiloSottile

I don't think @FiloSottile is working on this project anymore. I guess the fastest way to fix this is to fix it ourselves and request a pull.

Comment From: FiloSottile

Thanks @bjanders for doing the spec analysis in https://github.com/golang/go/issues/33093#issuecomment-1105208529, I think you're right and I was interpreting it wrong. We can probably get this into Go 1.21.

Comment From: gopherbot

Change https://go.dev/cl/549075 mentions this issue: crypto/x509/pkix: ensure Name.String correctly prints ASN1 printable strings

Comment From: odeke-em

Thank you for the discourse @rittneje @FiloSottile @bjanders, I am working on triaging plus fixing issues and I just stumbled upon this issue and it nerd snipped me and I've gone through parts of the specification and to accomplish a probable working fix for this, I examined expectations for ASN1 printable strings per the quoted RFCs and I've mailed out CL https://go-review.googlesource.com/c/go/+/549075 which can be a start for the fix but otherwise moved to the Go1.23 milestone.

Comment From: odeke-em

Kind ping @rolandshoemaker @FiloSottile and others, I did mail a fix for this issue in CL https://go-review.googlesource.com/c/go/+/549075