<div dir="ltr">This looks reasonable; a few nits and comments inline.<br><div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Dec 17, 2014 at 2:44 AM, Ryan Kelly <span dir="ltr"><<a href="mailto:rfkelly@mozilla.com" target="_blank">rfkelly@mozilla.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
Hi All,<br>
<br>
<br>
A limitation of the current FxA OAuth flow is that OAuth reliers cannot get access to the user's encryption keys.<br>
<br></blockquote><div><br></div><div><snip><br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
2) Service-specific keys<br>
<br>
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.<br>
<br>
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:<br>
<br>
  kS = HKDF(kB, "<a href="http://identity.mozilla.com/picl/v1/keys/service/readinglist" target="_blank">identity.mozilla.com/picl/v1/<u></u>keys/service/readinglist</a>")<br>
<br>
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.<br>
<br>
<br>
These two types completely define the encryption keys available to a relier.  During a key-enabled oauth flow they should somehow receive:<br>
<br>
  * the relier-specific kAr and kBr<br>
  * any scope-specific keys defined for the scopes they are granted<br></blockquote><div><br></div><div>I'm a little concerned that the set of scope-specific keys is unbounded, and we have a public-key encryption for each one.  That's very expensive.  Perhaps we want to limit the set of keys provided, or do just one encryption for the entirety of the keys: {} data.<br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Any use-cases not covered by one of these two types of derived key?<br>
<br>
<br>
<br>
A key-fetching OAuth dance:<br>
===========================<br>
<br>
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.<br>
<br>
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):<br>
<br>
<br>
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:<br>
<br>
  GET /v1/authorization?client_id=<u></u>AAA&scope=readinglist&<u></u>keyfetch=PUBKEY<br>
<br>
<br>
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.<br></blockquote><div><br></div><div>A little off topic, but what happens if the user wants to convey "you can only see one key" or "no keys at all"?<br><br></div><div><snip><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
  * There's a whole lot of potential for crypto to be done wrong<br>
    here!  It's pretty scary stuff and smells kinda fragile.<br>
<br>
<br>
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?<br></blockquote><div><br></div><div>I'm a little concerned about doing a lot of public-key crypto in the fxa-content-server.  It's getting ... unwieldy.<br><br></div><div>A few crypto nits:<br><br></div><div>* specing key interchange and encrypted forms is annoying.  I reverse engineered jwCrypto for Firefox for Android's FxA implementation.  Is JW{E,T,?} ready yet?<br><br></div><div>* is there any request and response integrity at the fxa-oauth protocol level?  I'm going to assume encrypt() is encrypt-and-HMAC throughout.  How does the relier know the keys in /authenticate are the same as those in /token?  Is this kind of state something that reliers expect to maintain already?<br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
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.<br>
<br>
Details aside, will this sort of enhanced OAuth dance give us what we want?<br>
<br>
Does this sound appropriately terrifying to everyone?<br></blockquote><div><br></div><div>Yes!  But this is also the most though-provoking email thread I've participated on in a month, so thank you for preparing the proposal.<br><br></div><div>Nick</div></div><br></div></div></div>