summaryrefslogtreecommitdiffstats
path: root/services/crypto/tests/unit/test_crypto_service.js
blob: 848892411366a008a74b0a22574d92da34777798 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

const idService = Cc["@mozilla.org/identity/crypto-service;1"].getService(
  Ci.nsIIdentityCryptoService
);

const ALG_DSA = "DS160";
const ALG_RSA = "RS256";

const BASE64_URL_ENCODINGS = [
  // The vectors from RFC 4648 are very silly, but we may as well include them.
  ["", ""],
  ["f", "Zg=="],
  ["fo", "Zm8="],
  ["foo", "Zm9v"],
  ["foob", "Zm9vYg=="],
  ["fooba", "Zm9vYmE="],
  ["foobar", "Zm9vYmFy"],

  // It's quite likely you could get a string like this in an assertion audience
  ["i-like-pie.com", "aS1saWtlLXBpZS5jb20="],

  // A few extra to be really sure
  ["andré@example.com", "YW5kcsOpQGV4YW1wbGUuY29t"],
  [
    "πόλλ' οἶδ' ἀλώπηξ, ἀλλ' ἐχῖνος ἓν μέγα",
    "z4DPjM67zrsnIM6_4by2zrQnIOG8gM67z47PgM63zr4sIOG8gM67zrsnIOG8kM-H4b-Wzr3Ov8-CIOG8k869IM68zq3Os86x",
  ],
];

let log = Log.repository.getLogger("crypto.service.test");
(function() {
  let appender = new Log.DumpAppender();
  log.level = Log.Level.Debug;
  log.addAppender(appender);
})();

// When the output of an operation is a
function do_check_eq_or_slightly_less(x, y) {
  Assert.ok(x >= y - 3 * 8);
}

function test_base64_roundtrip() {
  let message = "Attack at dawn!";
  let encoded = idService.base64UrlEncode(message);
  let decoded = base64UrlDecode(encoded);
  Assert.notEqual(message, encoded);
  Assert.equal(decoded, message);
  run_next_test();
}

function test_dsa() {
  idService.generateKeyPair(ALG_DSA, function(rv, keyPair) {
    log.debug("DSA generateKeyPair finished " + rv);
    Assert.ok(Components.isSuccessCode(rv));
    Assert.equal(typeof keyPair.sign, "function");
    Assert.equal(keyPair.keyType, ALG_DSA);
    do_check_eq_or_slightly_less(
      keyPair.hexDSAGenerator.length,
      (1024 / 8) * 2
    );
    do_check_eq_or_slightly_less(keyPair.hexDSAPrime.length, (1024 / 8) * 2);
    do_check_eq_or_slightly_less(keyPair.hexDSASubPrime.length, (160 / 8) * 2);
    do_check_eq_or_slightly_less(
      keyPair.hexDSAPublicValue.length,
      (1024 / 8) * 2
    );
    // XXX: test that RSA parameters throw the correct error

    log.debug("about to sign with DSA key");
    keyPair.sign("foo", function(rv2, signature) {
      log.debug("DSA sign finished " + rv2 + " " + signature);
      Assert.ok(Components.isSuccessCode(rv2));
      Assert.ok(signature.length > 1);
      // TODO: verify the signature with the public key
      run_next_test();
    });
  });
}

function test_rsa() {
  idService.generateKeyPair(ALG_RSA, function(rv, keyPair) {
    log.debug("RSA generateKeyPair finished " + rv);
    Assert.ok(Components.isSuccessCode(rv));
    Assert.equal(typeof keyPair.sign, "function");
    Assert.equal(keyPair.keyType, ALG_RSA);
    do_check_eq_or_slightly_less(
      keyPair.hexRSAPublicKeyModulus.length,
      2048 / 8
    );
    Assert.ok(keyPair.hexRSAPublicKeyExponent.length > 1);

    log.debug("about to sign with RSA key");
    keyPair.sign("foo", function(rv2, signature) {
      log.debug("RSA sign finished " + rv2 + " " + signature);
      Assert.ok(Components.isSuccessCode(rv2));
      Assert.ok(signature.length > 1);
      run_next_test();
    });
  });
}

function test_base64UrlEncode() {
  for (let [source, target] of BASE64_URL_ENCODINGS) {
    Assert.equal(target, idService.base64UrlEncode(source));
  }
  run_next_test();
}

function test_base64UrlDecode() {
  let utf8Converter = Cc[
    "@mozilla.org/intl/scriptableunicodeconverter"
  ].createInstance(Ci.nsIScriptableUnicodeConverter);
  utf8Converter.charset = "UTF-8";

  // We know the encoding of our inputs - on conversion back out again, make
  // sure they're the same.
  for (let [source, target] of BASE64_URL_ENCODINGS) {
    let result = utf8Converter.ConvertToUnicode(base64UrlDecode(target));
    result += utf8Converter.Finish();
    Assert.equal(source, result);
  }
  run_next_test();
}

add_test(test_base64_roundtrip);
add_test(test_dsa);
add_test(test_rsa);
add_test(test_base64UrlEncode);
add_test(test_base64UrlDecode);