On face, it looks reasonable. I'd introduce a bit of extra nonce to the
key generation sequence (otherwise it's conceivable that the master
could be derived from enough samples as well as it being possible to
predict keys). Ideally, keys would be generated on remote clients and
exchanged without passing through the server, thus preventing our
machines from having any actionable knowledge.

As it stands, it may still be possible for our servers to record the
keys being generated and distributed out, thus allowing us (in theory)
to read user content. Oh, the fun of pen registers.

Somewhat simplifying things, I understood one of the previous
conversations about this as folks wanting a "shared" key pair (For
services/reliers/ any 3rd party). This key pair would be somewhat
ephemeral, and could be changed whenever the basis for the key changes
(e.g. Party 4 is no longer part of our group, so change the keys to
exclude them).

I'm not really sure how to avoid using something akin to PKE for this,
unless there's some new, well proven mechanism for doing encryption. I'm
guessing we're still effectively doing that here, but using internally
generated keys as masters. I'm a bit confused about a few things, though.

* Where is kB actually generated? Is this done on Mozilla controlled
servers or is it generated and stored elsewhere? How is this data
stored, indexed and retrieved?

* You note that the response for the OAuth Dance is a block that
contains both a key derived from the fn( fn(user_kA, relier_id),
submitted_pubKey). Why not combine user_kApub & submitted_pubKey as a
shared secret and use more traditional RSA type encryption? I know that
encryption is scary as hell, but there are a LOT of reliable libraries
and it might be prudent to stick to known patterns rather than
concocting new ones.

On 2014/12/17 2:44 AM, Ryan Kelly wrote:
>
> Hi All,
>
>
> A limitation of the current FxA OAuth flow is that OAuth reliers
> cannot get access to the user's encryption keys.
>
> This means that we could not have build new-sync atop our OAuth
> infrastructure.  I've also heard from at least two potential new
> services that would like to do encryption of user data.
>
> Let's try to figure out a way to enable this.
>
> Below is a concrete proposal based on discussions I've had with a few
> folks.  It's intended as a starting point for discussion.  I don't
> think we can realistically ship anything like this before Q2, but it
> would be good to reach a rough consensus on approach so that people
> can starting hacking around with the ideas.
>
> It's pretty long, so I recommend stopping here if you're not
> interested OAuth or encryption keys...
>
>
>
> A brief recap of the current situation:
> =======================================
>
> Your Firefox Account comes with a pair of encryption keys, "kA" and
> "kB".  The first is known to the server and designed for encrypting
> data that must be recoverable even after a password reset.  The second
> is derived from the user's password and hence secret even from
> Mozilla, but will not survive a password reset event.
>
> Sync currently encrypts your stored data using a derivative of kB.
>
> To obtain these keys, you must know the user's account password and
> you must perform some special extra steps at login time.  There is no
> way to fetch either key without having the account password.
>
> Since OAuth reliers never get to see the user's password, there is
> currently no way for them to take advantage of these keys.
>
> Starting premises:
>
>   * OAuth reliers should be able to obtain encryption keys.
>
>   * OAuth reliers must not be able to access the raw values of kA or kB,
>     but may obtain derivatives of them with user consent.
>
>   * FxA servers must never learn kB or anything derived from it.
>
>   * OAuth relier servers should be able to avoid learning anything
>     derived from kB (although we cannot prevent them from deliberately
>     sending the keys from client to server).
>
>   * And of course, OAuth reliers must never have access to the user's
>     account password, or anything that can be used to guess it.
>
>
> Any amendments or additions to this list?
>
>
>
> A proposal for scoped encryption keys:
> ======================================
>
> There will be two different types of derived encryption key in our
> service ecosystem.
>
>
> 1) Relier-specific keys
>
> Each OAuth relier should be able to obtain a pair of derived keys
> kAr/kBr that are private to that relier.
>
>   kAr = HKDF(kA, "identity.mozilla.com/picl/v1/keys/relier/<client-id>")
>   kBr = HKDF(kB, "identity.mozilla.com/picl/v1/keys/relier/<client-id>")
>
> The use-case here is an external service that wants to do encryption
> of its own private data, such as an FxA/daybed.io integration.
>
>
> 2) Service-specific keys
>
> Each OAuth service provider should be able to have a derived key that
> is specific to that service, and is provided to any relier that is
> granted access to the service.
>
> As a concrete example, suppose that the readinglist service wants to
> encrypt some fields in the data stored on its server.  As a matter of
> policy, we decide that  we can tolerate loss of such data in the event
> of a password reset, so we define the key for scope "readinglist" as:
>
>   kS = HKDF(kB, "identity.mozilla.com/picl/v1/keys/service/readinglist")
>
> Any relier that is granted access to scope "readinglist" should also
> be able to get this derived key, in order to properly access the data
> stored in the service.
>
>
> These two types completely define the encryption keys available to a
> relier.  During a key-enabled oauth flow they should somehow receive:
>
>   * the relier-specific kAr and kBr
>   * any scope-specific keys defined for the scopes they are granted
>
>
> Any use-cases not covered by one of these two types of derived key?
>
>
>
> A key-fetching OAuth dance:
> ===========================
>
> The real trick, of course, is safely deriving these keys and
> delivering them to the relier.  I posit that this must be done as part
> of the OAuth dance.  The content-server is the only thing that can
> prompt the user for their password in order to derive the keys, and
> the content-server only gets involved during the OAuth dance.
>
> We have a couple of options here, but I'll sketch out the one I like
> best (large chunks of which are thanks to Alexis):
>
>
> 1) When initiating the OAuth dance, the relier generates a
> public/private keypair, stores the private key in its application
> state, and includes the public key in the OAuth authorization request:
>
>   GET /v1/authorization?client_id=AAA&scope=readinglist&keyfetch=PUBKEY
>
>
> 2) We're redirected to the content-server OAuth page, which does its
> usual solicitation of user permission, prompts for the user's password
> if necessary to obtain kA and kB, and derives the appropriate scoped
> encryption keys.
>
>
> 3) The content-server encrypts the derived keys using the supplied
> pubkey and includes them when provisioning the OAuth token:
>
>   POST /v1/authorization
>   ==>
>   {
>     "client_id": "AAA",
>     "scope": "readinglist",
>     "keys": {
>       "relier": [encrypt(kAr, pubkey), encrypt(kBr, pubkey)],
>       "readinglist": encrypt(kS, pubkey)
>     }
>   }
>   <==
>   {
>     "code": "XXX"
>   }
>
>
> 4) We're redirected back to the relier's registered redirect_uri,
> where they retrieve the granted token and encrypted encryption keys:
>
>
>   POST /v1/token
>   ==>
>   {
>     "code": "XXX"
>   }
>   <==
>   {
>     "access_token": "blahblah",
>     "token_type": "bearer",
>     "scope": "readinglist",
>     "keys" {
>       "relier": [encrypt(kAr, pubkey), encrypt(kBr, pubkey)],
>       "readinglist": encrypt(kS, pubkey)
>     }
>   }
>
> The relier can use its private key to decrypt the encryption keys and
> use them as it sees fit.
>
>
> 5) Profit.
>
>
> Points to note:
>
>   * The FxA servers never see any of the keys, because they transit
>     the server in encrypted form.
>
>   * The relier can generate and manage its keyfetch keypair in
>     client-side code, to avoid learning the keys server-side.
>
>   * This flow does not depend on persistent state on the client, all
>     state can be tunneled through URL params in the OAuth flow.
>
>   * There's a whole lot of potential for crypto to be done wrong
>     here!  It's pretty scary stuff and smells kinda fragile.
>
>
> I'd love to avoid public-key crypto here...perhaps there's a way for
> the content-server to generate a symmetric encryption secret and
> communicate it directly back to the relier without it transiting our
> servers?
>
> Chris also suggested that the encryption keys may not need to transit
> the server at all, but could instead be communicated from
> content-server to relier via a client-side postMessage API.  I don't
> know much about postMessage but it sounds worth exploring.
>
> Details aside, will this sort of enhanced OAuth dance give us what we
> want?
>
> Does this sound appropriately terrifying to everyone?
>
>
>
>  Cheers,
>
>     Ryan
>
> _______________________________________________
> Dev-fxacct mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/dev-fxacct

_______________________________________________
Dev-fxacct mailing list
[email protected]
https://mail.mozilla.org/listinfo/dev-fxacct

Reply via email to