services/sync/tests/unit/test_records_crypto.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/services/sync/tests/unit/test_records_crypto.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,156 @@
     1.4 +/* Any copyright is dedicated to the Public Domain.
     1.5 + * http://creativecommons.org/publicdomain/zero/1.0/ */
     1.6 +
     1.7 +Cu.import("resource://gre/modules/Log.jsm");
     1.8 +Cu.import("resource://services-sync/constants.js");
     1.9 +Cu.import("resource://services-sync/keys.js");
    1.10 +Cu.import("resource://services-sync/record.js");
    1.11 +Cu.import("resource://services-sync/resource.js");
    1.12 +Cu.import("resource://services-sync/service.js");
    1.13 +Cu.import("resource://services-sync/util.js");
    1.14 +Cu.import("resource://testing-common/services/sync/utils.js");
    1.15 +
    1.16 +let cryptoWrap;
    1.17 +
    1.18 +function crypted_resource_handler(metadata, response) {
    1.19 +  let obj = {id: "resource",
    1.20 +             modified: cryptoWrap.modified,
    1.21 +             payload: JSON.stringify(cryptoWrap.payload)};
    1.22 +  return httpd_basic_auth_handler(JSON.stringify(obj), metadata, response);
    1.23 +}
    1.24 +
    1.25 +function prepareCryptoWrap(collection, id) {
    1.26 +  let w = new CryptoWrapper();
    1.27 +  w.cleartext.stuff = "my payload here";
    1.28 +  w.collection = collection;
    1.29 +  w.id = id;
    1.30 +  return w;
    1.31 +}
    1.32 +
    1.33 +function run_test() {
    1.34 +  let server;
    1.35 +  do_test_pending();
    1.36 +
    1.37 +  ensureLegacyIdentityManager();
    1.38 +  Service.identity.username = "john@example.com";
    1.39 +  Service.identity.syncKey = "a-abcde-abcde-abcde-abcde-abcde";
    1.40 +  let keyBundle = Service.identity.syncKeyBundle;
    1.41 +
    1.42 +  try {
    1.43 +    let log = Log.repository.getLogger("Test");
    1.44 +    Log.repository.rootLogger.addAppender(new Log.DumpAppender());
    1.45 +
    1.46 +    log.info("Setting up server and authenticator");
    1.47 +
    1.48 +    server = httpd_setup({"/steam/resource": crypted_resource_handler});
    1.49 +
    1.50 +    log.info("Creating a record");
    1.51 +
    1.52 +    let cryptoUri = "http://localhost:8080/crypto/steam";
    1.53 +    cryptoWrap = prepareCryptoWrap("steam", "resource");
    1.54 +
    1.55 +    log.info("cryptoWrap: " + cryptoWrap.toString());
    1.56 +
    1.57 +    log.info("Encrypting a record");
    1.58 +
    1.59 +    cryptoWrap.encrypt(keyBundle);
    1.60 +    log.info("Ciphertext is " + cryptoWrap.ciphertext);
    1.61 +    do_check_true(cryptoWrap.ciphertext != null);
    1.62 +
    1.63 +    let firstIV = cryptoWrap.IV;
    1.64 +
    1.65 +    log.info("Decrypting the record");
    1.66 +
    1.67 +    let payload = cryptoWrap.decrypt(keyBundle);
    1.68 +    do_check_eq(payload.stuff, "my payload here");
    1.69 +    do_check_neq(payload, cryptoWrap.payload); // wrap.data.payload is the encrypted one
    1.70 +
    1.71 +    log.info("Make sure multiple decrypts cause failures");
    1.72 +    let error = "";
    1.73 +    try {
    1.74 +      payload = cryptoWrap.decrypt(keyBundle);
    1.75 +    }
    1.76 +    catch(ex) {
    1.77 +      error = ex;
    1.78 +    }
    1.79 +    do_check_eq(error, "No ciphertext: nothing to decrypt?");
    1.80 +
    1.81 +    log.info("Re-encrypting the record with alternate payload");
    1.82 +
    1.83 +    cryptoWrap.cleartext.stuff = "another payload";
    1.84 +    cryptoWrap.encrypt(keyBundle);
    1.85 +    let secondIV = cryptoWrap.IV;
    1.86 +    payload = cryptoWrap.decrypt(keyBundle);
    1.87 +    do_check_eq(payload.stuff, "another payload");
    1.88 +
    1.89 +    log.info("Make sure multiple encrypts use different IVs");
    1.90 +    do_check_neq(firstIV, secondIV);
    1.91 +
    1.92 +    log.info("Make sure differing ids cause failures");
    1.93 +    cryptoWrap.encrypt(keyBundle);
    1.94 +    cryptoWrap.data.id = "other";
    1.95 +    error = "";
    1.96 +    try {
    1.97 +      cryptoWrap.decrypt(keyBundle);
    1.98 +    }
    1.99 +    catch(ex) {
   1.100 +      error = ex;
   1.101 +    }
   1.102 +    do_check_eq(error, "Record id mismatch: resource != other");
   1.103 +
   1.104 +    log.info("Make sure wrong hmacs cause failures");
   1.105 +    cryptoWrap.encrypt(keyBundle);
   1.106 +    cryptoWrap.hmac = "foo";
   1.107 +    error = "";
   1.108 +    try {
   1.109 +      cryptoWrap.decrypt(keyBundle);
   1.110 +    }
   1.111 +    catch(ex) {
   1.112 +      error = ex;
   1.113 +    }
   1.114 +    do_check_eq(error.substr(0, 42), "Record SHA256 HMAC mismatch: should be foo");
   1.115 +
   1.116 +    // Checking per-collection keys and default key handling.
   1.117 +
   1.118 +    generateNewKeys(Service.collectionKeys);
   1.119 +    let bu = "http://localhost:8080/storage/bookmarks/foo";
   1.120 +    let bookmarkItem = prepareCryptoWrap("bookmarks", "foo");
   1.121 +    bookmarkItem.encrypt(Service.collectionKeys.keyForCollection("bookmarks"));
   1.122 +    log.info("Ciphertext is " + bookmarkItem.ciphertext);
   1.123 +    do_check_true(bookmarkItem.ciphertext != null);
   1.124 +    log.info("Decrypting the record explicitly with the default key.");
   1.125 +    do_check_eq(bookmarkItem.decrypt(Service.collectionKeys._default).stuff, "my payload here");
   1.126 +
   1.127 +    // Per-collection keys.
   1.128 +    // Generate a key for "bookmarks".
   1.129 +    generateNewKeys(Service.collectionKeys, ["bookmarks"]);
   1.130 +    bookmarkItem = prepareCryptoWrap("bookmarks", "foo");
   1.131 +    do_check_eq(bookmarkItem.collection, "bookmarks");
   1.132 +
   1.133 +    // Encrypt. This'll use the "bookmarks" encryption key, because we have a
   1.134 +    // special key for it. The same key will need to be used for decryption.
   1.135 +    bookmarkItem.encrypt(Service.collectionKeys.keyForCollection("bookmarks"));
   1.136 +    do_check_true(bookmarkItem.ciphertext != null);
   1.137 +
   1.138 +    // Attempt to use the default key, because this is a collision that could
   1.139 +    // conceivably occur in the real world. Decryption will error, because
   1.140 +    // it's not the bookmarks key.
   1.141 +    let err;
   1.142 +    try {
   1.143 +      bookmarkItem.decrypt(Service.collectionKeys._default);
   1.144 +    } catch (ex) {
   1.145 +      err = ex;
   1.146 +    }
   1.147 +    do_check_eq("Record SHA256 HMAC mismatch", err.substr(0, 27));
   1.148 +
   1.149 +    // Explicitly check that it's using the bookmarks key.
   1.150 +    // This should succeed.
   1.151 +    do_check_eq(bookmarkItem.decrypt(Service.collectionKeys.keyForCollection("bookmarks")).stuff,
   1.152 +        "my payload here");
   1.153 +
   1.154 +    log.info("Done!");
   1.155 +  }
   1.156 +  finally {
   1.157 +    server.stop(do_test_finished);
   1.158 +  }
   1.159 +}

mercurial