-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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: gate marshaling of Policies on a GODEBUG [freeze exception] #64248
Comments
Also related: #63909, but for duplicates between Policies and PolicyIdentifiers. |
This can be solved by introducing a new field on the type Certificate struct {
PolicyIdentifiers []asn1.ObjectIdentifier
// UsePolicies is used by [CreateCertificate], is signals that
// [Certificate.Policies] field should be used over [Certificate.PolicyIdentifiers]
UsePolicies bool
Policies []OID
} This way we can also remove this check, introduced by CL 539297 Lines 1381 to 1384 in 5abae02
|
CC @golang/security Does anything need to be done here? Thanks. |
This is currently a blocker for the RC 1, scheduled in about two weeks. Can someone from @golang/security take a look. Thanks. |
We're thinking about it, but don't have a good solution as of yet. I'd rather not add a bool to use the new field, ideally we'd like to transition to using this new field and deprecating the old one. If we add a bool that indicates we should use the new field the migration plan becomes very complicated since we cannot reasonably flip the default while retaining any real meaning for the bool (essentially we just end up carrying a bool field with zero meaning that either has no impact regardless of value, or we invert the meaning, which is breaking for existing code that uses the bool). One solution would be to have an enum field that selects which policies field to use, and we can flip the default when nil when we deprecate PolicyIdentifiers. I cannot think of a good name for it though. Possibly we should just revert the marshaling behavior for Policies, only parsing into it for 1.22 (which fixes 90% of the problems people were running into with certificates in the wild being used for TLS containing these OIDs), and then address the marshaling behavior in 1.23. |
It sounds like this would also cause the same issue. |
Unlike a bool, the enum can have a meaningful zero value (of default to whatever the runtime decides when unpopulated), whereas the zero value of a bool is the negative case (i.e. don't use Policies, use PolicyIdentifiers). i.e.
|
Oh sorry, when you say the same problem, do you mean the same marshaling problem, as in it would result in not nil-ing the correct field? I think that is addressed by the deprecating. We'd likely want to deprecate the field in one release, and then change the default of the enum in the next release, giving people long enough to migrate safely. |
Exactly, but i would still consider this a compatibility breaking change. Also this issue does not only apply to nil-ing the field, but also filtering out some specific OIDs. When the default of |
Yup that is still an issue. I think any approach we take here (that migrates from one field to another) is going to exhibit a degree of this problem. @rsc suggested taking the GODEBUG approach, which I think is a viable solution. We'd gate which field is marshaled behind a GODEBUG, i.e. x509marshalpolicies, and would only use one of the two fields, depending on the value of the GODEBUG. We can then change the default value at some point in the future, and anything using the I'll prepare two changes, one which removes the dual marshaling behavior, and another which gates which field is marshaled using a GODEBUG. We can submit the first one to get back to the "safe" behavior before 1.22RC1, and if we get this through the proposal/release-exception review in time for the 1.22RC1, we can submit that. |
But once we make the Policies the default, then all code that sets the PolicyIndetifiers field would break (all CreateCertificate templates that do not come from a parsed der certificate). I don't think that this is a good direction I understand that this will be guarded by the go directive, but we are going to break the most common approach (template does not come from ParseCertificate) |
I'm not sure ParseCertificate -> CreateCertificate loops are a tenable backwards compatibility target. Anything new we start parsing from a certificate might end up serialized. This is arguably even documented in CreateCertificate (emphasis mine):
If we did want to mitigate this, one option would be the Extensions / ExtraExtensions pattern, where parsing populates the former and marshaling uses the latter, but that's already complex enough without the legacy Policies field interacting. I like the suggestion of making it a GODEBUG. I think that'd be the best solution. |
Re-purposing this issue to propose the GODEBUG behavior, hopefully we can push this through before 1.22RC1, otherwise we'll be stuck with this until 1.23. |
Change https://go.dev/cl/546916 mentions this issue: |
Change https://go.dev/cl/546915 mentions this issue: |
@rolandshoemaker Does this proposal also include adding a new field? #64248 (comment) Will the |
It won't add a new field, the GODEBUG alone chooses which field will be marshaled (either PolicyIdentifiers or Policies). The current implementation (https://go.dev/cl/546916) doesn't change the value based on the Go version, at some point in the future (maybe 1.23?) we will make that change so that we give people a while to understand how the new field works. |
Have we ever done something like that with GODEBUGs? Most GODEBUGs have negligible effect for users. This would make all code that uses |
GODEBUGs being used this way is a somewhat new idea, so there aren't a huge number of examples, but we discussed this idea in the proposal committee and considered it acceptable. There was at least on previous example of a type system change being made this way (I cannot for the life of me remember the exact issue though). I expect flipping the default value will require going through the proposal committee again when we decide to make that change though, so we'll have another change to decide if we actually find this acceptable at that point. |
Probably it was #63223. |
Don't marshal Policies field. Updates #64248 Change-Id: I7e6d8b9ff1b3698bb4f585fa82fc4050eff3ae4d Reviewed-on: https://go-review.googlesource.com/c/go/+/546915 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Damien Neil <[email protected]>
The GODEBUG for go/types's alias transition is #63223. |
We've already added the new Policies field here:
Code right now unmarshals into both PolicyIdentifiers and Policies, but we only Marshal from PolicyIdentifiers for backwards compatibility, because old code does not know to update Policies. The proposal is to add GODEBUG=x509marshalpolicies=0 (default) to mean the current behavior, and =1 means marshal the Policies field instead of PolicyIdentifiers. Go 1.22 would keep the =0 default, but then Go 1.23 would change to =1. At the point where Go 1.23 is released, Go 1.21 is unsupported, so it is OK to assume the existence of Policies in any code. This seems fine. |
@rsc There is no |
@mateusz834 Thanks, removed UsePolicies. I was referring only to Policies. |
Based on the discussion above, this proposal seems like a likely accept. Add GODEBUG=x509marshalpolicies=0 (default) to mean the current behavior (marshal PolicyIdentifiers not Policies), and =1 means marshal the Policies field instead of PolicyIdentifiers. Go 1.22 would keep the =0 default, but then Go 1.23 would change to =1. At the moment where Go 1.23 is released, Go 1.21 is unsupported, so it will be OK to assume the existence of Policies in any code that needs updating (specifically by clearing Policies when it clears PolicyIdentifiers). |
I wonder whether it would be better to change how When This way we don't break code that does something like: template := x509.Certificate{
// (....)
PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
}
x509.CreateCertificate(rand.Reader, &template, caCert, pub, caPriv) EDIT: This has a drawback that if someone uses a parsed certificate as a template and wants to remove all x509 Policy Identifiers, then it is required to clear both |
I think having the field be marshaled depending on certain constraints ends up being a lot harder to reason about than just explicitly picking one field or the other. RC1 happens on the 12th, so we need to either decide if this is acceptable now, or push any change until 1.23. That said, since this is a GODEBUG feature, if we see people significantly misusing this functionality we can decide not to flip the default value, and revisit the design of the feature with those concerns in mind. cc @golang/release can we get a freeze exception for this? Understandable if this is a bit too late though. https://go.dev/cl/546916 implements the functionality described in this comment. |
From discussion with @dmitshur and @cagedmantis, a freeze exception is accepted. |
No change in consensus, so accepted. 🎉 Add GODEBUG=x509marshalpolicies=0 (default) to mean the current behavior (marshal PolicyIdentifiers not Policies), and =1 means marshal the Policies field instead of PolicyIdentifiers. Go 1.22 would keep the =0 default, but then Go 1.23 would change to =1. At the moment where Go 1.23 is released, Go 1.21 is unsupported, so it will be OK to assume the existence of Policies in any code that needs updating (specifically by clearing Policies when it clears PolicyIdentifiers). |
Don't marshal Policies field. Updates golang#64248 Change-Id: I7e6d8b9ff1b3698bb4f585fa82fc4050eff3ae4d Reviewed-on: https://go-review.googlesource.com/c/go/+/546915 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Damien Neil <[email protected]>
Use a GODEBUG to choose which certificate policy field to use. If x509usepolicies=1 is set, use the Policies field, otherwise use the PolicyIdentifiers field. Fixes golang#64248 Change-Id: I3f0b56102e0bac4ebe800497717c61c58ef3f092 Reviewed-on: https://go-review.googlesource.com/c/go/+/546916 Reviewed-by: Damien Neil <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
Openned #67620, so that we don't forget about this. |
#60665 introduced a new OID type and a new field on the Certificate.
This change might cause a slight backwards compatibility breakage, it was not discussed there, so it might be worth discussing it here again.
Consider https://go.dev/play/p/Z92_1DOZJQi?v=gotip
This does not fail on go 1.21, but on gotip it fails.
I am not sure whether we should be concerned about this. Not sure whether (and why) someone might be using a parsed certificate as a template, but who knows.
CC @rolandshoemaker
The text was updated successfully, but these errors were encountered: