diff options
Diffstat (limited to 'services/crypto/tests/unit')
-rw-r--r-- | services/crypto/tests/unit/head_helpers.js | 55 | ||||
-rw-r--r-- | services/crypto/tests/unit/test_crypto_crypt.js | 213 | ||||
-rw-r--r-- | services/crypto/tests/unit/test_crypto_deriveKey.js | 28 | ||||
-rw-r--r-- | services/crypto/tests/unit/test_crypto_random.js | 58 | ||||
-rw-r--r-- | services/crypto/tests/unit/test_load_modules.js | 16 | ||||
-rw-r--r-- | services/crypto/tests/unit/test_utils_hawk.js | 301 | ||||
-rw-r--r-- | services/crypto/tests/unit/test_utils_hkdfExpand.js | 120 | ||||
-rw-r--r-- | services/crypto/tests/unit/test_utils_httpmac.js | 69 | ||||
-rw-r--r-- | services/crypto/tests/unit/test_utils_pbkdf2.js | 162 | ||||
-rw-r--r-- | services/crypto/tests/unit/test_utils_sha1.js | 37 | ||||
-rw-r--r-- | services/crypto/tests/unit/xpcshell.ini | 20 |
11 files changed, 1079 insertions, 0 deletions
diff --git a/services/crypto/tests/unit/head_helpers.js b/services/crypto/tests/unit/head_helpers.js new file mode 100644 index 000000000..70522fc38 --- /dev/null +++ b/services/crypto/tests/unit/head_helpers.js @@ -0,0 +1,55 @@ +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cr = Components.results; +var Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +try { + // In the context of xpcshell tests, there won't be a default AppInfo + Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo); +} +catch(ex) { + +// Make sure to provide the right OS so crypto loads the right binaries +var OS = "XPCShell"; +if (mozinfo.os == "win") + OS = "WINNT"; +else if (mozinfo.os == "mac") + OS = "Darwin"; +else + OS = "Linux"; + +Cu.import("resource://testing-common/AppInfo.jsm", this); +updateAppInfo({ + name: "XPCShell", + ID: "{3e3ba16c-1675-4e88-b9c8-afef81b3d2ef}", + version: "1", + platformVersion: "", + OS: OS, +}); +} + +// Register resource alias. Normally done in SyncComponents.manifest. +function addResourceAlias() { + Cu.import("resource://gre/modules/Services.jsm"); + const resProt = Services.io.getProtocolHandler("resource") + .QueryInterface(Ci.nsIResProtocolHandler); + let uri = Services.io.newURI("resource://gre/modules/services-crypto/", + null, null); + resProt.setSubstitution("services-crypto", uri); +} +addResourceAlias(); + +/** + * Print some debug message to the console. All arguments will be printed, + * separated by spaces. + * + * @param [arg0, arg1, arg2, ...] + * Any number of arguments to print out + * @usage _("Hello World") -> prints "Hello World" + * @usage _(1, 2, 3) -> prints "1 2 3" + */ +var _ = function(some, debug, text, to) { + print(Array.slice(arguments).join(" ")); +}; diff --git a/services/crypto/tests/unit/test_crypto_crypt.js b/services/crypto/tests/unit/test_crypto_crypt.js new file mode 100644 index 000000000..fcea21d00 --- /dev/null +++ b/services/crypto/tests/unit/test_crypto_crypt.js @@ -0,0 +1,213 @@ +Cu.import("resource://services-crypto/WeaveCrypto.js"); +Cu.importGlobalProperties(['crypto']); + +var cryptoSvc = new WeaveCrypto(); + +add_task(function* test_key_memoization() { + let cryptoGlobal = cryptoSvc._getCrypto(); + let oldImport = cryptoGlobal.subtle.importKey; + if (!oldImport) { + _("Couldn't swizzle crypto.subtle.importKey; returning."); + return; + } + + let iv = cryptoSvc.generateRandomIV(); + let key = cryptoSvc.generateRandomKey(); + let c = 0; + cryptoGlobal.subtle.importKey = function(format, keyData, algo, extractable, usages) { + c++; + return oldImport.call(cryptoGlobal.subtle, format, keyData, algo, extractable, usages); + } + + // Encryption should cause a single counter increment. + do_check_eq(c, 0); + let cipherText = cryptoSvc.encrypt("Hello, world.", key, iv); + do_check_eq(c, 1); + cipherText = cryptoSvc.encrypt("Hello, world.", key, iv); + do_check_eq(c, 1); + + // ... as should decryption. + cryptoSvc.decrypt(cipherText, key, iv); + cryptoSvc.decrypt(cipherText, key, iv); + cryptoSvc.decrypt(cipherText, key, iv); + do_check_eq(c, 2); + + // Un-swizzle. + cryptoGlobal.subtle.importKey = oldImport; +}); + +// Just verify that it gets populated with the correct bytes. +add_task(function* test_makeUint8Array() { + Components.utils.import("resource://gre/modules/ctypes.jsm"); + + let item1 = cryptoSvc.makeUint8Array("abcdefghi", false); + do_check_true(item1); + for (let i = 0; i < 8; ++i) + do_check_eq(item1[i], "abcdefghi".charCodeAt(i)); +}); + +add_task(function* test_encrypt_decrypt() { + // First, do a normal run with expected usage... Generate a random key and + // iv, encrypt and decrypt a string. + var iv = cryptoSvc.generateRandomIV(); + do_check_eq(iv.length, 24); + + var key = cryptoSvc.generateRandomKey(); + do_check_eq(key.length, 44); + + var mySecret = "bacon is a vegetable"; + var cipherText = cryptoSvc.encrypt(mySecret, key, iv); + do_check_eq(cipherText.length, 44); + + var clearText = cryptoSvc.decrypt(cipherText, key, iv); + do_check_eq(clearText.length, 20); + + // Did the text survive the encryption round-trip? + do_check_eq(clearText, mySecret); + do_check_neq(cipherText, mySecret); // just to be explicit + + + // Do some more tests with a fixed key/iv, to check for reproducable results. + key = "St1tFCor7vQEJNug/465dQ=="; + iv = "oLjkfrLIOnK2bDRvW4kXYA=="; + + _("Testing small IV."); + mySecret = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo="; + let shortiv = "YWJj"; + let err; + try { + cryptoSvc.encrypt(mySecret, key, shortiv); + } catch (ex) { + err = ex; + } + do_check_true(!!err); + + _("Testing long IV."); + let longiv = "gsgLRDaxWvIfKt75RjuvFWERt83FFsY2A0TW+0b2iVk="; + try { + cryptoSvc.encrypt(mySecret, key, longiv); + } catch (ex) { + err = ex; + } + do_check_true(!!err); + + // Test small input sizes + mySecret = ""; + cipherText = cryptoSvc.encrypt(mySecret, key, iv); + clearText = cryptoSvc.decrypt(cipherText, key, iv); + do_check_eq(cipherText, "OGQjp6mK1a3fs9k9Ml4L3w=="); + do_check_eq(clearText, mySecret); + + mySecret = "x"; + cipherText = cryptoSvc.encrypt(mySecret, key, iv); + clearText = cryptoSvc.decrypt(cipherText, key, iv); + do_check_eq(cipherText, "96iMl4vhOxFUW/lVHHzVqg=="); + do_check_eq(clearText, mySecret); + + mySecret = "xx"; + cipherText = cryptoSvc.encrypt(mySecret, key, iv); + clearText = cryptoSvc.decrypt(cipherText, key, iv); + do_check_eq(cipherText, "olpPbETRYROCSqFWcH2SWg=="); + do_check_eq(clearText, mySecret); + + mySecret = "xxx"; + cipherText = cryptoSvc.encrypt(mySecret, key, iv); + clearText = cryptoSvc.decrypt(cipherText, key, iv); + do_check_eq(cipherText, "rRbpHGyVSZizLX/x43Wm+Q=="); + do_check_eq(clearText, mySecret); + + mySecret = "xxxx"; + cipherText = cryptoSvc.encrypt(mySecret, key, iv); + clearText = cryptoSvc.decrypt(cipherText, key, iv); + do_check_eq(cipherText, "HeC7miVGDcpxae9RmiIKAw=="); + do_check_eq(clearText, mySecret); + + // Test non-ascii input + // ("testuser1" using similar-looking glyphs) + mySecret = String.fromCharCode(355, 277, 349, 357, 533, 537, 101, 345, 185); + cipherText = cryptoSvc.encrypt(mySecret, key, iv); + clearText = cryptoSvc.decrypt(cipherText, key, iv); + do_check_eq(cipherText, "Pj4ixByXoH3SU3JkOXaEKPgwRAWplAWFLQZkpJd5Kr4="); + do_check_eq(clearText, mySecret); + + // Tests input spanning a block boundary (AES block size is 16 bytes) + mySecret = "123456789012345"; + cipherText = cryptoSvc.encrypt(mySecret, key, iv); + clearText = cryptoSvc.decrypt(cipherText, key, iv); + do_check_eq(cipherText, "e6c5hwphe45/3VN/M0bMUA=="); + do_check_eq(clearText, mySecret); + + mySecret = "1234567890123456"; + cipherText = cryptoSvc.encrypt(mySecret, key, iv); + clearText = cryptoSvc.decrypt(cipherText, key, iv); + do_check_eq(cipherText, "V6aaOZw8pWlYkoIHNkhsP1JOIQF87E2vTUvBUQnyV04="); + do_check_eq(clearText, mySecret); + + mySecret = "12345678901234567"; + cipherText = cryptoSvc.encrypt(mySecret, key, iv); + clearText = cryptoSvc.decrypt(cipherText, key, iv); + do_check_eq(cipherText, "V6aaOZw8pWlYkoIHNkhsP5GvxWJ9+GIAS6lXw+5fHTI="); + do_check_eq(clearText, mySecret); + + + key = "iz35tuIMq4/H+IYw2KTgow=="; + iv = "TJYrvva2KxvkM8hvOIvWp3=="; + mySecret = "i like pie"; + + cipherText = cryptoSvc.encrypt(mySecret, key, iv); + clearText = cryptoSvc.decrypt(cipherText, key, iv); + do_check_eq(cipherText, "DLGx8BWqSCLGG7i/xwvvxg=="); + do_check_eq(clearText, mySecret); + + key = "c5hG3YG+NC61FFy8NOHQak1ZhMEWO79bwiAfar2euzI="; + iv = "gsgLRDaxWvIfKt75RjuvFW=="; + mySecret = "i like pie"; + + cipherText = cryptoSvc.encrypt(mySecret, key, iv); + clearText = cryptoSvc.decrypt(cipherText, key, iv); + do_check_eq(cipherText, "o+ADtdMd8ubzNWurS6jt0Q=="); + do_check_eq(clearText, mySecret); + + key = "St1tFCor7vQEJNug/465dQ=="; + iv = "oLjkfrLIOnK2bDRvW4kXYA=="; + mySecret = "does thunder read testcases?"; + cipherText = cryptoSvc.encrypt(mySecret, key, iv); + do_check_eq(cipherText, "T6fik9Ros+DB2ablH9zZ8FWZ0xm/szSwJjIHZu7sjPs="); + + var badkey = "badkeybadkeybadkeybadk=="; + var badiv = "badivbadivbadivbadivbad="; + var badcipher = "crapinputcrapinputcrapinputcrapinputcrapinp="; + var failure; + + try { + failure = false; + clearText = cryptoSvc.decrypt(cipherText, badkey, iv); + } catch (e) { + failure = true; + } + do_check_true(failure); + + try { + failure = false; + clearText = cryptoSvc.decrypt(cipherText, key, badiv); + } catch (e) { + failure = true; + } + do_check_true(failure); + + try { + failure = false; + clearText = cryptoSvc.decrypt(cipherText, badkey, badiv); + } catch (e) { + failure = true; + } + do_check_true(failure); + + try { + failure = false; + clearText = cryptoSvc.decrypt(badcipher, key, iv); + } catch (e) { + failure = true; + } + do_check_true(failure); +}); diff --git a/services/crypto/tests/unit/test_crypto_deriveKey.js b/services/crypto/tests/unit/test_crypto_deriveKey.js new file mode 100644 index 000000000..00af474cb --- /dev/null +++ b/services/crypto/tests/unit/test_crypto_deriveKey.js @@ -0,0 +1,28 @@ +Components.utils.import("resource://services-crypto/WeaveCrypto.js"); + +function run_test() { + let cryptoSvc = new WeaveCrypto(); + // Extracted from test_utils_deriveKey. + let pp = "secret phrase"; + let salt = "RE5YUHpQcGl3bg=="; // btoa("DNXPzPpiwn") + + // 16-byte, extract key data. + let k = cryptoSvc.deriveKeyFromPassphrase(pp, salt, 16); + do_check_eq(16, k.length); + do_check_eq(btoa(k), "d2zG0d2cBfXnRwMUGyMwyg=="); + + // Test different key lengths. + k = cryptoSvc.deriveKeyFromPassphrase(pp, salt, 32); + do_check_eq(32, k.length); + do_check_eq(btoa(k), "d2zG0d2cBfXnRwMUGyMwyroRXtnrSIeLwSDvReSfcyA="); + let encKey = btoa(k); + + // Test via encryption. + let iv = cryptoSvc.generateRandomIV(); + do_check_eq(cryptoSvc.decrypt(cryptoSvc.encrypt("bacon", encKey, iv), encKey, iv), "bacon"); + + // Test default length (32). + k = cryptoSvc.deriveKeyFromPassphrase(pp, salt); + do_check_eq(32, k.length); + do_check_eq(encKey, btoa(k)); +} diff --git a/services/crypto/tests/unit/test_crypto_random.js b/services/crypto/tests/unit/test_crypto_random.js new file mode 100644 index 000000000..46b4c7f82 --- /dev/null +++ b/services/crypto/tests/unit/test_crypto_random.js @@ -0,0 +1,58 @@ +var WeaveCryptoModule = Cu.import("resource://services-crypto/WeaveCrypto.js"); + +var cryptoSvc = new WeaveCrypto(); + +function run_test() { + if (this.gczeal) { + _("Running crypto random tests with gczeal(2)."); + gczeal(2); + } + + // Test salt generation. + var salt; + + salt = cryptoSvc.generateRandomBytes(0); + do_check_eq(salt.length, 0); + salt = cryptoSvc.generateRandomBytes(1); + do_check_eq(salt.length, 4); + salt = cryptoSvc.generateRandomBytes(2); + do_check_eq(salt.length, 4); + salt = cryptoSvc.generateRandomBytes(3); + do_check_eq(salt.length, 4); + salt = cryptoSvc.generateRandomBytes(4); + do_check_eq(salt.length, 8); + salt = cryptoSvc.generateRandomBytes(8); + do_check_eq(salt.length, 12); + + // sanity check to make sure salts seem random + var salt2 = cryptoSvc.generateRandomBytes(8); + do_check_eq(salt2.length, 12); + do_check_neq(salt, salt2); + + salt = cryptoSvc.generateRandomBytes(1024); + do_check_eq(salt.length, 1368); + salt = cryptoSvc.generateRandomBytes(16); + do_check_eq(salt.length, 24); + + + // Test random key generation + var keydata, keydata2, iv; + + keydata = cryptoSvc.generateRandomKey(); + do_check_eq(keydata.length, 44); + keydata2 = cryptoSvc.generateRandomKey(); + do_check_neq(keydata, keydata2); // sanity check for randomness + iv = cryptoSvc.generateRandomIV(); + do_check_eq(iv.length, 24); + + cryptoSvc.algorithm = WeaveCryptoModule.AES_256_CBC; + keydata = cryptoSvc.generateRandomKey(); + do_check_eq(keydata.length, 44); + keydata2 = cryptoSvc.generateRandomKey(); + do_check_neq(keydata, keydata2); // sanity check for randomness + iv = cryptoSvc.generateRandomIV(); + do_check_eq(iv.length, 24); + + if (this.gczeal) + gczeal(0); +} diff --git a/services/crypto/tests/unit/test_load_modules.js b/services/crypto/tests/unit/test_load_modules.js new file mode 100644 index 000000000..50f5d709c --- /dev/null +++ b/services/crypto/tests/unit/test_load_modules.js @@ -0,0 +1,16 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +const modules = [ + "utils.js", + "WeaveCrypto.js", +]; + +function run_test() { + for (let m of modules) { + let resource = "resource://services-crypto/" + m; + _("Attempting to import: " + resource); + Components.utils.import(resource, {}); + } +} + diff --git a/services/crypto/tests/unit/test_utils_hawk.js b/services/crypto/tests/unit/test_utils_hawk.js new file mode 100644 index 000000000..0a2cf6c31 --- /dev/null +++ b/services/crypto/tests/unit/test_utils_hawk.js @@ -0,0 +1,301 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://services-common/utils.js"); +Cu.import("resource://services-crypto/utils.js"); + +function run_test() { + initTestLogging(); + + run_next_test(); +} + +add_test(function test_hawk() { + let compute = CryptoUtils.computeHAWK; + + // vectors copied from the HAWK (node.js) tests + let credentials_sha1 = { + id: "123456", + key: "2983d45yun89q", + algorithm: "sha1", + }; + + let method = "POST"; + let ts = 1353809207; + let nonce = "Ygvqdz"; + let result; + + let uri_http = CommonUtils.makeURI("http://example.net/somewhere/over/the/rainbow"); + let sha1_opts = { credentials: credentials_sha1, + ext: "Bazinga!", + ts: ts, + nonce: nonce, + payload: "something to write about", + }; + result = compute(uri_http, method, sha1_opts); + + // The HAWK spec uses non-urlsafe base64 (+/) for its output MAC string. + do_check_eq(result.field, + 'Hawk id="123456", ts="1353809207", nonce="Ygvqdz", ' + + 'hash="bsvY3IfUllw6V5rvk4tStEvpBhE=", ext="Bazinga!", ' + + 'mac="qbf1ZPG/r/e06F4ht+T77LXi5vw="' + ); + do_check_eq(result.artifacts.ts, ts); + do_check_eq(result.artifacts.nonce, nonce); + do_check_eq(result.artifacts.method, method); + do_check_eq(result.artifacts.resource, "/somewhere/over/the/rainbow"); + do_check_eq(result.artifacts.host, "example.net"); + do_check_eq(result.artifacts.port, 80); + // artifacts.hash is the *payload* hash, not the overall request MAC. + do_check_eq(result.artifacts.hash, "bsvY3IfUllw6V5rvk4tStEvpBhE="); + do_check_eq(result.artifacts.ext, "Bazinga!"); + + let credentials_sha256 = { + id: "123456", + key: "2983d45yun89q", + algorithm: "sha256", + }; + + let uri_https = CommonUtils.makeURI("https://example.net/somewhere/over/the/rainbow"); + let sha256_opts = { credentials: credentials_sha256, + ext: "Bazinga!", + ts: ts, + nonce: nonce, + payload: "something to write about", + contentType: "text/plain", + }; + + result = compute(uri_https, method, sha256_opts); + do_check_eq(result.field, + 'Hawk id="123456", ts="1353809207", nonce="Ygvqdz", ' + + 'hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", ' + + 'ext="Bazinga!", ' + + 'mac="q1CwFoSHzPZSkbIvl0oYlD+91rBUEvFk763nMjMndj8="' + ); + do_check_eq(result.artifacts.ts, ts); + do_check_eq(result.artifacts.nonce, nonce); + do_check_eq(result.artifacts.method, method); + do_check_eq(result.artifacts.resource, "/somewhere/over/the/rainbow"); + do_check_eq(result.artifacts.host, "example.net"); + do_check_eq(result.artifacts.port, 443); + do_check_eq(result.artifacts.hash, "2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY="); + do_check_eq(result.artifacts.ext, "Bazinga!"); + + let sha256_opts_noext = { credentials: credentials_sha256, + ts: ts, + nonce: nonce, + payload: "something to write about", + contentType: "text/plain", + }; + result = compute(uri_https, method, sha256_opts_noext); + do_check_eq(result.field, + 'Hawk id="123456", ts="1353809207", nonce="Ygvqdz", ' + + 'hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", ' + + 'mac="HTgtd0jPI6E4izx8e4OHdO36q00xFCU0FolNq3RiCYs="' + ); + do_check_eq(result.artifacts.ts, ts); + do_check_eq(result.artifacts.nonce, nonce); + do_check_eq(result.artifacts.method, method); + do_check_eq(result.artifacts.resource, "/somewhere/over/the/rainbow"); + do_check_eq(result.artifacts.host, "example.net"); + do_check_eq(result.artifacts.port, 443); + do_check_eq(result.artifacts.hash, "2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY="); + + /* Leaving optional fields out should work, although of course then we can't + * assert much about the resulting hashes. The resulting header should look + * roughly like: + * Hawk id="123456", ts="1378764955", nonce="QkynqsrS44M=", mac="/C5NsoAs2fVn+d/I5wMfwe2Gr1MZyAJ6pFyDHG4Gf9U=" + */ + + result = compute(uri_https, method, { credentials: credentials_sha256 }); + let fields = result.field.split(" "); + do_check_eq(fields[0], "Hawk"); + do_check_eq(fields[1], 'id="123456",'); // from creds.id + do_check_true(fields[2].startsWith('ts="')); + /* The HAWK spec calls for seconds-since-epoch, not ms-since-epoch. + * Warning: this test will fail in the year 33658, and for time travellers + * who journey earlier than 2001. Please plan accordingly. */ + do_check_true(result.artifacts.ts > 1000*1000*1000); + do_check_true(result.artifacts.ts < 1000*1000*1000*1000); + do_check_true(fields[3].startsWith('nonce="')); + do_check_eq(fields[3].length, ('nonce="12345678901=",').length); + do_check_eq(result.artifacts.nonce.length, ("12345678901=").length); + + let result2 = compute(uri_https, method, { credentials: credentials_sha256 }); + do_check_neq(result.artifacts.nonce, result2.artifacts.nonce); + + /* Using an upper-case URI hostname shouldn't affect the hash. */ + + let uri_https_upper = CommonUtils.makeURI("https://EXAMPLE.NET/somewhere/over/the/rainbow"); + result = compute(uri_https_upper, method, sha256_opts); + do_check_eq(result.field, + 'Hawk id="123456", ts="1353809207", nonce="Ygvqdz", ' + + 'hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", ' + + 'ext="Bazinga!", ' + + 'mac="q1CwFoSHzPZSkbIvl0oYlD+91rBUEvFk763nMjMndj8="' + ); + + /* Using a lower-case method name shouldn't affect the hash. */ + result = compute(uri_https_upper, method.toLowerCase(), sha256_opts); + do_check_eq(result.field, + 'Hawk id="123456", ts="1353809207", nonce="Ygvqdz", ' + + 'hash="2QfCt3GuY9HQnHWyWD3wX68ZOKbynqlfYmuO2ZBRqtY=", ' + + 'ext="Bazinga!", ' + + 'mac="q1CwFoSHzPZSkbIvl0oYlD+91rBUEvFk763nMjMndj8="' + ); + + /* The localtimeOffsetMsec field should be honored. HAWK uses this to + * compensate for clock skew between client and server: if the request is + * rejected with a timestamp out-of-range error, the error includes the + * server's time, and the client computes its clock offset and tries again. + * Clients can remember this offset for a while. + */ + + result = compute(uri_https, method, { credentials: credentials_sha256, + now: 1378848968650, + }); + do_check_eq(result.artifacts.ts, 1378848968); + + result = compute(uri_https, method, { credentials: credentials_sha256, + now: 1378848968650, + localtimeOffsetMsec: 1000*1000, + }); + do_check_eq(result.artifacts.ts, 1378848968 + 1000); + + /* Search/query-args in URIs should be included in the hash. */ + let makeURI = CommonUtils.makeURI; + result = compute(makeURI("http://example.net/path"), method, sha256_opts); + do_check_eq(result.artifacts.resource, "/path"); + do_check_eq(result.artifacts.mac, "WyKHJjWaeYt8aJD+H9UeCWc0Y9C+07ooTmrcrOW4MPI="); + + result = compute(makeURI("http://example.net/path/"), method, sha256_opts); + do_check_eq(result.artifacts.resource, "/path/"); + do_check_eq(result.artifacts.mac, "xAYp2MgZQFvTKJT9u8nsvMjshCRRkuaeYqQbYSFp9Qw="); + + result = compute(makeURI("http://example.net/path?query=search"), method, sha256_opts); + do_check_eq(result.artifacts.resource, "/path?query=search"); + do_check_eq(result.artifacts.mac, "C06a8pip2rA4QkBiosEmC32WcgFcW/R5SQC6kUWyqho="); + + /* Test handling of the payload, which is supposed to be a bytestring + (String with codepoints from U+0000 to U+00FF, pre-encoded). */ + + result = compute(makeURI("http://example.net/path"), method, + { credentials: credentials_sha256, + ts: 1353809207, + nonce: "Ygvqdz", + }); + do_check_eq(result.artifacts.hash, undefined); + do_check_eq(result.artifacts.mac, "S3f8E4hAURAqJxOlsYugkPZxLoRYrClgbSQ/3FmKMbY="); + + // Empty payload changes nothing. + result = compute(makeURI("http://example.net/path"), method, + { credentials: credentials_sha256, + ts: 1353809207, + nonce: "Ygvqdz", + payload: null, + }); + do_check_eq(result.artifacts.hash, undefined); + do_check_eq(result.artifacts.mac, "S3f8E4hAURAqJxOlsYugkPZxLoRYrClgbSQ/3FmKMbY="); + + result = compute(makeURI("http://example.net/path"), method, + { credentials: credentials_sha256, + ts: 1353809207, + nonce: "Ygvqdz", + payload: "hello", + }); + do_check_eq(result.artifacts.hash, "uZJnFj0XVBA6Rs1hEvdIDf8NraM0qRNXdFbR3NEQbVA="); + do_check_eq(result.artifacts.mac, "pLsHHzngIn5CTJhWBtBr+BezUFvdd/IadpTp/FYVIRM="); + + // update, utf-8 payload + result = compute(makeURI("http://example.net/path"), method, + { credentials: credentials_sha256, + ts: 1353809207, + nonce: "Ygvqdz", + payload: "andré@example.org", // non-ASCII + }); + do_check_eq(result.artifacts.hash, "66DiyapJ0oGgj09IXWdMv8VCg9xk0PL5RqX7bNnQW2k="); + do_check_eq(result.artifacts.mac, "2B++3x5xfHEZbPZGDiK3IwfPZctkV4DUr2ORg1vIHvk="); + + /* If "hash" is provided, "payload" is ignored. */ + result = compute(makeURI("http://example.net/path"), method, + { credentials: credentials_sha256, + ts: 1353809207, + nonce: "Ygvqdz", + hash: "66DiyapJ0oGgj09IXWdMv8VCg9xk0PL5RqX7bNnQW2k=", + payload: "something else", + }); + do_check_eq(result.artifacts.hash, "66DiyapJ0oGgj09IXWdMv8VCg9xk0PL5RqX7bNnQW2k="); + do_check_eq(result.artifacts.mac, "2B++3x5xfHEZbPZGDiK3IwfPZctkV4DUr2ORg1vIHvk="); + + // the payload "hash" is also non-urlsafe base64 (+/) + result = compute(makeURI("http://example.net/path"), method, + { credentials: credentials_sha256, + ts: 1353809207, + nonce: "Ygvqdz", + payload: "something else", + }); + do_check_eq(result.artifacts.hash, "lERFXr/IKOaAoYw+eBseDUSwmqZTX0uKZpcWLxsdzt8="); + do_check_eq(result.artifacts.mac, "jiZuhsac35oD7IdcblhFncBr8tJFHcwWLr8NIYWr9PQ="); + + /* Test non-ascii hostname. HAWK (via the node.js "url" module) punycodes + * "ëxample.net" into "xn--xample-ova.net" before hashing. I still think + * punycode was a bad joke that got out of the lab and into a spec. + */ + + result = compute(makeURI("http://ëxample.net/path"), method, + { credentials: credentials_sha256, + ts: 1353809207, + nonce: "Ygvqdz", + }); + do_check_eq(result.artifacts.mac, "pILiHl1q8bbNQIdaaLwAFyaFmDU70MGehFuCs3AA5M0="); + do_check_eq(result.artifacts.host, "xn--xample-ova.net"); + + result = compute(makeURI("http://example.net/path"), method, + { credentials: credentials_sha256, + ts: 1353809207, + nonce: "Ygvqdz", + ext: "backslash=\\ quote=\" EOF", + }); + do_check_eq(result.artifacts.mac, "BEMW76lwaJlPX4E/dajF970T6+GzWvaeyLzUt8eOTOc="); + do_check_eq(result.field, 'Hawk id="123456", ts="1353809207", nonce="Ygvqdz", ext="backslash=\\\\ quote=\\\" EOF", mac="BEMW76lwaJlPX4E/dajF970T6+GzWvaeyLzUt8eOTOc="'); + + result = compute(makeURI("http://example.net:1234/path"), method, + { credentials: credentials_sha256, + ts: 1353809207, + nonce: "Ygvqdz", + }); + do_check_eq(result.artifacts.mac, "6D3JSFDtozuq8QvJTNUc1JzeCfy6h5oRvlhmSTPv6LE="); + do_check_eq(result.field, 'Hawk id="123456", ts="1353809207", nonce="Ygvqdz", mac="6D3JSFDtozuq8QvJTNUc1JzeCfy6h5oRvlhmSTPv6LE="'); + + /* HAWK (the node.js library) uses a URL parser which stores the "port" + * field as a string, but makeURI() gives us an integer. So we'll diverge + * on ports with a leading zero. This test vector would fail on the node.js + * library (HAWK-1.1.1), where they get a MAC of + * "T+GcAsDO8GRHIvZLeepSvXLwDlFJugcZroAy9+uAtcw=". I think HAWK should be + * updated to do what we do here, so port="01234" should get the same hash + * as port="1234". + */ + result = compute(makeURI("http://example.net:01234/path"), method, + { credentials: credentials_sha256, + ts: 1353809207, + nonce: "Ygvqdz", + }); + do_check_eq(result.artifacts.mac, "6D3JSFDtozuq8QvJTNUc1JzeCfy6h5oRvlhmSTPv6LE="); + do_check_eq(result.field, 'Hawk id="123456", ts="1353809207", nonce="Ygvqdz", mac="6D3JSFDtozuq8QvJTNUc1JzeCfy6h5oRvlhmSTPv6LE="'); + + run_next_test(); +}); + + +add_test(function test_strip_header_attributes() { + let strip = CryptoUtils.stripHeaderAttributes; + + do_check_eq(strip(undefined), ""); + do_check_eq(strip("text/plain"), "text/plain"); + do_check_eq(strip("TEXT/PLAIN"), "text/plain"); + do_check_eq(strip(" text/plain "), "text/plain"); + do_check_eq(strip("text/plain ; charset=utf-8 "), "text/plain"); + + run_next_test(); +}); diff --git a/services/crypto/tests/unit/test_utils_hkdfExpand.js b/services/crypto/tests/unit/test_utils_hkdfExpand.js new file mode 100644 index 000000000..4b4b21900 --- /dev/null +++ b/services/crypto/tests/unit/test_utils_hkdfExpand.js @@ -0,0 +1,120 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +Cu.import("resource://services-common/utils.js"); +Cu.import("resource://services-crypto/utils.js"); + +// Test vectors from RFC 5869 + +// Test case 1 + +var tc1 = { + IKM: "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + salt: "000102030405060708090a0b0c", + info: "f0f1f2f3f4f5f6f7f8f9", + L: 42, + PRK: "077709362c2e32df0ddc3f0dc47bba63" + + "90b6c73bb50f9c3122ec844ad7c2b3e5", + OKM: "3cb25f25faacd57a90434f64d0362f2a" + + "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" + + "34007208d5b887185865" +}; + +// Test case 2 + +var tc2 = { + IKM: "000102030405060708090a0b0c0d0e0f" + + "101112131415161718191a1b1c1d1e1f" + + "202122232425262728292a2b2c2d2e2f" + + "303132333435363738393a3b3c3d3e3f" + + "404142434445464748494a4b4c4d4e4f", + salt: "606162636465666768696a6b6c6d6e6f" + + "707172737475767778797a7b7c7d7e7f" + + "808182838485868788898a8b8c8d8e8f" + + "909192939495969798999a9b9c9d9e9f" + + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", + info: "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + L: 82, + PRK: "06a6b88c5853361a06104c9ceb35b45c" + + "ef760014904671014a193f40c15fc244", + OKM: "b11e398dc80327a1c8e7f78c596a4934" + + "4f012eda2d4efad8a050cc4c19afa97c" + + "59045a99cac7827271cb41c65e590e09" + + "da3275600c2f09b8367793a9aca3db71" + + "cc30c58179ec3e87c14c01d5c1f3434f" + + "1d87" +}; + +// Test case 3 + +var tc3 = { + IKM: "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + salt: "", + info: "", + L: 42, + PRK: "19ef24a32c717b167f33a91d6f648bdf" + + "96596776afdb6377ac434c1c293ccb04", + OKM: "8da4e775a563c18f715f802a063c5a31" + + "b8a11f5c5ee1879ec3454e5f3c738d2d" + + "9d201395faa4b61a96c8" +}; + +function sha256HMAC(message, key) { + let h = CryptoUtils.makeHMACHasher(Ci.nsICryptoHMAC.SHA256, key); + return CryptoUtils.digestBytes(message, h); +} + +function _hexToString(hex) { + let ret = ""; + if (hex.length % 2 != 0) { + return false; + } + + for (let i = 0; i < hex.length; i += 2) { + let cur = hex[i] + hex[i + 1]; + ret += String.fromCharCode(parseInt(cur, 16)); + } + return ret; +} + +function extract_hex(salt, ikm) { + salt = _hexToString(salt); + ikm = _hexToString(ikm); + return CommonUtils.bytesAsHex(sha256HMAC(ikm, CryptoUtils.makeHMACKey(salt))); +} + +function expand_hex(prk, info, len) { + prk = _hexToString(prk); + info = _hexToString(info); + return CommonUtils.bytesAsHex(CryptoUtils.hkdfExpand(prk, info, len)); +} + +function hkdf_hex(ikm, salt, info, len) { + ikm = _hexToString(ikm); + if (salt) + salt = _hexToString(salt); + info = _hexToString(info); + return CommonUtils.bytesAsHex(CryptoUtils.hkdf(ikm, salt, info, len)); +} + +function run_test() { + _("Verifying Test Case 1"); + do_check_eq(extract_hex(tc1.salt, tc1.IKM), tc1.PRK); + do_check_eq(expand_hex(tc1.PRK, tc1.info, tc1.L), tc1.OKM); + do_check_eq(hkdf_hex(tc1.IKM, tc1.salt, tc1.info, tc1.L), tc1.OKM); + + _("Verifying Test Case 2"); + do_check_eq(extract_hex(tc2.salt, tc2.IKM), tc2.PRK); + do_check_eq(expand_hex(tc2.PRK, tc2.info, tc2.L), tc2.OKM); + do_check_eq(hkdf_hex(tc2.IKM, tc2.salt, tc2.info, tc2.L), tc2.OKM); + + _("Verifying Test Case 3"); + do_check_eq(extract_hex(tc3.salt, tc3.IKM), tc3.PRK); + do_check_eq(expand_hex(tc3.PRK, tc3.info, tc3.L), tc3.OKM); + do_check_eq(hkdf_hex(tc3.IKM, tc3.salt, tc3.info, tc3.L), tc3.OKM); + do_check_eq(hkdf_hex(tc3.IKM, undefined, tc3.info, tc3.L), tc3.OKM); +} diff --git a/services/crypto/tests/unit/test_utils_httpmac.js b/services/crypto/tests/unit/test_utils_httpmac.js new file mode 100644 index 000000000..67b337373 --- /dev/null +++ b/services/crypto/tests/unit/test_utils_httpmac.js @@ -0,0 +1,69 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://services-common/utils.js"); +Cu.import("resource://services-crypto/utils.js"); + +function run_test() { + initTestLogging(); + + run_next_test(); +} + +add_test(function test_sha1() { + _("Ensure HTTP MAC SHA1 generation works as expected."); + + let id = "vmo1txkttblmn51u2p3zk2xiy16hgvm5ok8qiv1yyi86ffjzy9zj0ez9x6wnvbx7"; + let key = "b8u1cc5iiio5o319og7hh8faf2gi5ym4aq0zwf112cv1287an65fudu5zj7zo7dz"; + let ts = 1329181221; + let method = "GET"; + let nonce = "wGX71"; + let uri = CommonUtils.makeURI("http://10.250.2.176/alias/"); + + let result = CryptoUtils.computeHTTPMACSHA1(id, key, method, uri, + {ts: ts, nonce: nonce}); + + do_check_eq(btoa(result.mac), "jzh5chjQc2zFEvLbyHnPdX11Yck="); + + do_check_eq(result.getHeader(), + 'MAC id="vmo1txkttblmn51u2p3zk2xiy16hgvm5ok8qiv1yyi86ffjzy9zj0ez9x6wnvbx7", ' + + 'ts="1329181221", nonce="wGX71", mac="jzh5chjQc2zFEvLbyHnPdX11Yck="'); + + let ext = "EXTRA DATA; foo,bar=1"; + + result = CryptoUtils.computeHTTPMACSHA1(id, key, method, uri, + {ts: ts, nonce: nonce, ext: ext}); + do_check_eq(btoa(result.mac), "bNf4Fnt5k6DnhmyipLPkuZroH68="); + do_check_eq(result.getHeader(), + 'MAC id="vmo1txkttblmn51u2p3zk2xiy16hgvm5ok8qiv1yyi86ffjzy9zj0ez9x6wnvbx7", ' + + 'ts="1329181221", nonce="wGX71", mac="bNf4Fnt5k6DnhmyipLPkuZroH68=", ' + + 'ext="EXTRA DATA; foo,bar=1"'); + + run_next_test(); +}); + +add_test(function test_nonce_length() { + _("Ensure custom nonce lengths are honoured."); + + function get_mac(length) { + let uri = CommonUtils.makeURI("http://example.com/"); + return CryptoUtils.computeHTTPMACSHA1("foo", "bar", "GET", uri, { + nonce_bytes: length + }); + } + + let result = get_mac(12); + do_check_eq(12, atob(result.nonce).length); + + result = get_mac(2); + do_check_eq(2, atob(result.nonce).length); + + result = get_mac(0); + do_check_eq(8, atob(result.nonce).length); + + result = get_mac(-1); + do_check_eq(8, atob(result.nonce).length); + + run_next_test(); +}); diff --git a/services/crypto/tests/unit/test_utils_pbkdf2.js b/services/crypto/tests/unit/test_utils_pbkdf2.js new file mode 100644 index 000000000..7313819ec --- /dev/null +++ b/services/crypto/tests/unit/test_utils_pbkdf2.js @@ -0,0 +1,162 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// XXX until bug 937114 is fixed +Cu.importGlobalProperties(['btoa']); +Cu.import("resource://services-crypto/utils.js"); +Cu.import("resource://services-common/utils.js"); + +var {bytesAsHex: b2h} = CommonUtils; + +function run_test() { + run_next_test(); +} + +add_task(function test_pbkdf2() { + let symmKey16 = CryptoUtils.pbkdf2Generate("secret phrase", "DNXPzPpiwn", 4096, 16); + do_check_eq(symmKey16.length, 16); + do_check_eq(btoa(symmKey16), "d2zG0d2cBfXnRwMUGyMwyg=="); + do_check_eq(CommonUtils.encodeBase32(symmKey16), "O5WMNUO5TQC7LZ2HAMKBWIZQZI======"); + let symmKey32 = CryptoUtils.pbkdf2Generate("passphrase", "salt", 4096, 32); + do_check_eq(symmKey32.length, 32); +}); + +// http://tools.ietf.org/html/rfc6070 +// PBKDF2 HMAC-SHA1 Test Vectors +add_task(function test_pbkdf2_hmac_sha1() { + let pbkdf2 = CryptoUtils.pbkdf2Generate; + let vectors = [ + {P: "password", // (8 octets) + S: "salt", // (4 octets) + c: 1, + dkLen: 20, + DK: h("0c 60 c8 0f 96 1f 0e 71"+ + "f3 a9 b5 24 af 60 12 06"+ + "2f e0 37 a6"), // (20 octets) + }, + + {P: "password", // (8 octets) + S: "salt", // (4 octets) + c: 2, + dkLen: 20, + DK: h("ea 6c 01 4d c7 2d 6f 8c"+ + "cd 1e d9 2a ce 1d 41 f0"+ + "d8 de 89 57"), // (20 octets) + }, + + {P: "password", // (8 octets) + S: "salt", // (4 octets) + c: 4096, + dkLen: 20, + DK: h("4b 00 79 01 b7 65 48 9a"+ + "be ad 49 d9 26 f7 21 d0"+ + "65 a4 29 c1"), // (20 octets) + }, + + // XXX Uncomment the following test after Bug 968567 lands + // + // XXX As it stands, I estimate that the CryptoUtils implementation will + // take approximately 16 hours in my 2.3GHz MacBook to perform this many + // rounds. + // + // {P: "password", // (8 octets) + // S: "salt" // (4 octets) + // c: 16777216, + // dkLen = 20, + // DK: h("ee fe 3d 61 cd 4d a4 e4"+ + // "e9 94 5b 3d 6b a2 15 8c"+ + // "26 34 e9 84"), // (20 octets) + // }, + + {P: "passwordPASSWORDpassword", // (24 octets) + S: "saltSALTsaltSALTsaltSALTsaltSALTsalt", // (36 octets) + c: 4096, + dkLen: 25, + DK: h("3d 2e ec 4f e4 1c 84 9b"+ + "80 c8 d8 36 62 c0 e4 4a"+ + "8b 29 1a 96 4c f2 f0 70"+ + "38"), // (25 octets) + + }, + + {P: "pass\0word", // (9 octets) + S: "sa\0lt", // (5 octets) + c: 4096, + dkLen: 16, + DK: h("56 fa 6a a7 55 48 09 9d"+ + "cc 37 d7 f0 34 25 e0 c3"), // (16 octets) + }, + ]; + + for (let v of vectors) { + do_check_eq(v.DK, b2h(pbkdf2(v.P, v.S, v.c, v.dkLen))); + } +}); + +// I can't find any normative ietf test vectors for pbkdf2 hmac-sha256. +// The following vectors are derived with the same inputs as above (the sha1 +// test). Results verified by users here: +// https://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors +add_task(function test_pbkdf2_hmac_sha256() { + let pbkdf2 = CryptoUtils.pbkdf2Generate; + let vectors = [ + {P: "password", // (8 octets) + S: "salt", // (4 octets) + c: 1, + dkLen: 32, + DK: h("12 0f b6 cf fc f8 b3 2c"+ + "43 e7 22 52 56 c4 f8 37"+ + "a8 65 48 c9 2c cc 35 48"+ + "08 05 98 7c b7 0b e1 7b"), // (32 octets) + }, + + {P: "password", // (8 octets) + S: "salt", // (4 octets) + c: 2, + dkLen: 32, + DK: h("ae 4d 0c 95 af 6b 46 d3"+ + "2d 0a df f9 28 f0 6d d0"+ + "2a 30 3f 8e f3 c2 51 df"+ + "d6 e2 d8 5a 95 47 4c 43"), // (32 octets) + }, + + {P: "password", // (8 octets) + S: "salt", // (4 octets) + c: 4096, + dkLen: 32, + DK: h("c5 e4 78 d5 92 88 c8 41"+ + "aa 53 0d b6 84 5c 4c 8d"+ + "96 28 93 a0 01 ce 4e 11"+ + "a4 96 38 73 aa 98 13 4a"), // (32 octets) + }, + + {P: "passwordPASSWORDpassword", // (24 octets) + S: "saltSALTsaltSALTsaltSALTsaltSALTsalt", // (36 octets) + c: 4096, + dkLen: 40, + DK: h("34 8c 89 db cb d3 2b 2f"+ + "32 d8 14 b8 11 6e 84 cf"+ + "2b 17 34 7e bc 18 00 18"+ + "1c 4e 2a 1f b8 dd 53 e1"+ + "c6 35 51 8c 7d ac 47 e9"), // (40 octets) + }, + + {P: "pass\0word", // (9 octets) + S: "sa\0lt", // (5 octets) + c: 4096, + dkLen: 16, + DK: h("89 b6 9d 05 16 f8 29 89"+ + "3c 69 62 26 65 0a 86 87"), // (16 octets) + }, + ]; + + for (let v of vectors) { + do_check_eq(v.DK, + b2h(pbkdf2(v.P, v.S, v.c, v.dkLen, Ci.nsICryptoHMAC.SHA256, 32))); + } +}); + +// turn formatted test vectors into normal hex strings +function h(hexStr) { + return hexStr.replace(/\s+/g, ""); +} diff --git a/services/crypto/tests/unit/test_utils_sha1.js b/services/crypto/tests/unit/test_utils_sha1.js new file mode 100644 index 000000000..f99350754 --- /dev/null +++ b/services/crypto/tests/unit/test_utils_sha1.js @@ -0,0 +1,37 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +_("Make sure sha1 digests works with various messages"); + +Cu.import("resource://services-crypto/utils.js"); + +function run_test() { + let mes1 = "hello"; + let mes2 = "world"; + + let dig0 = CryptoUtils.UTF8AndSHA1(mes1); + do_check_eq(dig0, + "\xaa\xf4\xc6\x1d\xdc\xc5\xe8\xa2\xda\xbe\xde\x0f\x3b\x48\x2c\xd9\xae\xa9\x43\x4d"); + + _("Make sure right sha1 digests are generated"); + let dig1 = CryptoUtils.sha1(mes1); + do_check_eq(dig1, "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"); + let dig2 = CryptoUtils.sha1(mes2); + do_check_eq(dig2, "7c211433f02071597741e6ff5a8ea34789abbf43"); + let dig12 = CryptoUtils.sha1(mes1 + mes2); + do_check_eq(dig12, "6adfb183a4a2c94a2f92dab5ade762a47889a5a1"); + let dig21 = CryptoUtils.sha1(mes2 + mes1); + do_check_eq(dig21, "5715790a892990382d98858c4aa38d0617151575"); + + _("Repeated sha1s shouldn't change the digest"); + do_check_eq(CryptoUtils.sha1(mes1), dig1); + do_check_eq(CryptoUtils.sha1(mes2), dig2); + do_check_eq(CryptoUtils.sha1(mes1 + mes2), dig12); + do_check_eq(CryptoUtils.sha1(mes2 + mes1), dig21); + + _("Nested sha1 should work just fine"); + let nest1 = CryptoUtils.sha1(CryptoUtils.sha1(CryptoUtils.sha1(CryptoUtils.sha1(CryptoUtils.sha1(mes1))))); + do_check_eq(nest1, "23f340d0cff31e299158b3181b6bcc7e8c7f985a"); + let nest2 = CryptoUtils.sha1(CryptoUtils.sha1(CryptoUtils.sha1(CryptoUtils.sha1(CryptoUtils.sha1(mes2))))); + do_check_eq(nest2, "1f6453867e3fb9876ae429918a64cdb8dc5ff2d0"); +} diff --git a/services/crypto/tests/unit/xpcshell.ini b/services/crypto/tests/unit/xpcshell.ini new file mode 100644 index 000000000..0b3a9324c --- /dev/null +++ b/services/crypto/tests/unit/xpcshell.ini @@ -0,0 +1,20 @@ +[DEFAULT] +head = head_helpers.js ../../../common/tests/unit/head_helpers.js +tail = +firefox-appdir = browser +support-files = + !/services/common/tests/unit/head_helpers.js + +[test_load_modules.js] + +[test_crypto_crypt.js] +[test_crypto_deriveKey.js] +[test_crypto_random.js] +# Bug 676977: test hangs consistently on Android +skip-if = os == "android" + +[test_utils_hawk.js] +[test_utils_hkdfExpand.js] +[test_utils_httpmac.js] +[test_utils_pbkdf2.js] +[test_utils_sha1.js] |