-
Notifications
You must be signed in to change notification settings - Fork 18k
encoding/asn1: support ObjectIdentifier sub-oid values greater than 2^31-1 #39795
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
Conversation
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed (or fixed any issues), please reply here with What to do if you already signed the CLAIndividual signers
Corporate signers
ℹ️ Googlers: Go here for more info. |
@googlebot I signed it! |
CLAs look good, thanks! ℹ️ Googlers: Go here for more info. |
This PR (HEAD: 35628c4) has been imported to Gerrit for code review. Please visit https://go-review.googlesource.com/c/go/+/240006 to see it. Tip: You can toggle comments from me using the |
Message from Gobot Gobot: Patch Set 1: Congratulations on opening your first change. Thank you for your contribution! Next steps: Most changes in the Go project go through a few rounds of revision. This can be During May-July and Nov-Jan the Go project is in a code freeze, during which Please don’t reply on this GitHub thread. Visit golang.org/cl/240006. |
This PR (HEAD: 2663d81) has been imported to Gerrit for code review. Please visit https://go-review.googlesource.com/c/go/+/240006 to see it. Tip: You can toggle comments from me using the |
This PR (HEAD: 5f541c3) has been imported to Gerrit for code review. Please visit https://go-review.googlesource.com/c/go/+/240006 to see it. Tip: You can toggle comments from me using the |
Message from Go Bot: Patch Set 1: Congratulations on opening your first change. Thank you for your contribution! Next steps: Most changes in the Go project go through a few rounds of revision. This can be During May-July and Nov-Jan the Go project is in a code freeze, during which Please don’t reply on this GitHub thread. Visit golang.org/cl/240006. |
I think it would be better (although I don't know if it can easily be changed; it is not a programming language that I use) to store a OID as the string of bytes that it is encoded as, and use that for comparison. Decoding it into the sequence of numbers is only necessary for display or conversion, not for comparison (if you need to compare a dotted decimal OID with a binary OID, it is better to encode the dotted decimal OID to binary instead of the other way around). Another alternative (which might avoid needing to change the types) might be to use negative numbers to represent OIDs that cannot be represented with the existing implementation; one possible way to do this would be, if a part of the OID cannot be decoded, use the bitwise complement of each individual byte for the rest of the OID. This has the disavantage that OIDs that can be decoded in the usual way have an alternate representation which encodes into the same thing, and this might be undesirable. |
This PR adds support for ASN.1 object identifiers where at least one sub-oid has a value greater than 2^31-1. As per ASN.1 specification, each sub-oid is an ASN.1 INTEGER, which can be of arbitrary size. For example, the value of a sub-oid could be
2 << 80
. In practice, scenarios with large sub-oids are rare but they do exist.One problem is that historically, the
ObjectIdentifier
type has been defined as[]int
; this means the max value of sub-oids is math.MaxInt32. The problem leaks in multiple go packages, such ascrypto.x509
. This is a problem because some real-world X.509 certificates have sub-oids values greater than 2^31.This is an initial proposal using option 3 below. I should add more unit tests, run some benchmarks and optimize code, but before that it would great to know if the approach is going in the right direction.
Besides fixing the ASN.1 compliance issue for the ASN.1 unmarshaler, another issue is how to parse X.509 certificates when policy identifiers have sub-oids larger than math.MaxInt32. The fix in the x.509 package is dependent on the asn1 fix. I am including the x509 fix, let me know if it makes more sense to have two separate PRs.
Option 1
Redefine
asn1.ObjectIdentifier
as a[]int64
or even[]*big.Int
. This is probably a non-starter because a lot of software has been built with this assumption. It's not possible to change the type to[]int64
or[]*big.Int
without breaking existing software.or
Option 2
Add two new types:
If all sub-oids are less than math.MaxInt32, then the return type could still be
ObjectIdentifier
to retain backward compatibility. If at least one sub-oid is more than math.MaxInt32, then the return value is ObjectIdentifierInt64. If at least one sub-oid is more than math.MaxInt64, then the return value is ObjectIdentifierBigInt.One problem with this approach is it's cumbersome for consumers (such as
crypto.x509
) to deal with three different types.Option 3
Add a new type that can take int, int64 or *big.Int as sub-oid values:
In particular, this could be used in the
x509
package to support certificates that have large sub-oid values. The existingPolicyIdentifiers
field cannot be removed without breaking the backward compatibility. It's doable but somewhat cumbersome to have two possible PolicyIdentifiers fields.Option 4
Use go generics:
Developers would be able to instantiate object identifiers with different sub-types:
x509.Certificate
could also be a generic type. Developers would have the choice of supporting X.509 certificates with policy identifiers that have large sub-oids:However, this generic approach does not work for existing code because that would result in compilation failure. For example, the code below causes "cannot use generic type ObjectIdentifier(type T SignedInteger) without instantiation"
To get around this problem, I was wondering if a default instantiation type has been considered when in the go generic specification, something like below. This would make it possible to retrofit existing code while providing extended use cases.
Or if somehow it were possible to have one generic version and one non-generic version:
One little annoyance is that even with generics, it's not possible to use common arithmetic operators (+, *, /) that work across int, int64 and *big.Int.
But even if there is a way to use generics without breaking code, it would seem odd to be required to expose the sub-oid generic type to all types (e.g.
x509.Certificate
) that use ObjectIdentifier.Current use of asn1.ObjectIdentifier type
Below are the publicly exposed asn1.ObjectIdentifier fields in the golang/go repo:
For #38737