Services/KeyExchange
Overview
Explore using J-PAKE to securely pass credentials to another device.
Tracking bug is bug 601644.
Engineers Involved
- Tarek (server)
- Philipp (FxSync)
- Stefan (FxHome)
User Requirements
- Setting up a new mobile device should only involve entering a short code on the desktop device
- Secondary request, not a hard requirement, is that if the user has a mobile device, and is setting up a desktop device, that the flow is similar and still involves entering the key on the desktop
Desired User Flow
- User chooses "quick setup" on new device
- Device displays a setup key that contains both the initial secret and a channel ID
- On a device that is authenticated, user chooses "add another device" and is prompted for that key
- The two devices exchange messages to build the secure tunnel
- The already-authenticated device passes all credentials (username/password/passphrase) to the new device
- New device completes setup and starts syncing
Implementation (draft)
Terminology
- Desktop: Client that has Fx Sync already set up
- Mobile: Client that needs to be set up (of course this could be another desktop computer, too)
- PIN: code that is displayed on Mobile and entered on Desktop
- Secret: weak secret that is used to start the J-PAKE algorithm
- Key: strong secret that both clients derive through J-PAKE
Encodings
- The Big numbers are encoded as hex strings (Messages 1 and 2)
- The hash in message 3 is hex encoded
- The ciphertext, IV and hmac are encoded in Base64 (Message 3)
Status Codes
The only valid status codes are 200 and 304 since those are part of the protocol and expected to happen.
Anything else, like 404 or 503 must result in a complete termination of the password exchange. The client can retry the exchange then at a later time, starting all over with clean state.
Flow
- Mobile asks server for new channel ID (3 characters a-z0-9)
C: GET /new_channel HTTP/1.1 S: "a7i"
- Mobile generates PIN from channel ID + random weak secret (3 characters a-z0-9), computes and uploads J-PAKE msg 1
C: PUT /a7i HTTP/1.1 C: C: { C: 'type': 's1', C: 'payload': { C: 'gx1': '45...9b', C: 'zkp_x1': { C: 'b': '09e22607ead737150b1a6e528d0c589cb6faa54a', C: 'gr': '58...7a' C: 'id': 'Mobile', C: } C: 'gx2': 'be...93', C: 'zkp_x2': { C: 'b': '222069aabbc777dc988abcc56547cd944f056b4c', C: 'gr': '5c...23' C: 'id': 'Mobile', C: } C: } C: } S: HTTP/1.1 200 OK S: ETag: "444b424cbc84805b40bcd35c8ebe4524"
- Desktop asks user for the PIN, extracts channel ID and weak secret, fetches Mobile's msg 1
C: GET /a7i HTTP/1.1 S: HTTP/1.1 200 OK ...
- Desktop computes and uploads msg 1
C: PUT /a7i HTTP/1.1 C: C: { C: 'type': 'c1', C: 'payload': { C: 'gx1': '45...9b', C: 'zkp_x1': { C: 'b': '09e22607ead737150b1a6e528d0c589cb6faa54a', C: 'gr': '58...7a' C: 'id': 'Desktop', C: } C: 'gx2': 'be...93', C: 'zkp_x2': { C: 'b': '222069aabbc777dc988abcc56547cd944f056b4c', C: 'gr': '5c...23' C: 'id': 'Desktop', C: } C: } C: } S: HTTP/1.1 200 OK S: Etag: "209a424cbc8480465abcd35c8ebe4524"
- Mobile polls for Desktop's msg 1
C: GET /a7i HTTP/1.1 C: If-None-Match: "444b424cbc84805b40bcd35c8ebe4524" S: HTTP/1.1 304 Not Modified
Mobile tries again after 1s
C: GET /a7i HTTP/1.1 C: If-None-Match: "444b424cbc84805b40bcd35c8ebe4524" S: HTTP/1.1 200 OK ...
Mobile computes and uploads msg 2
C: PUT /a7i HTTP/1.1 C: C: { C: 'type': 's2', C: 'payload': { C: 'A': '87...82', C: 'zkp_A': { C: 'b': '6f...08', C: 'id': 'Mobile C: 'gr': 'f8...49' C: } C: } C: } S: HTTP/1.1 200 OK S: ETag: "111a424cbc8480465abcd35c8ebe4524"
- Desktop polls for and eventually retrieves Mobile's msg 2
C: GET /a7i HTTP/1.1 C: If-None-Match: "209a424cbc8480465abcd35c8ebe4524" S: HTTP/1.1 200 OK ...
Desktop computes key, computes and uploads msg 2
C: PUT /a7i HTTP/1.1 C: C: { C: 'type': 'c2', C: 'payload': { C: 'A': '87...82', C: 'zkp_A': { C: 'b': '6f...08', C: 'id': 'Desktop', C: 'gr': 'f8...49' C: } C: } C: }
- Mobile retrieves Desktop's msg 2
C: GET /a7i HTTP/1.1 C: S: HTTP/1.1 200 OK ...
Mobile computes key, uploads hash of key to prove its knowledge (msg 3)
C: PUT /a7i HTTP/1.1 C: C: { C: 'type': 's3', C: 'payload': { C: 'hash': "aa...ff" C: } C: }
- Desktop retrieves Mobile's msg 3 (hashed key)
C: GET /a7i HTTP/1.1 C: S: HTTP/1.1 200 OK ...
verifies it against its own version. If the hash matches, it encrypts and uploads Sync credentials.
C: PUT /a7i HTTP/1.1 C: C: { C: 'type': 'c3', C: 'payload': { C: 'ciphertext': "base64encoded=", C: 'IV': "base64encoded=", C: 'hmac': "base64encoded=", C: } C: }
If the hash does not match, the Desktop deletes the session.
C: DELETE /a7i HTTP/1.1 S: HTTP/1.1 200 OK ...
This means that Mobile will receive a 404 when it tries to retrieve the encrypted credentials.
- Mobile retrieves encrypted credentials
C: GET /a7i HTTP/1.1 C: If-None-Match: "111a424cbc8480465abcd35c8ebe4524" S: HTTP/1.1 200 OK ...
decrypts Sync credentials and verifies HMAC.
- Mobile deletes the session [OPTIONAL]
C: DELETE /a7i HTTP/1.1 S: HTTP/1.1 200 OK ...
Security Considerations
Discuss potential design and implementation threats & mitigations here.