Bug 1835710 - Cancel off-thread JIT compilation before changing nursery allocation...
[gecko.git] / services / fxaccounts / Credentials.sys.mjs
blob977f57de2f027639d0c76245d4aad0f07e2cdc3f
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /**
6  * This module implements client-side key stretching for use in Firefox
7  * Accounts account creation and login.
8  *
9  * See https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol
10  */
12 import { Log } from "resource://gre/modules/Log.sys.mjs";
14 import { CryptoUtils } from "resource://services-crypto/utils.sys.mjs";
16 import { CommonUtils } from "resource://services-common/utils.sys.mjs";
18 const PROTOCOL_VERSION = "identity.mozilla.com/picl/v1/";
19 const PBKDF2_ROUNDS = 1000;
20 const STRETCHED_PW_LENGTH_BYTES = 32;
21 const HKDF_SALT = CommonUtils.hexToBytes("00");
22 const HKDF_LENGTH = 32;
24 // loglevel preference should be one of: "FATAL", "ERROR", "WARN", "INFO",
25 // "CONFIG", "DEBUG", "TRACE" or "ALL". We will be logging error messages by
26 // default.
27 const PREF_LOG_LEVEL = "identity.fxaccounts.loglevel";
28 let LOG_LEVEL = Log.Level.Error;
29 try {
30   LOG_LEVEL =
31     Services.prefs.getPrefType(PREF_LOG_LEVEL) ==
32       Ci.nsIPrefBranch.PREF_STRING &&
33     Services.prefs.getCharPref(PREF_LOG_LEVEL);
34 } catch (e) {}
36 var log = Log.repository.getLogger("Identity.FxAccounts");
37 log.level = LOG_LEVEL;
38 log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
40 export var Credentials = Object.freeze({
41   /**
42    * Make constants accessible to tests
43    */
44   constants: {
45     PROTOCOL_VERSION,
46     PBKDF2_ROUNDS,
47     STRETCHED_PW_LENGTH_BYTES,
48     HKDF_SALT,
49     HKDF_LENGTH,
50   },
52   /**
53    * KW function from https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol
54    *
55    * keyWord derivation for use as a salt.
56    *
57    *
58    *   @param {String} context  String for use in generating salt
59    *
60    *   @return {bitArray} the salt
61    *
62    * Note that PROTOCOL_VERSION does not refer in any way to the version of the
63    * Firefox Accounts API.
64    */
65   keyWord(context) {
66     return CommonUtils.stringToBytes(PROTOCOL_VERSION + context);
67   },
69   /**
70    * KWE function from https://github.com/mozilla/fxa-auth-server/wiki/onepw-protocol
71    *
72    * keyWord extended with a name and an email.
73    *
74    *   @param {String} name The name of the salt
75    *   @param {String} email The email of the user.
76    *
77    *   @return {bitArray} the salt combination with the namespace
78    *
79    * Note that PROTOCOL_VERSION does not refer in any way to the version of the
80    * Firefox Accounts API.
81    */
82   keyWordExtended(name, email) {
83     return CommonUtils.stringToBytes(PROTOCOL_VERSION + name + ":" + email);
84   },
86   setup(emailInput, passwordInput, options = {}) {
87     return new Promise(resolve => {
88       log.debug("setup credentials for " + emailInput);
90       let hkdfSalt = options.hkdfSalt || HKDF_SALT;
91       let hkdfLength = options.hkdfLength || HKDF_LENGTH;
92       let stretchedPWLength =
93         options.stretchedPassLength || STRETCHED_PW_LENGTH_BYTES;
94       let pbkdf2Rounds = options.pbkdf2Rounds || PBKDF2_ROUNDS;
96       let result = {};
98       let password = CommonUtils.encodeUTF8(passwordInput);
99       let salt = this.keyWordExtended("quickStretch", emailInput);
101       let runnable = async () => {
102         let start = Date.now();
103         let quickStretchedPW = await CryptoUtils.pbkdf2Generate(
104           password,
105           salt,
106           pbkdf2Rounds,
107           stretchedPWLength
108         );
110         result.quickStretchedPW = quickStretchedPW;
112         result.authPW = await CryptoUtils.hkdfLegacy(
113           quickStretchedPW,
114           hkdfSalt,
115           this.keyWord("authPW"),
116           hkdfLength
117         );
119         result.unwrapBKey = await CryptoUtils.hkdfLegacy(
120           quickStretchedPW,
121           hkdfSalt,
122           this.keyWord("unwrapBkey"),
123           hkdfLength
124         );
126         log.debug("Credentials set up after " + (Date.now() - start) + " ms");
127         resolve(result);
128       };
130       Services.tm.dispatchToMainThread(runnable);
131       log.debug("Dispatched thread for credentials setup crypto work");
132     });
133   },