toolkit/identity/tests/unit/test_jwcrypto.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/identity/tests/unit/test_jwcrypto.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,281 @@
     1.4 +/* Any copyright is dedicated to the Public Domain.
     1.5 +   http://creativecommons.org/publicdomain/zero/1.0/ */
     1.6 +
     1.7 +"use strict"
     1.8 +
     1.9 +Cu.import('resource://gre/modules/identity/LogUtils.jsm');
    1.10 +
    1.11 +XPCOMUtils.defineLazyModuleGetter(this, "IDService",
    1.12 +                                  "resource://gre/modules/identity/Identity.jsm",
    1.13 +                                  "IdentityService");
    1.14 +
    1.15 +XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto",
    1.16 +                                  "resource://gre/modules/identity/jwcrypto.jsm");
    1.17 +
    1.18 +XPCOMUtils.defineLazyServiceGetter(this,
    1.19 +                                   "CryptoService",
    1.20 +                                   "@mozilla.org/identity/crypto-service;1",
    1.21 +                                   "nsIIdentityCryptoService");
    1.22 +
    1.23 +const RP_ORIGIN = "http://123done.org";
    1.24 +const INTERNAL_ORIGIN = "browserid://";
    1.25 +
    1.26 +const SECOND_MS = 1000;
    1.27 +const MINUTE_MS = SECOND_MS * 60;
    1.28 +const HOUR_MS = MINUTE_MS * 60;
    1.29 +
    1.30 +function test_sanity() {
    1.31 +  do_test_pending();
    1.32 +
    1.33 +  jwcrypto.generateKeyPair("DS160", function(err, kp) {
    1.34 +    do_check_null(err);
    1.35 +
    1.36 +    do_test_finished();
    1.37 +    run_next_test();
    1.38 +  });
    1.39 +}
    1.40 +
    1.41 +function test_generate() {
    1.42 +  do_test_pending();
    1.43 +  jwcrypto.generateKeyPair("DS160", function(err, kp) {
    1.44 +    do_check_null(err);
    1.45 +    do_check_neq(kp, null);
    1.46 +
    1.47 +    do_test_finished();
    1.48 +    run_next_test();
    1.49 +  });
    1.50 +}
    1.51 +
    1.52 +function test_get_assertion() {
    1.53 +  do_test_pending();
    1.54 +
    1.55 +  jwcrypto.generateKeyPair(
    1.56 +    "DS160",
    1.57 +    function(err, kp) {
    1.58 +      jwcrypto.generateAssertion("fake-cert", kp, RP_ORIGIN, (err, backedAssertion) => {
    1.59 +        do_check_null(err);
    1.60 +
    1.61 +        do_check_eq(backedAssertion.split("~").length, 2);
    1.62 +        do_check_eq(backedAssertion.split(".").length, 3);
    1.63 +
    1.64 +        do_test_finished();
    1.65 +        run_next_test();
    1.66 +      });
    1.67 +    });
    1.68 +}
    1.69 +
    1.70 +function test_rsa() {
    1.71 +  do_test_pending();
    1.72 +  function checkRSA(err, kpo) {
    1.73 +    do_check_neq(kpo, undefined);
    1.74 +    log(kpo.serializedPublicKey);
    1.75 +    let pk = JSON.parse(kpo.serializedPublicKey);
    1.76 +    do_check_eq(pk.algorithm, "RS");
    1.77 +/* TODO
    1.78 +    do_check_neq(kpo.sign, null);
    1.79 +    do_check_eq(typeof kpo.sign, "function");
    1.80 +    do_check_neq(kpo.userID, null);
    1.81 +    do_check_neq(kpo.url, null);
    1.82 +    do_check_eq(kpo.url, INTERNAL_ORIGIN);
    1.83 +    do_check_neq(kpo.exponent, null);
    1.84 +    do_check_neq(kpo.modulus, null);
    1.85 +
    1.86 +    // TODO: should sign be async?
    1.87 +    let sig = kpo.sign("This is a message to sign");
    1.88 +
    1.89 +    do_check_neq(sig, null);
    1.90 +    do_check_eq(typeof sig, "string");
    1.91 +    do_check_true(sig.length > 1);
    1.92 +*/
    1.93 +    do_test_finished();
    1.94 +    run_next_test();
    1.95 +  };
    1.96 +
    1.97 +  jwcrypto.generateKeyPair("RS256", checkRSA);
    1.98 +}
    1.99 +
   1.100 +function test_dsa() {
   1.101 +  do_test_pending();
   1.102 +  function checkDSA(err, kpo) {
   1.103 +    do_check_neq(kpo, undefined);
   1.104 +    log(kpo.serializedPublicKey);
   1.105 +    let pk = JSON.parse(kpo.serializedPublicKey);
   1.106 +    do_check_eq(pk.algorithm, "DS");
   1.107 +/* TODO
   1.108 +    do_check_neq(kpo.sign, null);
   1.109 +    do_check_eq(typeof kpo.sign, "function");
   1.110 +    do_check_neq(kpo.userID, null);
   1.111 +    do_check_neq(kpo.url, null);
   1.112 +    do_check_eq(kpo.url, INTERNAL_ORIGIN);
   1.113 +    do_check_neq(kpo.generator, null);
   1.114 +    do_check_neq(kpo.prime, null);
   1.115 +    do_check_neq(kpo.subPrime, null);
   1.116 +    do_check_neq(kpo.publicValue, null);
   1.117 +
   1.118 +    let sig = kpo.sign("This is a message to sign");
   1.119 +
   1.120 +    do_check_neq(sig, null);
   1.121 +    do_check_eq(typeof sig, "string");
   1.122 +    do_check_true(sig.length > 1);
   1.123 +*/
   1.124 +    do_test_finished();
   1.125 +    run_next_test();
   1.126 +  };
   1.127 +
   1.128 +  jwcrypto.generateKeyPair("DS160", checkDSA);
   1.129 +}
   1.130 +
   1.131 +function test_get_assertion_with_offset() {
   1.132 +  do_test_pending();
   1.133 +
   1.134 +
   1.135 +  // Use an arbitrary date in the past to ensure we don't accidentally pass
   1.136 +  // this test with current dates, missing offsets, etc.
   1.137 +  let serverMsec = Date.parse("Tue Oct 31 2000 00:00:00 GMT-0800");
   1.138 +
   1.139 +  // local clock skew
   1.140 +  // clock is 12 hours fast; -12 hours offset must be applied
   1.141 +  let localtimeOffsetMsec = -1 * 12 * HOUR_MS;
   1.142 +  let localMsec = serverMsec - localtimeOffsetMsec;
   1.143 +
   1.144 +  jwcrypto.generateKeyPair(
   1.145 +    "DS160",
   1.146 +    function(err, kp) {
   1.147 +      jwcrypto.generateAssertion("fake-cert", kp, RP_ORIGIN,
   1.148 +        { duration: MINUTE_MS,
   1.149 +          localtimeOffsetMsec: localtimeOffsetMsec,
   1.150 +          now: localMsec},
   1.151 +          function(err, backedAssertion) {
   1.152 +            do_check_null(err);
   1.153 +
   1.154 +            // properly formed
   1.155 +            let cert;
   1.156 +            let assertion;
   1.157 +            [cert, assertion] = backedAssertion.split("~");
   1.158 +
   1.159 +            do_check_eq(cert, "fake-cert");
   1.160 +            do_check_eq(assertion.split(".").length, 3);
   1.161 +
   1.162 +            let components = extractComponents(assertion);
   1.163 +
   1.164 +            // Expiry is within two minutes, corrected for skew
   1.165 +            let exp = parseInt(components.payload.exp, 10);
   1.166 +            do_check_true(exp - serverMsec === MINUTE_MS);
   1.167 +
   1.168 +            do_test_finished();
   1.169 +            run_next_test();
   1.170 +          }
   1.171 +      );
   1.172 +    }
   1.173 +  );
   1.174 +}
   1.175 +
   1.176 +function test_assertion_lifetime() {
   1.177 +  do_test_pending();
   1.178 +
   1.179 +  jwcrypto.generateKeyPair(
   1.180 +    "DS160",
   1.181 +    function(err, kp) {
   1.182 +      jwcrypto.generateAssertion("fake-cert", kp, RP_ORIGIN,
   1.183 +        {duration: MINUTE_MS},
   1.184 +        function(err, backedAssertion) {
   1.185 +          do_check_null(err);
   1.186 +
   1.187 +          // properly formed
   1.188 +          let cert;
   1.189 +          let assertion;
   1.190 +          [cert, assertion] = backedAssertion.split("~");
   1.191 +
   1.192 +          do_check_eq(cert, "fake-cert");
   1.193 +          do_check_eq(assertion.split(".").length, 3);
   1.194 +
   1.195 +          let components = extractComponents(assertion);
   1.196 +
   1.197 +          // Expiry is within one minute, as we specified above
   1.198 +          let exp = parseInt(components.payload.exp, 10);
   1.199 +          do_check_true(Math.abs(Date.now() - exp) > 50 * SECOND_MS);
   1.200 +          do_check_true(Math.abs(Date.now() - exp) <= MINUTE_MS);
   1.201 +
   1.202 +          do_test_finished();
   1.203 +          run_next_test();
   1.204 +        }
   1.205 +      );
   1.206 +    }
   1.207 +  );
   1.208 +}
   1.209 +
   1.210 +function test_audience_encoding_bug972582() {
   1.211 +  let audience = "i-like-pie.com";
   1.212 +
   1.213 +  jwcrypto.generateKeyPair(
   1.214 +    "DS160",
   1.215 +    function(err, kp) {
   1.216 +      do_check_null(err);
   1.217 +      jwcrypto.generateAssertion("fake-cert", kp, audience,
   1.218 +        function(err, backedAssertion) {
   1.219 +          do_check_null(err);
   1.220 +
   1.221 +          let [cert, assertion] = backedAssertion.split("~");
   1.222 +          let components = extractComponents(assertion);
   1.223 +          do_check_eq(components.payload.aud, audience);
   1.224 +
   1.225 +          do_test_finished();
   1.226 +          run_next_test();
   1.227 +        }
   1.228 +      );
   1.229 +    }
   1.230 +  );
   1.231 +}
   1.232 +
   1.233 +// End of tests
   1.234 +// Helper function follow
   1.235 +
   1.236 +function extractComponents(signedObject) {
   1.237 +  if (typeof(signedObject) != 'string') {
   1.238 +    throw new Error("malformed signature " + typeof(signedObject));
   1.239 +  }
   1.240 +
   1.241 +  let parts = signedObject.split(".");
   1.242 +  if (parts.length != 3) {
   1.243 +    throw new Error("signed object must have three parts, this one has " + parts.length);
   1.244 +  }
   1.245 +
   1.246 +  let headerSegment = parts[0];
   1.247 +  let payloadSegment = parts[1];
   1.248 +  let cryptoSegment = parts[2];
   1.249 +
   1.250 +  let header = JSON.parse(base64UrlDecode(headerSegment));
   1.251 +  let payload = JSON.parse(base64UrlDecode(payloadSegment));
   1.252 +
   1.253 +  // Ensure well-formed header
   1.254 +  do_check_eq(Object.keys(header).length, 1);
   1.255 +  do_check_true(!!header.alg);
   1.256 +
   1.257 +  // Ensure well-formed payload
   1.258 +  for (let field of ["exp", "aud"]) {
   1.259 +    do_check_true(!!payload[field]);
   1.260 +  }
   1.261 +
   1.262 +  return {header: header,
   1.263 +          payload: payload,
   1.264 +          headerSegment: headerSegment,
   1.265 +          payloadSegment: payloadSegment,
   1.266 +          cryptoSegment: cryptoSegment};
   1.267 +};
   1.268 +
   1.269 +let TESTS = [
   1.270 +  test_sanity,
   1.271 +  test_generate,
   1.272 +  test_get_assertion,
   1.273 +  test_get_assertion_with_offset,
   1.274 +  test_assertion_lifetime,
   1.275 +  test_audience_encoding_bug972582,
   1.276 +];
   1.277 +
   1.278 +TESTS = TESTS.concat([test_rsa, test_dsa]);
   1.279 +
   1.280 +TESTS.forEach(add_test);
   1.281 +
   1.282 +function run_test() {
   1.283 +  run_next_test();
   1.284 +}

mercurial