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

Allow changing Preable construction & usage in OPAQUE-3DH #375

Closed
dequbed opened this issue Sep 30, 2022 · 6 comments
Closed

Allow changing Preable construction & usage in OPAQUE-3DH #375

dequbed opened this issue Sep 30, 2022 · 6 comments

Comments

@dequbed
Copy link

dequbed commented Sep 30, 2022

As of 4c36aa9, the Preamble used by OPAQUE-3DH is defined as:

concat("RFCXXXX",
       I2OSP(len(context), 2), context,
       I2OSP(len(client_identity), 2), client_identity,
       ke1,
       I2OSP(len(server_identity), 2), server_identity,
       credential_response,
       server_nonce,
       server_keyshare)

I'm currently working on a SASL mechanism specification using OPAQUE, where it would be benefitial to be able to construct this transcript hash, that is the preamble, in a very different way.

For one, due to SASLprep and encoding limitates enforced by the wire format, client_identity has three different representations. The mechanism specification would need to be careful to make clear which one is used in every context and it would make implementation bugs much more likely, as the representations only differ with identities containing complex unicode or characters such as '=' and ','.

Secondly, while the preamble does have a context field parts of the data I would like to include are only available after the server response, making constructing the preamble using a running hash function impossible.

I think this is a reasonably simple change as making 'preamble' an (opaque) parameter to AuthServerRespond and AuthClientFinalize instead of constructing it inline would already allow me to refer to those functions as-is instead of having to redefine them using a different preamble construction.

If this change is something that is wanted I'm happy to write a pull request with updated text to this end.

@kevinlewi
Copy link
Collaborator

I don't think the preamble construction should be changed, as it is core to the security of the protocol and should be kept as required with this specific format. The preamble must incorporate its current parameters (client_identity, ke1, server_identity, ke2), as leaving any of them out would not be a good idea.

Perhaps the way the elements are concatenated together could be adjusted without affecting security, but I don't think that that is what you are suggesting...

@stef
Copy link
Contributor

stef commented Oct 2, 2022

may i ask why this is necessary? my guess would be that this is for channel binding? if so i don't think channel binding is a useful thing in the context of opaque, since each session is unique and thus implicitly channel-bound. channel binding only makes sense for auth protocols where the authentication token (hashed? password) is static and thus can be replayed/reused easily in other connections.

@dequbed
Copy link
Author

dequbed commented Oct 4, 2022

Right, I put the cart before the horse here a bit.

The first thing I think that I should explain is that I'm treating OPAQUE in this application not as a complete monolithic and immutable protocol but rather as one that can be adapted to its application where necessary.

In this specific application I'm wrapping the OPAQUE exchange for authentication and have the requirement that some additional adjacent data is integrity protected and cryptographically bound into this authentication exchange.

The best approach for that is to protect this adjacent data with the MAC sent in KE2 and KE3.

To illustrate what I'm planning with an example, C: and S: meaning messages sent by the client and server side respectively (newlines and comments added for readability):

C: y=tls-exporter,a=admin,n=user,r=rqdPU7Jkr.../QdeUv2Re+uCl
   └────── adjacent data  ──────┘  └─ b64 encoding of ke1 ─┘

   ┌──────────────────── adjacent data ────────────────────┐
S: c=YYWzZcN...sq3Ur6/hHBfw==,i=dj0xOSxtPTQwO...D0zLHA9MQo=,
   v=f7s7GPGMl2DPCgoPyqh...jhuYAWdMqC4yl3qZYmT58=,p=MAANo1c2VwPlWV7e...0PZhvrpjyKs3+Bko=
   └─ b64 encoding of ke2 minus the server MAC ─┘   └─ b64 encoding of the server mac ─┘

C: p=+HU90iCCXustmuDlOejEcig5inkRPlIraEDh7kJwT1w=
     └────────── b64 encoding of ke3  ──────────┘

This adjacent data is here the (client) Authorization and Authentication identities, channel binding data, and the parameters to the KSF that need to be used.

My approach to generating a preamble / transaction log here would be to construct a running hash over the wire-format messages and MAC that, the server mac running up to but excluding the ,p= of its message. (Which is the reason why KE2 needs to be split up)

The preamble must incorporate its current parameters (client_identity, ke1, server_identity, ke2), as leaving any of them out would not be a good idea.

Yes, I am acutely aware of that and as you can see from my above example I do not plan to exclude any data from the transaction hash, and instead only want to include further important data. An open question is however that I would prefer to bind to the public keys of the parties and not other identities like usernames. However, including the public keys of both sides into the transaction log is merely an issue of specifying it.

Perhaps the way the elements are concatenated together could be adjusted without affecting security, but I don't think that that is what you are suggesting...

I did in fact realize yesterday evening that a solution would be to use this adjacent data as client_identity and server_identity respectively. It would allow to keep the running hash and would solve most technological hurdles, but it does strike me as violating the spirit of the standard and also makes little obvious sense to users.

re stef:

if so i don't think channel binding is a useful thing in the context of opaque, since each session is unique and thus implicitly channel-bound.

Channel binding is about binding an authentication to an underlying encrypted channel like TLS and thus making sure that both sides see the same channel. That's very much not something that OPAQUE gives you implicitly.

channel binding only makes sense for auth protocols where the authentication token (hashed? password) is static and thus can be replayed/reused easily in other connections.

Well, in that case channel binding would make sense because the password and server-side record are static and reused in other connections. :)

@stef
Copy link
Contributor

stef commented Oct 4, 2022

Channel binding is about binding an authentication to an underlying encrypted channel like TLS and thus making sure that both sides see the same channel. That's very much not something that OPAQUE gives you implicitly.

ok, it might seem a dumb question, but it's genuine. what does it matter if a channel is encrypted or not, if the goal is to make sure that both sides see the same channel? and if the two parties can authenticate each other (which they do) then presuming that the ephemeral keys are indeed only used once, the authentication is bound to that tcp connection - limiting here to tcp like transports makes sense i hope, with udp this might not work. so i think opaque does indeed bind to a channel implicitly, and i think the fact of it being encrypted does not matter, as long as the channel is tcp-like connection-based.

@dequbed
Copy link
Author

dequbed commented Oct 4, 2022

@stef This is somewhat derailing the original issue by now, so I'm answering this in a new issue.

@dequbed
Copy link
Author

dequbed commented Oct 6, 2022

As the approach of 'just shove it into the identities' does solve this particular need as far as I can tell I think its appropiate to close this issue for now.

@dequbed dequbed closed this as not planned Won't fix, can't repro, duplicate, stale Oct 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants