stef / libopaque

c implementation of the OPAQUE protocol with bindings for python, php, ruby, lua, zig, java, erlang, golang, js and SASL.
GNU Lesser General Public License v3.0
68 stars 9 forks source link

Explicitly specify SASL mechanism #31

Closed dequbed closed 1 year ago

dequbed commented 1 year ago

It would probably be useful to have a (rough) specification of the SASL mechanism for OPAQUE. I'd like to implement that mechanism in rsasl and for that a specification to be able to throw issues at would be quite useful.

stef commented 1 year ago

awesome, i also have somenone else who is interested in such a spec, and even open to help author, so expect rick to show up here soon :)

vanrein commented 1 year ago

Rick says ping with a really good feeling that you are documenting this.

Pretty simple, really, RFC4422 states the requirements to a mechanism, and the facilities available. There are some variations, such as whether the client already makes a first stab while choosing the OPAQUE mechanism, and whether the server sends additional data alongside with sucessful authentication. You end up specifying the mechname, token formats and when/which token is sent and what constitutes success/failure. Don't forget to also specify the encryption ("wrap") options.

SASL is discussed in the Kitten WG so I suggest subscribing there are posting the proposal. If they like it they might turn it into a full RFC. But only having an Internet Draft already suffices for claiming the mechanism name and binding it to that form of spec. (Internet Drafts are but one form that fulfills longevity of the documentation, unlike, say, a documented posted on a private website that could get reorganised.)

vanrein commented 1 year ago

One place where I'd love to use this is the PAM module that uses Realm Crossover and that I would love to expand with encryption, somehow. Or the upcoming sgetty program that uses SASL; no idea yet how to relay that to the user, but it could revolutionise the security of container, terminal, modem and desktop access. I wrote saltty as a terminal client.

OPAQUE could add encryption options for non-Kerberos users — I have not added encryption anywhere at this time... but I would love figuring out how that could be done. I would also look for ways of adding encryption to Realm Crossover and find ways of getting that into TTY and ASCII as well. Imagine an encrypted session for the duration of SASL-driven sudo, that could add proper value.

I defined SASL for ASCII with an implementation as a special form of mulTTY ASCII discipline with its implementation. This is young software!A

Sorry for being a dreamer... of a future that can make life more secure/private :-)

vanrein commented 1 year ago

A last dream I've had is SASL over EAP which allows WiFi/LAN-level authentication with user credentials. This makes a good combination with Realm Crossover because a hotspot needs nothing but a network connection to login.

That could end the terror of Facebook login for which bar owners are now charged by a "login service provider". And it would be possible to use an agreed-upon key to encrypt traffic, where all the WiFi/LAN owner would do is tunnel it to a VPN concentrator. The owner of the WiFi router no longer needs to worry about abuse of his IP because the client uses his own.

dequbed commented 1 year ago

Pretty simple, really, RFC4422 states the requirements to a mechanism, and the facilities available. There are some variations, such as whether the client already makes a first stab while choosing the OPAQUE mechanism, and whether the server sends additional data alongside with sucessful authentication. You end up specifying the mechname, token formats and when/which token is sent and what constitutes success/failure.

Also there are additional things we'd need to outline, e.g. if/how authzid is transferred.

Don't forget to also specify the encryption ("wrap") options.

I personally don't feel good defining a security layer for OPAQUE. It's very different to Kerberos and doesn't inherently provide several things that would be required for a modern cryptographic transport layer. Immediately to mind come that OPAQUE currently doesn't even use any symmetric encryption (as far as I can tell), lacking support for key renegotiation (especially relevant for ChaCha20-Poly1305 and AES-(SIV-)GCM) and defining a cipher suite to begin with (AES is not safe on devices not providing hardware support, ChaCha20 is not available in audited libraries for many languages).

All of these are very much solveable problems mind you! But they would have to be solved, which is not an easy task, and we'd end up re-specifing and -implementing major parts of (D)TLS.

IMHO a better solution would be to specify how to use channel bindings so OPAQUE can be used to prove that no active attacker is intercepting the transport encryption.

Maybe OPAQUE should in fact become a GSSAPI mechanism instead. It could still be used with SASL thanks to the GS2- mechanism family (and could be given a vanity shorthand like GS2-OPAQUE) but using GSSAPI would actually allow to later on switch out the transport ciphers and such; it would also allow usage in protocols not using SASL, e.g. SSH. Channel bindings can also be used in that case, so achievable security is equally good.

EDIT: And a GSSAPI would also immediately specify how to use OPAQUE in HTTP thanks to SPNEGO! Although, with draft-vanrein-httpauth-sasl the same can be said for SASL.

vanrein commented 1 year ago

Also there are additional things we'd need to outline, e.g. if/how authzid is transferred.

Ah yes, that allows the use of an alias different from, but somehow permissive from, the authentication identity. Very useful.

Don't forget to also specify the encryption ("wrap") options. I personally don't feel good defining a security layer for OPAQUE. It's very different to Kerberos and doesn't inherently provide several things that would be required for a modern cryptographic transport layer.

That's a fair concern, indeed. To be quite honest, for Realm Crossover we derive this no matter what (it does use Kerberos infra, as a matter of fact). It mutually exchanges salts to do this in a channel-specific manner.

All of these are very much solveable problems mind you! But they would have to be solved, which is not an easy task, and we'd end up re-specifing and -implementing major parts of (D)TLS.

I admit that is what I am interested in :) as it matches how people use RFB/VNC with SASL -- if it supports encryption, then that will be used.

IMHO a better solution would be to specify how to use channel bindings so OPAQUE can be used to prove that no active attacker is intercepting the transport encryption.

I believe you cannot simply export secret keys from SASL. In GSSAPI you do have a gss_get_mic() and gss_verify_mic() that could help to enforce a channel binding code.

Maybe OPAQUE should in fact become a GSSAPI mechanism instead.

I think that makes sense. Note that GS2- and GSSAPI offer different options; GS2- negotiates the GSSAPI mech during SASL negotation, which avoids later hickups; but GS2-* explicitly bans the use of encryption, which you don't seem to mind. The inclusion of SSH is a great plus, although one could also imagine getting that from SASL (with an extension to OpenSSH).

EDIT: And a GSSAPI would also immediately specify how to use OPAQUE in HTTP thanks to SPNEGO! Although, with draft-vanrein-httpauth-sasl the same can be said for SASL.

The difference is that SPNEGO is considered really weak. This is one of the motivations behind the work on HTTP-SASL.

dequbed commented 1 year ago

Ah yes, that allows the use of an alias different from, but somehow permissive from, the authentication identity. Very useful.

Very useful and also a staple of just about every SASL mechanisms since LOGIN. Would be amiss to let it go now ;)

All of these are very much solveable problems mind you! But they would have to be solved, which is not an easy task, and we'd end up re-specifing and -implementing major parts of (D)TLS.

I admit that is what I am interested in :) as it matches how people use RFB/VNC with SASL -- if it supports encryption, then that will be used.

I'm not explicitly against the idea of specifying a security layer. But in that case I'd like to steal a page from PASETO and forgo cipher agility using protocol versioning. So e.g. instead of a mechanism OPAQUE we instead define the family OPAQUE-* with OPAQUE-v1 employing (again, just illustrative examples) HKDF(Blake2b) + AES-256-GCM-SIV for transport layer encryption and a separate OPAQUE-v2 employing HSalsa20 + XChaCha20-Poly1305 for encryption. That way should it turn out that AES-GCM-SIV was a bad idea the mechanism OPAQUE-v1 could be marked 'OBSOLETE' or even 'MUST NOT be used' with IANA and a new OPAQUE-v3 that solves those issues (by switching to AES-256-GCM for example) be specified.

That would still leave us with the problem of key renegotiation but AFAICT neither SASL nor GSS-API specify that ciphertext overhead must be constant so it should be no issue to implement a scheme where that happens inline and entirely invisible to the user.

IMHO a better solution would be to specify how to use channel bindings so OPAQUE can be used to prove that no active attacker is intercepting the transport encryption.

I believe you cannot simply export secret keys from SASL. In GSSAPI you do have a gss_get_mic() and gss_verify_mic() that could help to enforce a channel binding code.

I don't think it's necessary to export secret keys from SASL here. The channel bindings could be included in the OPAQUE exchange, e.g. (without having checked the effect on security here, this too is just an illustrative example ^^) by using the channel binding data as part of the client_ resp. server_identity used in OPAQUE.

Note that SASL in that situation really excells in a system where both sides encrypt as early and as much as possible with identity being validated much later (including with channel bindings in this case). OPAQUE on the other hand excells in situations where you validate identity first and then use that to establish an immediately trusted encrypted channel. TLS mostly leands towards the former but IIRC you have written a draft of TLS and Kerberos integration that has to deal with the same underlying issue, so I assume this won't become a big problem.

Funnily enough this approach of validating identity first is why I'm currently developing a Kerberos server that uses OPAQUE to make the KDC not have to store princial keys to make it a much less attractive attack target.

Maybe OPAQUE should in fact become a GSSAPI mechanism instead.

I think that makes sense. Note that GS2- and GSSAPI offer different options; GS2- negotiates the GSSAPI mech during SASL negotation, which avoids later hickups; but GS2-* explicitly bans the use of encryption, which you don't seem to mind. The inclusion of SSH is a great plus, although one could also imagine getting that from SASL (with an extension to OpenSSH).

I'm not opposed to not having security layers, yes. ;) That being said, if we do want to specify security layers I'd think the right choice would then be to define an OPAQUE SASL mechanism and GSSAPI mechanism separately that makes the best use of both frameworks. Looking at the more recent SASL mechanism RFCs this does seem to be the norm either way.

The difference is that SPNEGO is considered really weak. This is one of the motivations behind the work on HTTP-SASL.

I'm not aware of SPNEGO being considered especially weak in a general context, just the most prevalent SPNEGO implementation happens to be Microsoft Active Directory which suffers from some questionable algorithm choices.

Could you provide any information on attacks on / weaknesses of the protocol side of SPENGO specifically?

stef commented 1 year ago

great to have you both on board with this, it seems you are very much more knowledgeable about SASL and GSSAPI than me. i'm quite excited about all your comments, ideas and other input.

my plan is to only specify what exists already, the authentication and the messages being exchanged between client and server. i'm gonna publish a 1st draft asap.

things for the more distant future...

i was thinking also earlier of doing a secure layer as well, but that should be unrelated to OPAQUE really and could be used also by other SASL auth mechanisms. I'm not sure if and why key renegotiation is important, but then i was thinking if i do already a secure layer, why not make it double ratchet based, which means there is constant key ratcheting. and opaque already has the other part of signal the x3dh anyway.

however what i think is much more needed - at least for HTTP and other protocols that can have totally unrelated requests in the same TCP connection - than a secure layer is some kind of HOTP like authentication mechanism that avoid having the client do the full 3 message dance to authenticate every request. With HOTP every request could be authenticated independently without any roundtrips and it would mitigate replay attacks at the cost of maintaining state at the client and server. the latter being a problem in setups where you have a loadbalancing setup, then every balanced server needs access to the state (which is really just a counter). but then this whole HOTP mechanism is really only needed for HTTP, dunno other protos that support SASL and send totally unrelated requests in the same TCP connection.

i think doing a GSSAPI OPAQUE mechanism is a very interesting idea.

The topic of channel binding is one that i also think is extremely useful to explore, although i have not quite groked how that would work with HTTP for example.

and yes, this is correct:

Note that SASL in that situation really excells in a system where both sides encrypt as early and as much as possible with identity being validated much later (including with channel bindings in this case). OPAQUE on the other hand excells in situations where you validate identity first and then use that to establish an immediately trusted encrypted channel.

hence i am convinced that this https://datatracker.ietf.org/doc/html/draft-sullivan-tls-opaque is the right approach to solve all of this. despite me nagging nick he so far seems to not have revived this effort, maybe you can ping him about this?

stef commented 1 year ago

so this is my first stab at a specification: https://github.com/stef/sasl-opaque @dequbed please tell me what you miss from this, and what is that should not be in there. any help, comments, etc much appreciated.

vanrein commented 1 year ago

Thanks, Stef.

I have a habit of writing everything I can think of, but also to stop certain things if you tell me you don't care. (Language, say.)

https://github.com/stef/sasl-opaque/compare/main...arpa2:sasl-opaque:main

I will go and read up on te reference you included as Informative. I haven't yet studied OPAQUE, but do know SRP.

-Rick

stef commented 1 year ago

not sure you need to read the opaque spec. but go ahead and enjoy if you have the time.

vanrein commented 1 year ago

not sure you need to read the opaque spec. but go ahead and enjoy if you have the time.

I won't need it to see the tokens pass in and out, but I like to understand what is going on. I will try the specs first; compared to SRP they add more notational spin, but these structures alone are interesting to see (unlike directly spec'ing out the bytes). I liked the notational style in the new TLS too.

I worked on SRP before, even made it work with a kay in PKCS #11, https://github.com/arpa2/srp-pkcs11 I am interested in OPAQUE because it (finally) carries over the ideas of SRP to elliptic curves. Safe DH keys are ridiculous.

dequbed commented 1 year ago

so this is my first stab at a specification: https://github.com/stef/sasl-opaque @dequbed please tell me what you miss from this, and what is that should not be in there. any help, comments, etc much appreciated.

I finally had the time to get my idea for a draft into a more readable state and publish it to Github; see https://github.com/dequbed/draft-reitzenstein-auth-opaque (rendered)

My draft focuses much more on the wire format, based on GS2 and heavily on SCRAM, and goes about defining a mechanism family instead of just one singular mechanism (I think this is the better approach as it would make specifiying OPAQUE using e.g. Argon2id+Decaf448+Blake3 much easier, i.e. that could be "OPAQUE-A448BLK(-PLUS)" and a quite short RFC only specifing the exact variants of all primitives)

I also try to fix what is in my opinion one of the biggest warts of OPAQUE proper; it requiring pre-defined parameters for the KSF. Instead I pass the parameters in the first server message which as I understand the OPAQUE spec should work.

I do like your idea of using the authid and server hostname as client and server identity respectively!

hyc commented 1 year ago

Thanks for the ping. IMO, there should be a SASL/OPAQUE mechanism and it should offer a security layer, so that it can be a drop-in replacement for e.g. SASL/DIGEST-MD5 and SASL/SCRAM. In practice, OpenLDAP supports both SASL and TLS security layers simultaneously, but on (at least) older Windows AD they are mutually exclusive, so omitting the option of a security layer here would severely limit its usefulness in Windows environments.

dequbed commented 1 year ago

Thanks for the ping. IMO, there should be a SASL/OPAQUE mechanism and it should offer a security layer, so that it can be a drop-in replacement for e.g. SASL/DIGEST-MD5 and SASL/SCRAM. In practice, OpenLDAP supports both SASL and TLS security layers simultaneously, but on (at least) older Windows AD they are mutually exclusive, so omitting the option of a security layer here would severely limit its usefulness in Windows environments.

I disagree. For one, SCRAM does not offer a security layer in the first place, so not having one would still be a drop-in replacement. Secondly, security layers are usually worse than just using TLS with channel binding. That option is exactly what SCRAM goes for, and my draft follows suit.

In the AD situation that is also IMO the best solution; use TLS to connect to the server and use channel binding to bind the authentication to that TLS channel. It has none of the complexities of security layers while providing almost all of the benefits of them and provides all of the security of TLS.

stef commented 1 year ago

so this is my first stab at a specification: https://github.com/stef/sasl-opaque @dequbed please tell me what you miss from this, and what is that should not be in there. any help, comments, etc much appreciated.

I finally had the time to get my idea for a draft into a more readable state and publish it to Github; see https://github.com/dequbed/draft-reitzenstein-auth-opaque (rendered)

great work!

My draft focuses much more on the wire format, based on GS2 and heavily on SCRAM, and goes about defining a mechanism family instead of just one singular mechanism (I think this is the better approach as it would make specifiying OPAQUE using e.g. Argon2id+Decaf448+Blake3 much easier, i.e. that could be "OPAQUE-A448BLK(-PLUS)" and a quite short RFC only specifing the exact variants of all primitives)

I like how our proposals are complementary, mine defines the wireformat of the opaque messages (based on ke[123]) and yours the packaging of them into gs2. using this approach it is possible to define further configurations of opaque using additional rfcs that define the wireformat of those like mine. we should find a way to refer to each other in our proposals.

i have three comments on your proposal:

1/ i don't think channel binding makes sense in the context of OPAQUE. afaiu channel binding is meant for auth mechanisms where the authentication token (hashesof? passwords) can be replayed/reused in other channels, right? but with OPAQUE each session (channel?) is unique due to the use of ephemeral key parameters, and thus reusing the "authentication" token KE3 in another channel/connection will be futile. 2/ you write every instantiation of opaque consists of 3 steps/messages. this is not quite true, since opaque also authenticates the server, opaque must abort if the client cannot validate the server. 3/ I expect a few RFC-specified OPAQUE variants (members of the family) currently the IRTF CFRG specifies and publishes testvectors only for two variants one r255 and one p256 based, and this draft is now being worked on for already 2+ years, and both of them using a "null" KSF. on the other hand i have to admit, the variant i specify in my draft is using argon2i as a ksf, so there is already a variant, which fixes the omission of a KSF. and the other C based implementation of opaque supports also 448 iirc so that would be a couple more variants depending on their chosen KSF (i think they only do null, now?)

I also try to fix what is in my opinion one of the biggest warts of OPAQUE proper; it requiring pre-defined parameters for the KSF. Instead I pass the parameters in the first server message which as I understand the OPAQUE spec should work.

there has been previous discussions on this: https://github.com/cfrg/draft-irtf-cfrg-opaque/issues/69 and i tend to agree, that negotiation of KSF parameters adds complexity which is undesirable.

I do like your idea of using the authid and server hostname as client and server identity respectively!

thanks. i think it's kind of obvious.

stef commented 1 year ago

oh. i forgot, the server can also abort early already after the first message from the client, if parameters are invalid, like the blinded element not being a point on the curve.

vanrein commented 1 year ago

Um, is it useful to start a competing fork instead of aiming for one integrated text? What is your plan regarding getting things together?

dequbed commented 1 year ago

1/ i don't think channel binding makes sense in the context of OPAQUE. […]

I already answered to this question in more detail in my Preamble issue. TL;DR no channel binding are very much useful for OPAQUE.

2/ you write every instantiation of opaque consists of 3 steps/messages. this is not quite true, since opaque also authenticates the server, opaque must abort if the client cannot validate the server.

I'll keep it under nits, but in general aborted authentications are already specified by RFC4422 so I don't go into detail for it.

3/ I expect a few RFC-specified OPAQUE variants (members of the family) […]

Sure, and I'd like to cooperate with them to use a shared registry for specified groups of cryptographic primitives so we don't double that work. The existing spec however already allows for any KSF, test vectors not required.

I also try to fix what is in my opinion one of the biggest warts of OPAQUE proper; it requiring pre-defined parameters for the KSF. Instead I pass the parameters in the first server message which as I understand the OPAQUE spec should work.

there has been previous discussions on this: [link skipped] and i tend to agree, that negotiation of KSF parameters adds complexity which is undesirable.

I am aware of that issue. That issue however is about putting that information in the OPAQUE envelope proper, which I do agree is superflous. What my draft is doing is informing the client of the parameters that were used at registration, in other words what kevinlewi called "Option 1" in the linked issue.

Um, is it useful to start a competing fork instead of aiming for one integrated text? What is your plan regarding getting things together?

I already had written most of my spec before stef posted his draft, I just didn't end up setting the github repo to public because of the rough state of the draft. And given how much the spec needs to evolve I don't think incorporating the two documents will be an issue.

hyc commented 1 year ago

I disagree. For one, SCRAM does not offer a security layer in the first place, so not having one would still be a drop-in replacement. Secondly, security layers are usually worse than just using TLS with channel binding. That option is exactly what SCRAM goes for, and my draft follows suit.

IMO the lack of a security layer in SCRAM was a mistake. Many OpenLDAP installations used SASL/DIGEST-MD5 with the security layer because it's easier to deploy than TLS - i.e., nobody needs to contact a CA or generate certs or whatever. If sites already have the infrastructure required to deploy TLS, then they don't need SASL at all, they can do server authentication in TLS itself and just use one-way-hashed passwords for authentication, or issue X.509 certs to all their users. SASL itself becomes completely superfluous without a security layer.

stef commented 1 year ago

i believe this issue can be closed, since there is this: https://github.com/stef/sasl-opaque

if you disagree, please reopen and explain why you think this needs further tracking. thank you all for your valuable contributions!