Hi All,
(This was a shower thought that I wanted to write down while it was in my head - comments welcome, but no action required.) In previous discussions of adding two-factor auth to FxA, we've struggled with the issue of backwards-compatibility for API consumers that don't know how to do 2FA. The standard solution here is to let the user generate one-time-use "application passwords" that can be entered into legacy systems. For example, this is how you can login to gmail in thunderbird if you have 2FA enabled: https://support.google.com/accounts/answer/185833?hl=en Things aren't so simple for us, because the password in FxA does double-duty as a source of entropy for your encryption key. I couldn't find any historical docs on a solution for this, and I recall some folks saying that we hadn't found a good solution. So apologies if we've already tread this ground before :-) But I think we could in fact make it work - the web app could generate application passwords by doing the same crypto steps as the change-password flow, but submitting the results to a different API endpoint so they're saved as an extra password, rather than replacing the existing password. Here's a strawman modeled off the change-password API: 1) Provide the current password, and get a keyfetch token: > POST /v1/password/appkey/start > { > "email": "[email protected]", > "authPW": "hashofcurrentpassword" > } . < { < "keyFetchToken": "token" < } 2) Use the keyfetchtoken to obtain current value of kB using the existing API 3) Generate a random hex string. This will be "appPW", the application password that is ultimately given to the user. 4) Do the pbkdf-ing and hashing necessary to calculate authPW from this key, and to wrap kB with it: quickStretchedPW = PBKDF(appPW, email) authPW = HKDF(quickStretchedPW, "authPW") unwrapBkey = HKDF(quickStretchedPW, "unwrapBkey") wrapKb = XOR(kB, unwrapBkey) 5) Submit these values to the server to register a new application password: > POST /v1/password/appkey/finish > Authorization: session token palaver here > { > "email": "[email protected]", > "authPW": "authPW calculated from the appPW", > "wrapKb": "wrapKb calculated from the appPW" > } . < { } 6) The server stores these in a separate table. When processing a login attempt, it first tries the password from the main accounts table, then tries any application passwords found in this additional table. 7) Present the appPW to the user to copy-paste into their legacy app. >From the perspective of a legacy device, you can enter the "appPW" instead of your account password, and it'd behave just like you entered a regular valid password. The one thing that we *couldn't* do with this flow, is store the application password in plaintext in the db, since it's equivalent in power to kB. The user would have to write it down somewhere at the time of generation, or it would be lost forever. Thoughts? Cheers, Ryan _______________________________________________ Dev-fxacct mailing list [email protected] https://mail.mozilla.org/listinfo/dev-fxacct

