bcgit / bc-java

Bouncy Castle Java Distribution (Mirror)
https://www.bouncycastle.org/java.html
MIT License
2.21k stars 1.1k forks source link

Geting TLS Channel Binding data for later use in SCRAM #1535

Open bmalkow opened 7 months ago

bmalkow commented 7 months ago

I need to use TLS channel binding data in SASL SCRAM. Easiest way for me is using BC as provider, because I don't want to implement own AbstractTlsServer (especially getCredentials() is thing I don't fully understand). So, please add way to get channel binding data after notifyHandshakeComplete() via ProvSSLEngine. Or improve implementation of DefaultTlsServer to be easy to use. 😄 Thanks

peterdettman commented 7 months ago

e.g.:

byte[] channelBinding = ((BCSSLEngine)engine).getConnection().getChannelBinding("tls-exporter");

bmalkow commented 7 months ago

Unfortunately it doesn't work, when I use BC as provider:

java.lang.IllegalStateException: Export of key material only available from notifyHandshakeComplete()

There is no way to disable cleanupHandshake() or export those data before cleanup.

peterdettman commented 7 months ago

Oh I see that this is broken because we currently clear the master secret (and in TLS 1.3 the exporter secret) after the handshake completes. Our existing tests only cover "tls-unique" channel binding so this wasn't picked up.

A quick fix would be to calculate the "tls-exporter" channel binding for all connections, but it'd be nicer if it could be on demand, including access to the more general TlsContext#exportKeyingMaterial.

Neustradamus commented 1 week ago

@peterdettman: Have you progressed on it?

Thanks in advance.

Linked to:

peterdettman commented 6 days ago

@Neustradamus I have a branch that adds BCSSLParameters#setChannelBindings; those channel bindings will then be established at handshake completion for later collection via BCSSLConnection#getChannelBinding . This is fairly simple but the binding "tls-exporter" has the annoyance that it might be calculated for TLS 1.2 even when you only wanted it in case TLS 1.3 was negotiated (and e.g. "tls-unique" otherwise). I'm inclined to use a separate "tls-exporter-legacy" for the TLS 1.2 case.

Another possibility would be using a callback in the vein of SSLEngine#setHandshakeApplicationProtocolSelector that is called to determine the list of channel bindings (with access to the handshake session presumably).

Finally, I've been contemplating to just have a callback that will give access to the new BCSSLConnection while the "handshake completion window" is still open. There are concerns here around threading issues. The standard JSSE HandshakeCompletedListener notification is thread-decoupled, which would defeat the purpose here. OTOH, SSLSessionBindingListener calls are not thread-decoupled, but I guess that is not so tangled up in the actual protocol. Maybe BCSSLConnection could store values like a session, or perhaps this callback could return a generic "user data" Object that could be collected via a different BCSSLConnection method later.

Comments welcome on the above, or if I've overlooked a better option.