Skip to content
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/tls: implement RFC7627 #43922

Closed
brawer opened this issue Jan 26, 2021 · 40 comments
Closed

crypto/tls: implement RFC7627 #43922

brawer opened this issue Jan 26, 2021 · 40 comments
Assignees
Labels
Proposal Proposal-Accepted Proposal-Crypto Proposal related to crypto packages or other security issues
Milestone

Comments

@brawer
Copy link

brawer commented Jan 26, 2021

I’m not a crypto expert, but couldn’t Go’s TLS stack un-deprecate ConnectionState.TLSUnique by implementing RFC7627? In terms of API, when a TLS connection doesn’t use RFC7627, the TLSUnique field might be cleared. See also #18346.

@gopherbot gopherbot added this to the Proposal milestone Jan 26, 2021
@seankhliao seankhliao added the Proposal-Crypto Proposal related to crypto packages or other security issues label Jan 26, 2021
@ianlancetaylor ianlancetaylor added this to Incoming in Proposals (old) Feb 17, 2021
@ianlancetaylor
Copy link
Contributor

CC @FiloSottile

@bskidmore
Copy link

Is there an update on this potential issue?

@bskidmore
Copy link

bskidmore commented Oct 21, 2021

Is there an update on this issue?

@rsc
Copy link
Contributor

rsc commented Oct 27, 2021

/cc @FiloSottile and also @agl (because he co-authored the RFC)

@rsc
Copy link
Contributor

rsc commented Oct 27, 2021

This proposal has been added to the active column of the proposals project
and will now be reviewed at the weekly proposal review meetings.
— rsc for the proposal review group

@rsc rsc moved this from Incoming to Active in Proposals (old) Oct 27, 2021
@FiloSottile
Copy link
Contributor

I am not sure what the deployment status of RFC 7627 is. I will look into it and try to figure out if it's worth the complexity.

ConnectionState.TLSUnique is unlikely to become useful though unless we can reject non-RFC 7627 connections, because clearing or setting it to nil would be a backwards compatibility breakage. I also don't want to expose something wonky and unsafe like a RFC7627InUse or TLSUniqueIsSafe bool.

What do you need TLSUnique for that is not served by ConnectionState.ExportKeyingMaterial by the way? The latter is available in TLS 1.3 and it returns an error, so if we need to we can make it degrade more gracefully.

@brawer
Copy link
Author

brawer commented Oct 28, 2021

The motivation for filling this proposal was to make it possible to support SCRAM with channel binding. SCRAM is an authentication method that avoids the transmission and storage of passwords, which is quite interesting from a security perspective. SCRAM is available (at least in the specification) as an authentication method for all SASL-based application protocols, such as SMTP, IMAP, POP, LDAP, and others. For XMPP, use of SCRAM is mandatory; and there's also some minor other, non-SASL protocols with SCRAM authentication. RFC7677 defines two authentication methods for SASL, SCRAM-SHA256-PLUS and SCRAM-SHA256 (with and without channel binding), and similar specs exist for other hash functions. Unfortunately, without a channel binding mechanism, SCRAM is vulnerable to meddler-in-the-middle attacks. Therefore, only the SCRAM-*-PLUS authentication schemes (ie. with channel binding) are actually secure.

On TLS 1.2, channel binding is done with the value of TLSUnique, whose security depends on RFC7627 being used —;hence this proposal here. As of October 2021, Channel bindings for TLS 1.3 are still going through the IETF standardization process, so TLS 1.3 is not yet an option for SCRAM-*-PLUS.

If implementing RFC7627 in TLS 1.2 turns out to be too much work (too risky, too painful to be bothered, whatever), Go could perhaps also just do nothing: Just wait until TLS 1.3 has a channel binding mechanism, and then expose the needed parts from the Go crypto stack. (Admittedly, when filling this proposal here, I didn't expect it would sit around for such a long time; meanwhile, requiring TLS 1.3 might have become more realistic. But of course we're all busy, no offense.) Looking at the TLS 1.3 channel binding draft, it appears that the existing implementation of the Go crypto stack might be sufficient to support SCRAM-*-PLUS on TLS 1.3 unless IETF makes substantial changes to the draft RFC, but perhaps you could have a look to confirm. Personally, I'd still find it nice if TLS 1.2 was supportable for a while (which would need RFC 7627 for secure channel binding), but I can certainly see the cost in complexity and pain.

@rsc
Copy link
Contributor

rsc commented Dec 1, 2021

/cc @FiloSottile

@rsc
Copy link
Contributor

rsc commented Jan 5, 2022

cc @golang/security

@ksridhar57
Copy link

ksridhar57 commented Jan 7, 2022

Hi,

I was trying to test the KDF functions for FIPS certification and realised that go's (version 1.12.1) crypto/tls does not implement RFC 7627 requirements. What is the recommended approach here? Is this specification now implemented in later versions of go releases?
I'm not too familiar with the specifications and I'm arriving at this understanding based on the crypto source code I happened to go through at a high level. Would appreciate some guidance here.

Thanks!

@Neustradamus
Copy link

About SCRAM, it will be nice to support it.
TLS 1.2 is always used (-PLUS variants: TLS Binding).

@ksridhar57
Copy link

Do we have a solution where we could patch the TLS implementation in Go to support RFC 7627? As I understand this specification is now becoming mandatory for FIPS 140-3 certifications. Any advice is appreciated.

@FiloSottile FiloSottile self-assigned this Mar 2, 2022
@rsc
Copy link
Contributor

rsc commented Mar 16, 2022

@FiloSottile, you self-assigned this. What is the status of this? Do you think we should accept the proposal?

@FiloSottile
Copy link
Contributor

@FiloSottile, you self-assigned this. What is the status of this? Do you think we should accept the proposal?

I self-assigned it to look into it, which I haven't done properly yet.

@rsc
Copy link
Contributor

rsc commented May 4, 2022

Putting on hold until security team has more bandwidth to look at this.

@rsc
Copy link
Contributor

rsc commented May 4, 2022

Placed on hold.
— rsc for the proposal review group

@rsc rsc moved this from Active to Hold in Proposals (old) May 4, 2022
@krissridhar
Copy link

Hi,

Resurrecting the earlier query on RFC 7627 does Go library 1.18 or later support the use of Extended Master Secret extensions in TLS? Any guidance here is much appreciated!

Thanks

@krissridhar
Copy link

Hi @https://github.com/rsc, is the proposal to implement RFC 7627 still on hold? Any advise on how this requirement is going to be addressed in Go?

@neverpanic
Copy link

Just to re-iterate on this, and why this might be important: Submissions to NIST for FIPS-certification after May 16th, 2023 must enforce the use of the extended master secret in TLS 1.2. This means that systems in FIPS mode will no longer be able to talk to Go TLS servers unless they offer TLS 1.3 (which admittedly they can since it's supported in anything >= Go 1.13).

See the FIPS 140-3 Implementation Guidance, section D.Q "Transition of the TLS 1.2 KDF to Support the Extended Master Secret".

@FiloSottile
Copy link
Contributor

FiloSottile commented Apr 27, 2023

Ok, to recap, there are two channel binding mechanisms we care about here.

  1. tls-unique is defined in RFC 5929 and is basically just the Finished hash. tls-unique is exposed as ConnectionState.TLSUnique and "will be nil for TLS 1.3 connections and for all resumed connections".
  2. Exported Key Material is defined in RFC 5705 and is basically a hash of master secret and the Randoms. EKM is exposed as ConnectionState.ExportKeyingMaterial and returns an error if renegotiation (not resumption) is enabled.

RFC 9266 introduced tls-exporter which is based on EKM, and actually recommended replacing tls-unique with it.

Without RFC 7627, tls-unique can be forced not to be unique only for resumed connections, while EKM can be forced not to be unique for any connections. In that sense, it looks like we deprecated the wrong thing: TLSUnique is nil when resuming, and is always unique otherwise; ExportKeyingMaterial (and hence the new tls-exporter) instead might not be unique even in initial handshakes.

(An aside about renegotiation. Renegotiation is bad. We refuse to do it as a server. We disable it by default as a client. When we do it, we require certificates not to change, so I think our renegotiation implementation is actually unaffected by this. Still I guess we can refuse to renegotiate resumed connections if extended_master_secret is not in use. But also I don't care about renegotiation.)

Concretely, I propose for Go 1.21 we:

  1. Implement the extended_master_secret extension both on the client and on the server, and always enable it.
  2. Add a bool to sessionState to carry over whether e_m_s was used in the original session.
    • Note that this will make tickets not interoperate across Go 1.20 and Go 1.21 (falling back cleanly to full handshakes). This resolves a concern I had with the MUST in RFC 7627 to break if the original connection supported e_m_s and the resumed one doesn't. That felt too harsh if the cause was progressive rollout, but with this change resumption will just be skipped in that scenario.
  3. Implement the recommendation in Section 5.4 of RFC 7627 to disable tls-unique for resumed connections without e_m_s. This actually means enabling TLSUnique for resumed connections with e_m_s, since it's currently disabled for all resumed connections. We can also undeprecate TLSUnique.
  4. Implement the recommendation in Section 5.4 of RFC 7627 to disable EKM for all connections without e_m_s by returning an error from ExportKeyingMaterial. This is indirectly also recommended in Section 2 of RFC 9266 (which says tls-exporter is not defined for connections without e_m_s, and the only way to reflect that is to refuse EKM).

Note that (4) is a breaking change. In particular, EKM will not be available on the Go 1.21 side of a connection between Go 1.20 and Go 1.21. We should either provide a GODEBUG for this, or wait until Go 1.22 to enforce it, since by then all supported versions of Go will support e_m_s. Opinions?

@FiloSottile
Copy link
Contributor

Oh, and about FIPS compliance, thank you @neverpanic for referencing the IG. The requirement is only for new validations, so it doesn't affect what we need select for now (even in crypto/tls/fipsonly mode), but you're correct that modules tested after May 16, 2023 won't be able to communicate with Go 1.20. I think that's going to be ok: modules tested in May 2023 are unlikely to get deployed before August 2023, when Go 1.21 will be released.

@rsc rsc removed the Proposal-Hold label May 10, 2023
@rsc
Copy link
Contributor

rsc commented May 17, 2023

We should definitely add a GODEBUG if this is for Go 1.21. Even for Go 1.22 it should probably be a GODEBUG.

Is the goal to get this into Go 1.21?

Have all remaining concerns about this proposal been addressed?

@FiloSottile
Copy link
Contributor

Let's leave (4) for Go 1.22, we don't need to do that part to be compatible with new FIPS modules.

I'll mail a CL for (1)-(3) today for Go 1.21.

@gopherbot
Copy link

Change https://go.dev/cl/497376 mentions this issue: crypto/tls: implement Extended Master Secret

@rsc
Copy link
Contributor

rsc commented May 24, 2023

Based on the discussion above, this proposal seems like a likely accept.
— rsc for the proposal review group

@Neustradamus
Copy link

@FiloSottile: Thanks for your proposal, I hope the support of tls-exporter (in more tls-unique) soon...

gopherbot pushed a commit that referenced this issue May 25, 2023
All OpenSSL tests now test operation with EMS. To test a handshake
*without* EMS we need to pass -Options=-ExtendedMasterSecret which is
only available in OpenSSL 3.1, which breaks a number of other tests.

Updates #43922

Change-Id: Ib9ac79a1d03fab6bfba5fe9cd66689cff661cda7
Reviewed-on: https://go-review.googlesource.com/c/go/+/497376
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
@rsc
Copy link
Contributor

rsc commented May 30, 2023

Update: (1), (2), (3) were landed for Go 1.21 because they are non-breaking changes. (4) is planned for Go 1.22 with a GODEBUG.

@rsc
Copy link
Contributor

rsc commented May 31, 2023

No change in consensus, so accepted. 🎉
This issue now tracks the work of implementing the proposal.
— rsc for the proposal review group

@rsc rsc changed the title proposal: crypto/tls: implement RFC7627 crypto/tls: implement RFC7627 May 31, 2023
@rsc rsc modified the milestones: Proposal, Backlog May 31, 2023
@ianlancetaylor
Copy link
Contributor

@FiloSottile Would you be able to add a release note for the changes here? There is a TODO in doc/go1.21.html. Thanks.

Also I see that this issue is still open. What is left to do?

Also I see a comment about a GODEBUG setting, which as far as I can tell is not implemented. Is that still useful or did the CL go in a different direction?

(My apologies for not understanding what this issue is actually about.)

@Neustradamus
Copy link

@ianlancetaylor: It is not fully supported: @FiloSottile has specified "Let's leave (4) for Go 1.22".

@ianlancetaylor
Copy link
Contributor

@Neustradamus Thanks. So we just need release notes for the other parts.

@ianlancetaylor
Copy link
Contributor

Ah, this has actually been done in https://go.dev/cl/501303. Sorry for the noise.

@Neustradamus
Copy link

Now Go 1.21.0 has been released, what is the status of this ticket?

@jgallucci32
Copy link

Looks like change was merged several months ago
https://go-review.googlesource.com/c/go/+/497376

@Neustradamus
Copy link

@rolandshoemaker rolandshoemaker self-assigned this Oct 31, 2023
@Neustradamus
Copy link

I think that you have seen the jabber.ru MITM and Channel Binding is the solution:

Little details, to know easily:

  • tls-unique for TLS =< 1.2
  • tls-server-end-point
  • tls-exporter for TLS = 1.3

@gopherbot
Copy link

Change https://go.dev/cl/544155 mentions this issue: crypto/tls: disable ExportKeyingMaterial without EMS

@Neustradamus
Copy link

Hello @FiloSottile, now it is perfect for you about TLS 1.3?

Can you look "tls-server-end-point" too?

It is in RFC and XEPs too:

Thanks in advance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Proposal Proposal-Accepted Proposal-Crypto Proposal related to crypto packages or other security issues
Projects
Status: Accepted
Development

No branches or pull requests