michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: "use strict"; michael@0: michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Cu.import('resource://gre/modules/identity/LogUtils.jsm'); michael@0: michael@0: const idService = Cc["@mozilla.org/identity/crypto-service;1"] michael@0: .getService(Ci.nsIIdentityCryptoService); michael@0: michael@0: const ALG_DSA = "DS160"; michael@0: const ALG_RSA = "RS256"; michael@0: michael@0: const BASE64_URL_ENCODINGS = [ michael@0: // The vectors from RFC 4648 are very silly, but we may as well include them. michael@0: ["", ""], michael@0: ["f", "Zg=="], michael@0: ["fo", "Zm8="], michael@0: ["foo", "Zm9v"], michael@0: ["foob", "Zm9vYg=="], michael@0: ["fooba", "Zm9vYmE="], michael@0: ["foobar", "Zm9vYmFy"], michael@0: michael@0: // It's quite likely you could get a string like this in an assertion audience michael@0: ["i-like-pie.com", "aS1saWtlLXBpZS5jb20="], michael@0: michael@0: // A few extra to be really sure michael@0: ["andré@example.com", "YW5kcsOpQGV4YW1wbGUuY29t"], michael@0: ["πόλλ' οἶδ' ἀλώπηξ, ἀλλ' ἐχῖνος ἓν μέγα", michael@0: "z4DPjM67zrsnIM6_4by2zrQnIOG8gM67z47PgM63zr4sIOG8gM67zrsnIOG8kM-H4b-Wzr3Ov8-CIOG8k869IM68zq3Os86x"], michael@0: ]; michael@0: michael@0: // When the output of an operation is a michael@0: function do_check_eq_or_slightly_less(x, y) { michael@0: do_check_true(x >= y - (3 * 8)); michael@0: } michael@0: michael@0: function test_base64_roundtrip() { michael@0: let message = "Attack at dawn!"; michael@0: let encoded = idService.base64UrlEncode(message); michael@0: let decoded = base64UrlDecode(encoded); michael@0: do_check_neq(message, encoded); michael@0: do_check_eq(decoded, message); michael@0: run_next_test(); michael@0: } michael@0: michael@0: function test_dsa() { michael@0: idService.generateKeyPair(ALG_DSA, function (rv, keyPair) { michael@0: log("DSA generateKeyPair finished ", rv); michael@0: do_check_true(Components.isSuccessCode(rv)); michael@0: do_check_eq(typeof keyPair.sign, "function"); michael@0: do_check_eq(keyPair.keyType, ALG_DSA); michael@0: do_check_eq_or_slightly_less(keyPair.hexDSAGenerator.length, 1024 / 8 * 2); michael@0: do_check_eq_or_slightly_less(keyPair.hexDSAPrime.length, 1024 / 8 * 2); michael@0: do_check_eq_or_slightly_less(keyPair.hexDSASubPrime.length, 160 / 8 * 2); michael@0: do_check_eq_or_slightly_less(keyPair.hexDSAPublicValue.length, 1024 / 8 * 2); michael@0: // XXX: test that RSA parameters throw the correct error michael@0: michael@0: log("about to sign with DSA key"); michael@0: keyPair.sign("foo", function (rv, signature) { michael@0: log("DSA sign finished ", rv, signature); michael@0: do_check_true(Components.isSuccessCode(rv)); michael@0: do_check_true(signature.length > 1); michael@0: // TODO: verify the signature with the public key michael@0: run_next_test(); michael@0: }); michael@0: }); michael@0: } michael@0: michael@0: function test_rsa() { michael@0: idService.generateKeyPair(ALG_RSA, function (rv, keyPair) { michael@0: log("RSA generateKeyPair finished ", rv); michael@0: do_check_true(Components.isSuccessCode(rv)); michael@0: do_check_eq(typeof keyPair.sign, "function"); michael@0: do_check_eq(keyPair.keyType, ALG_RSA); michael@0: do_check_eq_or_slightly_less(keyPair.hexRSAPublicKeyModulus.length, michael@0: 2048 / 8); michael@0: do_check_true(keyPair.hexRSAPublicKeyExponent.length > 1); michael@0: michael@0: log("about to sign with RSA key"); michael@0: keyPair.sign("foo", function (rv, signature) { michael@0: log("RSA sign finished ", rv, signature); michael@0: do_check_true(Components.isSuccessCode(rv)); michael@0: do_check_true(signature.length > 1); michael@0: run_next_test(); michael@0: }); michael@0: }); michael@0: } michael@0: michael@0: function test_base64UrlEncode() { michael@0: for (let [source, target] of BASE64_URL_ENCODINGS) { michael@0: do_check_eq(target, idService.base64UrlEncode(source)); michael@0: } michael@0: run_next_test(); michael@0: } michael@0: michael@0: function test_base64UrlDecode() { michael@0: let utf8Converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] michael@0: .createInstance(Ci.nsIScriptableUnicodeConverter); michael@0: utf8Converter.charset = "UTF-8"; michael@0: michael@0: // We know the encoding of our inputs - on conversion back out again, make michael@0: // sure they're the same. michael@0: for (let [source, target] of BASE64_URL_ENCODINGS) { michael@0: let result = utf8Converter.ConvertToUnicode(base64UrlDecode(target)); michael@0: result += utf8Converter.Finish(); michael@0: do_check_eq(source, result); michael@0: } michael@0: run_next_test(); michael@0: } michael@0: michael@0: add_test(test_base64_roundtrip); michael@0: add_test(test_dsa); michael@0: add_test(test_rsa); michael@0: add_test(test_base64UrlEncode); michael@0: add_test(test_base64UrlDecode); michael@0: michael@0: function run_test() { michael@0: run_next_test(); michael@0: }