Changes

Jump to: navigation, search

Identity/AttachedServices/KeyServerProtocol

962 bytes added, 22:01, 27 June 2013
Email+Password -> SignToken: merge "sign" and "reset" token-fetching methods
NOTE: This specification is under active development (27-Jun-2013). Several pieces are not yet complete. If you write any code based on this design, keep a close eye on this page and/or contact me (warner) on the #picl IRC channel to learn about changes. Eventually this will be nailed down and should serve as a stable spec for the PICL keyserver/IdP protocol.
== Email+Password -> SignToken /ResetToken ==
The current stub just submits plaintext email+password and receives back (signToken, kA, wrap(kB)). It uses no key-stretching, nor SRP.
The full replacement uses key-stretching to transform the email+password into a "masterKey", then feeds this into an SRP protocol to get a session key. It uses this session key to decrypt a bundle of encrypted data from the keyserver, resulting in three values: kA, wrap(kB), and the signToken(or resetToken).
[[File:PICL-IdPAuth-bigpix.png|IdP Auth Big Picture]]
This same protocol is used, with slightly different methods and constants, to obtain the "resetToken".
The protocol is optimized to minimize round-trips and to enable parallelism. As a result, the two messages it sends (getSignToken1 getToken1 and getSignToken2getToken2) each perform multiple jobs.
=== getSignToken1 getToken1 ===
As soon as the user finishes typing in the email address, the client should send it in the "getSignToken1getToken1" message to the keyserver. The response will include a set of parameters that are needed for key-stretching (described below), and the common parameters used by both sides of the SRP protocol to follow. These are simply looked up in a database entry for the client, along with an account-id. It must also include an allocated session-id that is used to associate this request with the subsequent getSignToken2 getToken2 request. Finally, the response also includes the server's contribution to the SRP protocol ("srpB"), which is calculated on the server based upon a random value that it remembers in the session.
=== Proof-Of-Work ===
To protect the server's session table memory and CPU usage for the initial SRP calculation, the server might require clients to perform busy-work before calling getSignToken1getToken1().
(TBD)
=== Client-Side Key Stretching ===
The current stub does no stretching. It just performs a single HKDF operation, combining the user's email address, their password, and a "stretchSalt" retrieved from the server's getSignToken1getToken1() response.
[[File:PICL-IdPAuth-stretch-KDF.png|Stretching KDF]]
A later version of the protocol will replace this with the PBKDF2+scrypt+PBKDF2 protocol described in [[Identity/CryptoIdeas/01-PBKDF-scrypt]]. This stretching is expected to take a second or two. The client can optimistically start this process (using default parameters) before receiving the getSignToken1getToken1() response, and then check that it used the right parameters afterwards (repeating the operation if not). (We'll want to build the stretching function with periodic checkpoints so that we don't have to lose all progress if the parameters turn out to be wrong). The "stretchSalt" is added *after* the stretching, to enable this parallelism (at a tiny cost in security).
After "masterKey" is derived, a second HKDF call is used to derive "unwrapKey" and "srpPW" which will be used later.
[[File:PICL-IdPAuth-client-SRP.png|client-side SRP]]
The basic idea is that we're using the main-KDF output "srpPW" as a password for the SRP calculation, and leaving . We use the other values (email address for "identity" , and a server-provided string for "salt") . (We could safely leave them blank, since they're equivalent values are already folded into the password-stretching process, but it's less confusing to follow the SRP spec and fill them in with something sensible).
The SRP "g" (generator) and "N" (prime modulus) should use the 2048-bit value from RFC 5054 Appendix A, which is also used in SRP. Clients should not accept arbitrary g/N values(to protect against small primes, non-primes, and non-generators). In the future we might allow alternate parameter sets, in which case the server's first response should indicate which parameter set to use.
The server creates its "B" value according to the SRP protocol and includes it in the response to getSignToken1getToken1.
The client does its entire SRP calculation in a single step, after receiving the server's "B" value. It creates its "A" value, computes the shared secret S, and the proof-of-knowledge M1. It sends both "A" and "M1" in the same message (getSignToken2getToken2).
The server receives "A", computes the shared secret "S", computes M1, checks that the client's M1 is correct, then derives the shared session key K. It then allocates a signToken token (of the requested type) and encrypts kA+wrap(kB)+signToken token as described below, returning the encrypted/MACed bundle in the response to getSignToken2getToken2.
=== getSignToken2 getToken2 ===
This method has two flavors, one for obtaining "signing tokens", the other for getting "reset tokens". TBD: either we'll have two different method names / API endpoints (getToken2Sign and getToken2Reset), or we'll pass an argument to a single "getToken2" method that indicates either "sign" or "reset". (using different endpoints would make it easier to monitor server load). The client-side SRP calculation results in two values that are sent to the server in the "getSignToken2getToken2()" message: "srpA" and "srpM1". "A" is the client's contribution to the SRP protocol. "M1" is an output of this protocol, and proves (to the server) that this client knew the right password.
The server feeds "A" into its own SRP calculation and derives (hopefully) the same "S" value as the client did. It can then compute its own copy of M1 and see if it matches. If not, the client (or a man-in-the-middle) did not get the right password, and the server will return an error and increment it's "somebody is trying to guess passwords" counter (which will be used to trigger defenses against online guessing attacks). If it does match, then both sides can derive the same "K" session key.
The server then allocates a signToken token for this device, and encrypts kA/wrap(kB)/signToken token with the session key. The server returns a success message with the encrypted bundle.
Future variants (e.g. to fetch a third kind of token) might put additional values in the response to getToken2. === Decrypting the getSignToken2 getToken2 Response ===
The SRP session key ("srpK") is used to derive two other keys: respHMACkey and respXORkey.
[[File:PICL-IdPAuth-decryptSignToken1.png|Decrypting the signToken 1]]
The respXORkey is used to encrypt the concatenated kA/wrap(kB)/signToken token string, by simply XORing the two. This ciphertext is then protected by a MAC, using HMAC-SHA256, keyed by respHMACkey. The MAC is appended to the ciphertext, and the whole bundle is returned to the client.
[[File:PICL-IdPAuth-decryptSignToken2.png|Decrypting the signToken 2]]
The client recomputes the MAC, compares it (throwing an error if it doesn't match), extracts the ciphertext, XORs it with the derived respXORkey, then splits it into the separate kA/wrap(kB)/token values. Since the kA/wrap(kB)/signToken response is so similar to the kA/wrap(kB)/resetToken response, the same code can be used to check+decrypt both. However remember that the respXORkey/respHMACkey is derived differently for each (using different "context" values).
== Signing Certificates ==
Confirm
471
edits

Navigation menu