Thanks Lunar for bringing this into discussion. See below.
David Goulet wrote:
On 06 Dec (17:23:10), Lunar wrote:
Hi!
Sorry to be late to the party. I still haven't seen UX concerns fully addressed, and I think we should not create a specification that will make the life of our users harder if we can avoid it.
I believe it can be addressed by a good UI in TBB mostly to fit this client authorization proposal. Answers below.
s7r:
George Kadianakis wrote:
I have a more mature torspec branch now for your eyes and only. Please see branch `prop224_client_auth_4` in my torspec repo: https://gitweb.torproject.org/user/asn/torspec.git/log/?h=prop224_client_aut...
The changes are based on the feedback and discussion on this thread.
I would like to state, since I seen it in older posts on this thread, that I dislike the idea of generating at client side low entropy ed25519 key pairs based on simple passwords. It may sound simple and good from UX point of view, but we are decreasing the security of a very secure auth scheme with it and enabling an over-the-hand practice that keys come from client to HS and not vice-versa.
I hope we can find a balance between “a very secure auth scheme” that will be too cumbersome to use for most users and “a secure and usable auth scheme”.
I've been hoping we could get a nice UI in Tor Browser to access authenticated onion services for a while now (#8000). The difficult part UX-wise is that there is no way to differentiate between an onion service that is either non-existant, temporary unavailable or authenticated. (But it's good for security, so let's keep things that way.)
How are users expected to give enter the private key in Tor Browser? Does the key have to be saved on disk? What should I have to do to browse an authenticated onion service when running under Tails without persistence enabled?
We thought about this a bit (maybe not in depth) but the idea here is that an HS operator will have a choice between creating an authentication token for a specific client or add one that a client gave it to her.
At client side, the private keys have to be saved on disk (in plain text if we want to provide a simpler UX, because either way I don't think we can make it as simple as we'd like).
For a client, we kept the "token" to be a one liner containing the key material and an identifier. So it becomes a matter of "How the client generates that token?" and "How it is exchanged between client and operator?" I think the way to go here is for sure an integration in TBB.
First option would be for a user to enter a password and the keys are derived from it and we output the one line that the user should give to the HS operator. If the HS operator already have that line configured in, well great, it addresses the Tails use case where you move around and you simply need to input your password to get the right token that you've already gave to the HS.
I agree here. This becomes a problem when the same user has multiple authenticated HSes. She has to either remember a different password linked to every authorized HS - which is bad for UX, either use a single password for all of them, to keep things easy. If users choose simple passwords, which people are inclined to do, brute-forcing the auth credentials for adversaries that know the onion hostname will become trivial and will defeat the purpose of authentication.
The second option would be to "Generate token for me", output the line and give out-of-band to HS operator that one liner.
And the third option would be to "Enter token here" which is the case where HS operator gives out token to client.
All those are a UI challenge but I think will be _great_ improvement to the current state of things but they are all on TBB side.
Yes, second and third options are not something human memorable or easily reproductive, and will not survive a re-install without backup or suite the 'amnesic' mode users.
Here's a wild idea:
We generate the key client side using a string of words, that are human memorable and when entered again will produce the same key. I think such a system would work at large scale. The key produced here will be the master key.
To solve the challenge of mapping onion hostnames to tokens, eliminate the need to use the same token for all authorized HS and also kind of fix the issue when we don't know which HS uses auth or not, we derive child keys from the master key for each onion hostname.
Client and server need to compute the same child key in every case, so the derivation key will be the HS full onion hostname itself.
Example: token for foo.onion = <master-key> -> <derivation-key: 'foo.onion'> token for abc.onion = <master-key> -> <derivation-key: 'abc.onion'>
Benefits: - users share a single master public key with servers which is easier and also use different credentials for each HS. They can even include it on business cards, email signatures, publish on their blog, you name it.
- there's no need to map each token with an onion hostname, Tor just does it by computing the right token for each HS (this can be cached for a session so that it's not computed over and over again).
- different tokens for every HS computed /used automatically and not even shown to the user, for a simple and easy UX.
- we know if the HS is non-auth, auth or offline: if we don't find a descriptor, it's offline. If we find a descriptor, we compute the child key and decrypt it (auth enabled) or just connect if it's non-auth. This requires computing child keys for every HS we try to connect to, but maybe it's worth it?
- no penalties on server side for revoking a client. Just delete the master public key. Same client can be re-added with the same master public key. When a client changes the master public key it's no different than all other mechanisms anyway so we lose nothing.
Cons: - a HS that has a client master public key can learn if the same client is also authorized for other HS that the address is _known_ . However, one can only learn this info, the auth cannot be defeated since only public key is known, not the private key which is used at client side to decrypt the descriptor.
While I think such a mechanism may be nice from UX point of view, I don't know if curve25519 supports it. It is possible and proven in practice with secp256k1 which is where I got the idea, but this requires a point of view from someone with deeper knowledge in crypto.
One thing that we unfortunately can't solve is the "give token to HS operator automagically", it has to be out-of-band else we are getting into another world of complexity. HOWEVER, we could think of a proposal to have some sort of "Auth Server Transport" support which you could tell your tor to fetch token from that "auth server" but that is some big piece of work.
I don't see how to streamline support for an amnesic system if I have to generate a unique keypair that I need to give to the onion service owner beforehand.
To be honest, it would be quite amazing to pull off a TBB UI for this at the same time as we roll out prop224 in a tor stable :) with the use case of amnesic system.
Should we draw inspiration from miniLock? https://minilock.io/files/HOPEX.pdf (see slide 35)
If I try to think of my experience as an admin, I see several cases where it would be much easier to give authentication token to users myself. User story:
Elena has set up an Etherpad instance on her private server. She generates a handful of access codes before going to meet the newly formed copwatch chapter. After the end of the meeting, she can give out a piece of paper to all attendees so they can access the minutes and write up reports together in the future.
You really don't want to have all attendees bring their computer or require them to meet with Elena at a later time.
Yeah... the client token I've been talking about is a bit long actually but we have to to ensure some semblance of modern security that is ECC keys of 32 bytes.
However, what we could do server side is generate a client key associated with some keywords that if put in TBB UI would generate same client key (a bit like pond does with the words).
This should be an option also. So the HS either generates a random key for a client either uses client's master public key to derive the child key. These need to co-exist at the same time, they are solid use cases.