services/sync/tests/unit/test_records_crypto.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* Any copyright is dedicated to the Public Domain.
michael@0 2 * http://creativecommons.org/publicdomain/zero/1.0/ */
michael@0 3
michael@0 4 Cu.import("resource://gre/modules/Log.jsm");
michael@0 5 Cu.import("resource://services-sync/constants.js");
michael@0 6 Cu.import("resource://services-sync/keys.js");
michael@0 7 Cu.import("resource://services-sync/record.js");
michael@0 8 Cu.import("resource://services-sync/resource.js");
michael@0 9 Cu.import("resource://services-sync/service.js");
michael@0 10 Cu.import("resource://services-sync/util.js");
michael@0 11 Cu.import("resource://testing-common/services/sync/utils.js");
michael@0 12
michael@0 13 let cryptoWrap;
michael@0 14
michael@0 15 function crypted_resource_handler(metadata, response) {
michael@0 16 let obj = {id: "resource",
michael@0 17 modified: cryptoWrap.modified,
michael@0 18 payload: JSON.stringify(cryptoWrap.payload)};
michael@0 19 return httpd_basic_auth_handler(JSON.stringify(obj), metadata, response);
michael@0 20 }
michael@0 21
michael@0 22 function prepareCryptoWrap(collection, id) {
michael@0 23 let w = new CryptoWrapper();
michael@0 24 w.cleartext.stuff = "my payload here";
michael@0 25 w.collection = collection;
michael@0 26 w.id = id;
michael@0 27 return w;
michael@0 28 }
michael@0 29
michael@0 30 function run_test() {
michael@0 31 let server;
michael@0 32 do_test_pending();
michael@0 33
michael@0 34 ensureLegacyIdentityManager();
michael@0 35 Service.identity.username = "john@example.com";
michael@0 36 Service.identity.syncKey = "a-abcde-abcde-abcde-abcde-abcde";
michael@0 37 let keyBundle = Service.identity.syncKeyBundle;
michael@0 38
michael@0 39 try {
michael@0 40 let log = Log.repository.getLogger("Test");
michael@0 41 Log.repository.rootLogger.addAppender(new Log.DumpAppender());
michael@0 42
michael@0 43 log.info("Setting up server and authenticator");
michael@0 44
michael@0 45 server = httpd_setup({"/steam/resource": crypted_resource_handler});
michael@0 46
michael@0 47 log.info("Creating a record");
michael@0 48
michael@0 49 let cryptoUri = "http://localhost:8080/crypto/steam";
michael@0 50 cryptoWrap = prepareCryptoWrap("steam", "resource");
michael@0 51
michael@0 52 log.info("cryptoWrap: " + cryptoWrap.toString());
michael@0 53
michael@0 54 log.info("Encrypting a record");
michael@0 55
michael@0 56 cryptoWrap.encrypt(keyBundle);
michael@0 57 log.info("Ciphertext is " + cryptoWrap.ciphertext);
michael@0 58 do_check_true(cryptoWrap.ciphertext != null);
michael@0 59
michael@0 60 let firstIV = cryptoWrap.IV;
michael@0 61
michael@0 62 log.info("Decrypting the record");
michael@0 63
michael@0 64 let payload = cryptoWrap.decrypt(keyBundle);
michael@0 65 do_check_eq(payload.stuff, "my payload here");
michael@0 66 do_check_neq(payload, cryptoWrap.payload); // wrap.data.payload is the encrypted one
michael@0 67
michael@0 68 log.info("Make sure multiple decrypts cause failures");
michael@0 69 let error = "";
michael@0 70 try {
michael@0 71 payload = cryptoWrap.decrypt(keyBundle);
michael@0 72 }
michael@0 73 catch(ex) {
michael@0 74 error = ex;
michael@0 75 }
michael@0 76 do_check_eq(error, "No ciphertext: nothing to decrypt?");
michael@0 77
michael@0 78 log.info("Re-encrypting the record with alternate payload");
michael@0 79
michael@0 80 cryptoWrap.cleartext.stuff = "another payload";
michael@0 81 cryptoWrap.encrypt(keyBundle);
michael@0 82 let secondIV = cryptoWrap.IV;
michael@0 83 payload = cryptoWrap.decrypt(keyBundle);
michael@0 84 do_check_eq(payload.stuff, "another payload");
michael@0 85
michael@0 86 log.info("Make sure multiple encrypts use different IVs");
michael@0 87 do_check_neq(firstIV, secondIV);
michael@0 88
michael@0 89 log.info("Make sure differing ids cause failures");
michael@0 90 cryptoWrap.encrypt(keyBundle);
michael@0 91 cryptoWrap.data.id = "other";
michael@0 92 error = "";
michael@0 93 try {
michael@0 94 cryptoWrap.decrypt(keyBundle);
michael@0 95 }
michael@0 96 catch(ex) {
michael@0 97 error = ex;
michael@0 98 }
michael@0 99 do_check_eq(error, "Record id mismatch: resource != other");
michael@0 100
michael@0 101 log.info("Make sure wrong hmacs cause failures");
michael@0 102 cryptoWrap.encrypt(keyBundle);
michael@0 103 cryptoWrap.hmac = "foo";
michael@0 104 error = "";
michael@0 105 try {
michael@0 106 cryptoWrap.decrypt(keyBundle);
michael@0 107 }
michael@0 108 catch(ex) {
michael@0 109 error = ex;
michael@0 110 }
michael@0 111 do_check_eq(error.substr(0, 42), "Record SHA256 HMAC mismatch: should be foo");
michael@0 112
michael@0 113 // Checking per-collection keys and default key handling.
michael@0 114
michael@0 115 generateNewKeys(Service.collectionKeys);
michael@0 116 let bu = "http://localhost:8080/storage/bookmarks/foo";
michael@0 117 let bookmarkItem = prepareCryptoWrap("bookmarks", "foo");
michael@0 118 bookmarkItem.encrypt(Service.collectionKeys.keyForCollection("bookmarks"));
michael@0 119 log.info("Ciphertext is " + bookmarkItem.ciphertext);
michael@0 120 do_check_true(bookmarkItem.ciphertext != null);
michael@0 121 log.info("Decrypting the record explicitly with the default key.");
michael@0 122 do_check_eq(bookmarkItem.decrypt(Service.collectionKeys._default).stuff, "my payload here");
michael@0 123
michael@0 124 // Per-collection keys.
michael@0 125 // Generate a key for "bookmarks".
michael@0 126 generateNewKeys(Service.collectionKeys, ["bookmarks"]);
michael@0 127 bookmarkItem = prepareCryptoWrap("bookmarks", "foo");
michael@0 128 do_check_eq(bookmarkItem.collection, "bookmarks");
michael@0 129
michael@0 130 // Encrypt. This'll use the "bookmarks" encryption key, because we have a
michael@0 131 // special key for it. The same key will need to be used for decryption.
michael@0 132 bookmarkItem.encrypt(Service.collectionKeys.keyForCollection("bookmarks"));
michael@0 133 do_check_true(bookmarkItem.ciphertext != null);
michael@0 134
michael@0 135 // Attempt to use the default key, because this is a collision that could
michael@0 136 // conceivably occur in the real world. Decryption will error, because
michael@0 137 // it's not the bookmarks key.
michael@0 138 let err;
michael@0 139 try {
michael@0 140 bookmarkItem.decrypt(Service.collectionKeys._default);
michael@0 141 } catch (ex) {
michael@0 142 err = ex;
michael@0 143 }
michael@0 144 do_check_eq("Record SHA256 HMAC mismatch", err.substr(0, 27));
michael@0 145
michael@0 146 // Explicitly check that it's using the bookmarks key.
michael@0 147 // This should succeed.
michael@0 148 do_check_eq(bookmarkItem.decrypt(Service.collectionKeys.keyForCollection("bookmarks")).stuff,
michael@0 149 "my payload here");
michael@0 150
michael@0 151 log.info("Done!");
michael@0 152 }
michael@0 153 finally {
michael@0 154 server.stop(do_test_finished);
michael@0 155 }
michael@0 156 }

mercurial