[HN Gopher] Fooling Go's X.509 Certificate Verification
       ___________________________________________________________________
        
       Fooling Go's X.509 Certificate Verification
        
       Author : hasheddan
       Score  : 50 points
       Date   : 2026-06-06 13:52 UTC (2 days ago)
        
 (HTM) web link (danielmangum.com)
 (TXT) w3m dump (danielmangum.com)
        
       | fsmv wrote:
       | I don't think that's an ongoing debate looks to me that it ended
       | in 2019
       | https://github.com/golang/go/issues/31440#issuecomment-53724...
        
       | pseudohadamard wrote:
       | This is what happens when kids today are unaware of history. This
       | was a known problem 30+ years ago, and the Go kids have just
       | rediscovered it for themselves. The most extreme case of this
       | madness was imagining you could re-encode certificates into a DER
       | blob from their stored components and the signature would still
       | validate, something that OER (from memory) guys are now trying to
       | do.
       | 
       | The rules for DNs are "there is only one encoding rule and that
       | is memcpy(); there is only one matching rule and that is
       | memcmp()". Given that Go has fallen into the decades-old trap of
       | trying to re-encode strings, it's bound to be vulnerable to any
       | number of other issues like evading excludedSubtrees through
       | string-encoding tricks.
        
         | ahmedtd wrote:
         | From the article, it doesn't seem like Go is trying to re-
         | encode strings? Go is saying (correctly, IMO) that a UTF8String
         | field in the Issuer is _not_ the same as a PrintableString
         | field in the Subject.
        
           | pseudohadamard wrote:
           | Ah, you're right, I was a bit confused by the bouncing back
           | and forth between Go and OpenSSL and the title, "Fooling Go's
           | X.509" when in fact on re-read Go appears to be doing the
           | right thing and using a strict compare while OpenSSL uses the
           | open-to-manipulation compare.
        
             | akerl_ wrote:
             | Maybe this should be a lesson about the dangers of rolling
             | in hot with a bunch of insults?
        
         | jchw wrote:
         | Between this and the IPv6 zone identifier issue, it feels like
         | there's a bit of a trend of commenters more or less assuming Go
         | is doing the wrong thing when it's actually following the
         | standards/best practices _more_ correctly than average. I
         | wonder where this reputation came from.
        
           | fragmede wrote:
           | Most people accessing a site are likely not using Golang and
           | are using Chrome. Thus Chrome is assumed right and Go is the
           | one that's the outlier.
        
             | jchw wrote:
             | That's a different point, this particular thread is
             | actually about a behavior that Chrome/OpenSSL/etc. have
             | that is actually somewhat _undesirable_ due to being
             | complex and error prone.
             | 
             | Simply following Chrome/OpenSSL/etc. yields the best
             | compatibility, but the Go behavior is much simpler in this
             | very security critical path, and I'm not sure if it really
             | occurs on the web. It seems most people are reporting it
             | for other uses of X.509 like TPM. You can certainly see the
             | argument in favor of Go's _vastly_ simpler approach.
             | 
             | Go has a lot of trade-offs like this. If you can't decode
             | from or encode into UTF-8 a given filename, Go's high level
             | I/O APIs can't deal with it - depending on your exact point
             | of view, the kinds of software you write and certainly some
             | level of taste, you may see this as horrible, or you may
             | see it as a totally reasonable trade-off. Some programs can
             | go ahead and say "Sorry, we only support UTF-8 filenames"
             | and some really can't.
             | 
             | But when being rational and reasoned it's really
             | challenging to make the argument that Go's choices are bad
             | due to inexperience from the language designers or standard
             | library authors or general poor attention to detail.
             | Calling the developers "Go kids" is already amusing
             | considering it is very famously a project originally
             | created by Rob Pike, Ken Thompson and Robert Griesemer -
             | not foolish young developers who are likely to repeat
             | mistakes of the past by way of ignorance. Of course, that
             | doesn't mean say, the TLS stack, deserves to carry some
             | special weight just because the language was designed by
             | computer science stalwarts, but I've dug into the Go TLS
             | stack a fair bit in my leisure and to me personally it
             | definitely does not feel like the work of people who are
             | ignorant or foolish.
             | 
             | I may be over-indexing on two recent comments here, but it
             | does sort of feel like there's an undercurrent of this, and
             | it bums me out because I particularly like Go for the exact
             | opposite reason, I really think a lot of the tradeoffs,
             | love them or hate them, are very well thought out.
             | 
             | edit: For posterity sake, it is worth noting that it was
             | wrong for me to say "Chrome/OpenSSL/etc." as Chrome
             | actually has a similar behavior to Go here.
        
         | gowld wrote:
         | The Go "kids" are famous for, among other things, being
         | industry leaders 30 years ago.
        
           | sidewndr46 wrote:
           | Those young whipper snappers with their lifetime of
           | experience!
        
       | agwa wrote:
       | The blog post provides a certificate chain that validates in
       | OpenSSL but not in Go.
       | 
       | The reason it doesn't validate in Go is that the Subject field in
       | the CA certificate uses a different string encoding than the
       | Issuer field in the leaf certificate, so the fields are not byte-
       | for-byte equal.
       | 
       | Go requires the Issuer and Subject to be byte-for-byte equal.
       | This was permitted by older specs, but RFC 5280 changed the rules
       | to require the use of RFC 4518 (LDAP stringprep) for comparing
       | strings. This turned a simple memcmp into a complicated algorithm
       | that requires implementing Unicode normalization, for virtually
       | zero benefit. That's the last thing you want in your security-
       | critical certificate verifier, so Go quite sensibly chose to
       | follow the older specs in this regard. The CA/Browser Forum's
       | Baseline Requirements also mandate byte-for-byte equality, so
       | Go's behavior won't cause publicly-trusted certificates to be
       | incorrectly rejected.
       | 
       | Note that LDAP stringprep is so complicated that OpenSSL doesn't
       | even try to implement it properly and uses an approximation
       | instead. So you would also be able to "fool" OpenSSL into
       | rejecting certificate chains that RFC 5280 says are valid.
       | 
       | The blog post says that this is an "ongoing debate" in the Go
       | project but I don't think that's accurate. I'd be shocked if they
       | ever changed this behavior, given that crypto/x509 targets
       | publicly-trusted certificates and the current behavior is so much
       | simpler.
        
         | tptacek wrote:
         | I feel like basically all the X509 threads on HN should
         | basically be locked until after you write your first comment on
         | them.
        
           | tialaramex wrote:
           | Yeah, no, Andrew has insightful things to say, but he's
           | hardly indispensable.
        
           | agwa wrote:
           | Aw, thanks :-)
        
         | jiggawatts wrote:
         | Something I noticed decades ago is that some small, innocuous
         | features can drag with them giant ecosystems of software.
         | 
         | I first noticed this when I had to implement a C++ client for a
         | custom RPC protocol and the dev "on the other end of the wire"
         | added one new "convenience" in the data types supported...
         | which would have required me to include the entire Java runtime
         | in my client!
         | 
         | All protocol specs are vulnerable to this effect where it's all
         | too easy to require clients to include half a dozen different
         | regex engines, three byte code virtual machines, and most of
         | LLVM for good measure.
        
           | sidewndr46 wrote:
           | any specification eventually grows to encompass all features
           | of its original implementation language.
        
             | PunchyHamster wrote:
             | We should require 2 different implementation, each in
             | different enough (so no C/C++ pair) language with each
             | specification.
             | 
             | Because that way we not only get rid of language's smell in
             | how stuff is implemented, but also the act of implementing
             | the spec will quickly show any cases where it looked simple
             | in spec but turns out to be mess implementation wise.
             | 
             | Too much work ? Well, make your spec be tighter and simpler
             | before you burden the rest of programming community with
             | implementing it
        
       | briansmith wrote:
       | This is uninteresting. CAs are well aware that they have to
       | encode the subject DN and issuer DN identically to maximize
       | interoperability. There are several implementations that require
       | that.
       | 
       | If we were to make a new version of the spec for X.509
       | certificates, I would hope that we would eliminate all the non-
       | UTF8 encodings so that this would be a non-issue.
        
         | bigfatkitten wrote:
         | Even outside of the web PKI, the requirement for identical
         | encoding is also often found in certificate policies used
         | within closed communities.
        
         | NooneAtAll3 wrote:
         | if 2 fields are identical, why aren't they 1 field?
        
           | woodruffw wrote:
           | They're two different fields on different certificates. The
           | issuer on the child needs to match the subject on the parent;
           | every certificate has its own subject and issuer.
        
         | imperfectfourth wrote:
         | uninteresting to you, i learned something new.
        
         | dsl wrote:
         | That is like saying you can't get a virus on your computer
         | because Facebook doesn't allow viruses to be posted to the
         | internet.
         | 
         | Differential parsing is a whole class of security bugs and they
         | matter a lot. Take a look at HTTP Request Smuggling for
         | examples.
         | 
         | Also, I am pretty sure there are more non-web x509 certificates
         | out there than all the "browser trusted CAs" combined have
         | signed. :)
        
           | woodruffw wrote:
           | To be clear, the differential here occurs because OpenSSL
           | does the wrong thing. Go is correct to fail closed here, and
           | it's very hard to imagine a setting in which Go failing
           | closed is a relevant security differential.
        
       | entrope wrote:
       | Perhaps I overlooked something, but which part of this involved
       | "fooling Go"? I would usually not call it "fooling" something to
       | trigger a not-strictly-required rejection of a dubious trait,
       | especially when best practice says to avoid that trait.
        
       | pqpdf wrote:
       | This is a great example of how format complexity creates security
       | problems.
       | 
       | The same thing shows up in PDFs: two tools can read the same file
       | and disagree about what's actually in it because they interpret
       | the structure differently.
       | 
       | X.509, PDFs, Office docs. Whenever multiple implementations are
       | making judgment calls on the same bytes, those edge cases become
       | very interesting from a security perspective.
        
       | woodruffw wrote:
       | The title of this post is wildly misleading: Go's behavior is
       | correct here. But even if it wasn't, failing closed isn't
       | generally a way one fools a X.509 path validator.
       | 
       | Source: having had the displeasure of implementing an RFC 5280
       | and CABF-conforming path validator.
        
       ___________________________________________________________________
       (page generated 2026-06-09 04:01 UTC)