See attached, because GMail would wrap lines if I sent it inline.
Robert Ransom
Unlike other commands besides AUTHENTICATE
AUTHENTICATE and PROTOCOLINFO
HMAC-SHA256("Tor controller-to-server cookie authenticator", CookieString)
I'm more than a little green with HMAC. Does this mean that the hmac key is that static string, so it would be implemented like...
import hmac cookie_file = open("/path/to/cookie") h = hmac.new("Tor controller-to-server cookie authenticator", cookie_file.read())
# that second wrapper, where it looks like the above is the key h = hmac.new(h.hexdigest(), server_challenge_response)
# send to the controller send_to_controller(h.hexdigest())
Also, is "HMAC-SHA256" some special hmac implementation that I need to look up? Is it part of the builtin python lib?
Speaking as someone who will need to implement the controller side of this I'm not really sure what I'm supposed to do with this. Some points of clarification that are needed:
1. Is CLIENTCHALLENGE just any arbitrary client provided string used as a salt for the hash? 2. The CLIENTRESPONSE is something that I validate then discard, right? 3. What happens if a user issues a AUTHCHALLENGE, PROTOCOLINFO, then AUTHENTICATE? What about PROTOCOLINFO, AUTHCHALLENGE, AUTHENTICATE?
Personally I don't see the reason for the last handshake. The controller is proving that it should have access by providing the cookie contents. Providing both the cookie contents and SERVERCHALLENGE proves that we sent and received the AUTHCHALLENGE which isn't terribly interesting.
If we only included the AUTHCHALLENGE message and response then this would not require a new authentication method so controllers could opt into the extra cookie validation. That said, if your intent is to force controllers to do the SAFECOOKIE handshake then this makes sense.
Cheers! -Damian
On 2012-02-05, Damian Johnson atagar1@gmail.com wrote:
Unlike other commands besides AUTHENTICATE
AUTHENTICATE and PROTOCOLINFO
HMAC-SHA256("Tor controller-to-server cookie authenticator", CookieString)
I'm more than a little green with HMAC. Does this mean that the hmac key is that static string, so it would be implemented like...
import hmac cookie_file = open("/path/to/cookie") h = hmac.new("Tor controller-to-server cookie authenticator", cookie_file.read())
# that second wrapper, where it looks like the above is the key h = hmac.new(h.hexdigest(), server_challenge_response)
Yes. (See the line below that, which tells you which argument is the key.)
# send to the controller send_to_controller(h.hexdigest())
This seems backwards.
Also, is "HMAC-SHA256" some special hmac implementation that I need to look up? Is it part of the builtin python lib?
Some versions of Python include SHA256 and a generic HMAC implementation (which can be used with SHA256) in their standard library.
Speaking as someone who will need to implement the controller side of this I'm not really sure what I'm supposed to do with this. Some points of clarification that are needed:
- Is CLIENTCHALLENGE just any arbitrary client provided string used
as a salt for the hash?
It is a nonce, used to prove that the CLIENTRESPONSE value is ‘fresh’.
- The CLIENTRESPONSE is something that I validate then discard, right?
Yes.
- What happens if a user issues a AUTHCHALLENGE, PROTOCOLINFO, then
AUTHENTICATE? What about PROTOCOLINFO, AUTHCHALLENGE, AUTHENTICATE?
The former is an error; the latter is expected behaviour.
The safe cookie authentication protocol is only needed for controllers which look at Tor's response to the PROTOCOLINFO command to decide where to look for a cookie file.
Personally I don't see the reason for the last handshake. The controller is proving that it should have access by providing the cookie contents. Providing both the cookie contents and SERVERCHALLENGE proves that we sent and received the AUTHCHALLENGE which isn't terribly interesting.
In the safe cookie authentication protocol, the controller never sends the cookie itself. That is the entire point of the protocol.
If we only included the AUTHCHALLENGE message and response then this would not require a new authentication method so controllers could opt into the extra cookie validation. That said, if your intent is to force controllers to do the SAFECOOKIE handshake then this makes sense.
The old cookie authentication protocol exposes the *controller* to an attack by (what it thinks is) Tor. Controllers which use PROTOCOLINFO to determine which cookie file to use should be updated to remove support for the old COOKIE protocol. Controllers which only look for cookie files at paths whitelisted by their users can safely continue to use COOKIE.
Robert Ransom
See branch safecookie of https://gitweb.torproject.org/rransom/torspec.git for a revised ‘safe cookie authentication’ protocol (in spec-patch form); see branch safecookie-023 of https://gitweb.torproject.org/rransom/tor.git for a completely untested implementation on Tor 0.2.3.x. This needs testing and a backport, and a few Trac tickets.
Robert Ransom
See branch safecookie of https://gitweb.torproject.org/rransom/torspec.git for a revised ‘safe cookie authentication’ protocol
The spec still doesn't look reader friendly but guess we won't be expecting too many clients to implement this. One other note is that keywords like 'must' should be capitalized similar to other parts of the spec.
This needs testing and a backport, and a few Trac tickets.
We could save some work by writing a handler for this in stem. Currently when you run...
git clone git://git.torproject.org/stem.git ./stem/run_tests.py --integ --target RUN_ALL --tor /path/to/your/tor
You'll exercise all of the connection and authentication use cases within around a minute, including... * no control port or socket * control port * control socket * no auth * password auth * cookie auth * multiple auth methods
This will confirm that you aren't inadvertently breaking something else. Then if we add the safe cookie handshake and integ test it'll be easier for you to test this change as it's developed (test runs with a single target take around eight seconds). I'd be happy to help if you can get just about any python snippet correctly authenticating to your feature.
Cheers! -Damian
On Sun, Feb 5, 2012 at 7:46 AM, Robert Ransom rransom.8774@gmail.com wrote:
See attached, because GMail would wrap lines if I sent it inline.
Added as proposal 193.
This seems like a general case of "A and B prove to each other that they both know some secret S without revealing S." Are there existing protocols for that with security proofs? It seems like something that's probably been done before.
I wonder, have you got the HMAC arguments reversed in some places? When you do HMAC("string", cookiestring), you seem to be using the secret thing as the message, and the not-secret thing as the key.
This would be a little easier to read if the function HMAC(HMAC(x,y),z) were given a name.
Part of me wants to to incorporate both the ClientChallengeString and ServerChallengeString in both of the authenticator values, just on the theory that authenticating more fields of the protocol is probably smarter.
I'd note that this doesn't actually prevent information leakage entirely. Instead of making you reveal some secret 32-byte file S, the attacker now makes you reveal HMAC(HMAC(k,S),c), where k is constant and the attacker controls c. That's fine if S has plenty of entropy, but not so good if (say) S has 20 bytes of predictable data and 12 bytes of a user-generated password. Then again, I'm not so sure a zero-knowledge protocol is really warranted here.
I am leery of adding this to 0.2.3.x (which is in feature-freeze), much less backporting it, but I'm having a hard time coming up with a way to do this entirely in the controller, so I guess we could call it a "security fix" rather than a "feature" if we can't think of another way to kludge around the problem.
yrs,
On 2012-02-07, Nick Mathewson nickm@alum.mit.edu wrote:
On Sun, Feb 5, 2012 at 7:46 AM, Robert Ransom rransom.8774@gmail.com wrote:
See attached, because GMail would wrap lines if I sent it inline.
Added as proposal 193.
Remember to push it.
This seems like a general case of "A and B prove to each other that they both know some secret S without revealing S." Are there existing protocols for that with security proofs? It seems like something that's probably been done before.
Yes. I believe this is an existing protocol, except for the extra (inner) HMAC (see next chunk of reply).
I wonder, have you got the HMAC arguments reversed in some places? When you do HMAC("string", cookiestring), you seem to be using the secret thing as the message, and the not-secret thing as the key.
I am, but that HMAC is meant only as a ‘tweaked message-digest function’, so that we never ever compute HMAC(potentially_secret_cookie_string, something_else). (It's remotely possible that someone could have a 32-byte HMAC-SHA256 key stored as a binary file; I want to keep the server from abusing such a key.)
This would be a little easier to read if the function HMAC(HMAC(x,y),z) were given a name.
Part of me wants to to incorporate both the ClientChallengeString and ServerChallengeString in both of the authenticator values, just on the theory that authenticating more fields of the protocol is probably smarter.
I'll think about this further.
I'd note that this doesn't actually prevent information leakage entirely. Instead of making you reveal some secret 32-byte file S, the attacker now makes you reveal HMAC(HMAC(k,S),c), where k is constant and the attacker controls c. That's fine if S has plenty of entropy, but not so good if (say) S has 20 bytes of predictable data and 12 bytes of a user-generated password. Then again, I'm not so sure a zero-knowledge protocol is really warranted here.
The server reveals its string first, thereby proving knowledge of the secret (unless the client e.g. reuses a challenge, in which case it deserves to lose) or access to an oracle for the server-to-controller PoK. (If the server has access to an oracle, it can already brute-force a low-entropy secret. An honest server's secret is not low-entropy, so we don't have to worry about a client using this attack.)
This is also another reason that I used the weird HMAC-of-HMAC construction for both proofs -- no one has an excuse for using a protocol which this authentication protocol could be used to attack.
I am leery of adding this to 0.2.3.x (which is in feature-freeze), much less backporting it, but I'm having a hard time coming up with a way to do this entirely in the controller, so I guess we could call it a "security fix" rather than a "feature" if we can't think of another way to kludge around the problem.
The best that a controller can do without this protocol is to refuse to use the cookie path Tor specifies in its response to a PROTOCOLINFO command unless the controller's user has whitelisted that cookie path. I don't know whether that would be acceptable to controller authors and users.
Robert Ransom
I don't know whether that would be acceptable to controller authors and users.
I'm fine with a couple things... * adding a tor provided blacklist * adding a tor provided whitelist *if* Tor itself fails to start when the torrc has an CookieAuthFile outside of that list and all versions which allow for non-whitelisted files are flagged as obsolete
It would cause confusion for users to be able to define any arbitrary cookie path in Tor, then have some controllers provide buggy looking behavior by failing to authenticate.
As mentioned in irc this Safe Cookie proposal should also include the deprecation of the current CookieAuthentication option. Otherwise a malicious socket could simply claim to only support non-safe cookie authentication to still trick controllers into divulging the cookie. Users could tell their controller to only allow safe cookie auth but in practice users, of course, won't do that.
Cheers! -Damian