-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
crypto/x509: multi-value RDN sequence is not properly DER-ordered #24254
Comments
Note: in case of equal length a comparison by byte of the values would have to be done. Also note: the GNUTLS client is being fixed to account for this kind of broken client certs, |
Automatic merge from submit-queue (batch tested with PRs 18835, 18857, 18641, 18656, 18837). Reorder groups in cert Subjects This is to workaround Bug #18715, which is caused by Golang Crypto's x509 certificate generation ordering Subjects RDN incorrectly *and* GNUTLS' bug that "fixes" client certs on read with the correct encoding. To avoid issues until both are fixed we set the correct ordering ourself Fixes #18715 xref golang/go#24254 https://gitlab.com/gnutls/gnutls/issues/403#note_61687722
@FiloSottile any chance you'll look at this in the near future ? |
Aiming to look into this before the end of the week. |
thanks |
This is an encoding/asn1 issue, it should order all SET OFs before encoding them since that's what DER specifies. (Can't tell exactly how SETs should be ordered though.) I can fix this, but I'd like first confirmation from @agl that encoding/asn1 doesn't guarantee an |
Also, do we aim to error out on valid BER but invalid DER, or do we tolerate it? (In this case, we would have to error out parsing an unsorted SET OF to be strict.) |
The first problem is that there is no SET OF support in encoding/asn1 and that structure is defined to be a SEQUENCE instead of a SET OF, they are identical on the wire so this is not immediately evident and it generally won't show as an issue. You will need to tolerate unordered on receiving because otherwise you will break compatibility with your older self. The ordering is done on the encoded octet, so you need to encode the set and then order its members. See the ITU-T spec and the workaround we have in Openshift (see links above) to get it right for now. |
encoding/asn1 does support SET and SET OF via a struct tag or when the type name ends in SET (see the Agreed that we'll have to keep tolerating this here, but I was curious what the default stance on DER parsing is in encoding/asn1. |
@agl confirmed we have no such invariant, so let's fix this in Marshal by properly sorting SET OF entries when serializing. Still have to figure out if SETs also have a sorting requirement (I think they don't since they can be heterogeneous?). |
The ITU-T documents says only SET OF is ordered, afaict. |
Not ordered the same as a SET OF, but SET does have an ordering specified in X.690, Section 10.3, which applies to DER (which then references X.680):
Section 8.6 of X.680 states:
|
This is a blocking concern to us. We're about to develop a document push protocol on top of AMQP 1.0 and are considering Go as the language for the software. Seeing this however, it would be unsafe to use Go with security as software might break on it. The point is obviously just a minute encoding detail, but since it breaks certificate signatures on software that adheres to the specifications, we may have to avoid Go until it is fixed. What a pitty. Is there a due date when this will be certainly fixed? I doubt you could promise anything of that kind, right? Until then, is there a workaround, in the form of a correctly working certificate implementation that can be used with Go without risking incompatibility with other software? |
Sorry for letting this slip. It will definitely be fixed in Go 1.14, but it's not a small enough change to push during the Go 1.13 code freeze. FWIW, the X.509 ecosystem is full of non-DER encodings, so virtually every verifier accepts mild standard deviations like this. Indeed, Go is used in a myriad of environments and incompatibility was only ever reported against GnuTLS, which has now been fixed. Note that this only applies to pkix.Name fields of length higher than 1, which are fairly uncommon. As for a workaround, you can simply sort the pkix.Name fields correctly in your application. @simo5 I am not convinced by your sorting implementation. That code does simply a length sort, when instead things should be sorted lexicographically, simply sorting shorter values before longer values that start with the shorter values.
So for example
or am I misunderstanding the specification? |
@FiloSottile you are probably misunderstanding, it was quite a while ago so I forgot details, but I had to go through the ITU documents and read extra-carefully, and when I was done I was very surprised by the outcome which was completely unintuitive. |
I think one of the key details was that ordering was done after encoding, see the first comment here which explains exactly what paragraphs to look at and the side effects of the scheme (length becomes determinant). |
I re-read all relevant parts I can find, and I still don't see how length would become first criteria (exactly because it's first encoded with padding, then sorted). Moreover, notice the ordering from the original issue is
|
Big IIRC. |
@FiloSottile given this comment:
I would assume this remains true for the 1.14 code freeze. Should this be pushed to 1.15 and marked |
@simo5 is right, the sorted value includes the length prefix. I verified by running
which sorted them as Changing asn1.Unmarshal to be stricter is too big a change to do in Go 1.14, and it's even unclear if we should be strict about this, but it should be pretty simple to make encoding do the right thing, and we shouldn't ever be off-DER in what we generate. I'll put together a CL. |
I tried to put together a change, and due to how the encoder works, it's not actually trivial. This was my fault for not doing it earlier, sorry. Since there is a workaround (sorting the sequence in your application code), let's push to Go 1.15. |
This MUST then be documented quite vigorously.
IMHO this is not a reasonable workaround. You are passing complexity outside the API that is supposed to conceal it, for mere reasons of implementation effort. Applications will not (all) do this and this delaying approach will only make the stampede of Go's incompatibility continue. Please put in the effort to be standards compliant, like the others (should) have.
|
To be clear, I'm not saying we shouldn't fix this. Of course we shouldn't generate non-DER. I'm saying I failed to do so before the tree froze, and the change is not small enough to merge after the freeze. If you want to make sure this is fixed in Go 1.15, you can also make a CL. (By the way, this issue is as old as encoding/asn1, but was reported only last year. There isn't a strong argument for its urgency.) |
This issue is currently labeled as early-in-cycle for Go 1.15. That time is now, so friendly ping. If it no longer needs to be done early in cycle, that label can be removed. |
This task has been here for a long time, and all this time Go has been
incompatible and causing problems for other toolkits. The sooner the
better, really.
|
Per X690 Section 11.6 sort the order of SET of components when generating DER. This CL makes no changes to Unmarshal, meaning unordered components will still be accepted, and won't be re-ordered during parsing. In order to sort the components a new encoder, setEncoder, which is similar to multiEncoder is added. The functional difference is that setEncoder encodes each component to a [][]byte, sorts the slice using a sort.Sort interface, and then writes it out to the destination slice. The ordering matches the output of OpenSSL. Fixes golang#24254 Change-Id: Iff4560f0b8c2dce5aae616ba30226f39c10b972e
Change https://golang.org/cl/226984 mentions this issue: |
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
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:
The correctly ordered encoding would look like:
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.
The text was updated successfully, but these errors were encountered: