toolkit/identity/tests/unit/test_jwcrypto.js

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:eb9801498421
1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
3
4 "use strict"
5
6 Cu.import('resource://gre/modules/identity/LogUtils.jsm');
7
8 XPCOMUtils.defineLazyModuleGetter(this, "IDService",
9 "resource://gre/modules/identity/Identity.jsm",
10 "IdentityService");
11
12 XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto",
13 "resource://gre/modules/identity/jwcrypto.jsm");
14
15 XPCOMUtils.defineLazyServiceGetter(this,
16 "CryptoService",
17 "@mozilla.org/identity/crypto-service;1",
18 "nsIIdentityCryptoService");
19
20 const RP_ORIGIN = "http://123done.org";
21 const INTERNAL_ORIGIN = "browserid://";
22
23 const SECOND_MS = 1000;
24 const MINUTE_MS = SECOND_MS * 60;
25 const HOUR_MS = MINUTE_MS * 60;
26
27 function test_sanity() {
28 do_test_pending();
29
30 jwcrypto.generateKeyPair("DS160", function(err, kp) {
31 do_check_null(err);
32
33 do_test_finished();
34 run_next_test();
35 });
36 }
37
38 function test_generate() {
39 do_test_pending();
40 jwcrypto.generateKeyPair("DS160", function(err, kp) {
41 do_check_null(err);
42 do_check_neq(kp, null);
43
44 do_test_finished();
45 run_next_test();
46 });
47 }
48
49 function test_get_assertion() {
50 do_test_pending();
51
52 jwcrypto.generateKeyPair(
53 "DS160",
54 function(err, kp) {
55 jwcrypto.generateAssertion("fake-cert", kp, RP_ORIGIN, (err, backedAssertion) => {
56 do_check_null(err);
57
58 do_check_eq(backedAssertion.split("~").length, 2);
59 do_check_eq(backedAssertion.split(".").length, 3);
60
61 do_test_finished();
62 run_next_test();
63 });
64 });
65 }
66
67 function test_rsa() {
68 do_test_pending();
69 function checkRSA(err, kpo) {
70 do_check_neq(kpo, undefined);
71 log(kpo.serializedPublicKey);
72 let pk = JSON.parse(kpo.serializedPublicKey);
73 do_check_eq(pk.algorithm, "RS");
74 /* TODO
75 do_check_neq(kpo.sign, null);
76 do_check_eq(typeof kpo.sign, "function");
77 do_check_neq(kpo.userID, null);
78 do_check_neq(kpo.url, null);
79 do_check_eq(kpo.url, INTERNAL_ORIGIN);
80 do_check_neq(kpo.exponent, null);
81 do_check_neq(kpo.modulus, null);
82
83 // TODO: should sign be async?
84 let sig = kpo.sign("This is a message to sign");
85
86 do_check_neq(sig, null);
87 do_check_eq(typeof sig, "string");
88 do_check_true(sig.length > 1);
89 */
90 do_test_finished();
91 run_next_test();
92 };
93
94 jwcrypto.generateKeyPair("RS256", checkRSA);
95 }
96
97 function test_dsa() {
98 do_test_pending();
99 function checkDSA(err, kpo) {
100 do_check_neq(kpo, undefined);
101 log(kpo.serializedPublicKey);
102 let pk = JSON.parse(kpo.serializedPublicKey);
103 do_check_eq(pk.algorithm, "DS");
104 /* TODO
105 do_check_neq(kpo.sign, null);
106 do_check_eq(typeof kpo.sign, "function");
107 do_check_neq(kpo.userID, null);
108 do_check_neq(kpo.url, null);
109 do_check_eq(kpo.url, INTERNAL_ORIGIN);
110 do_check_neq(kpo.generator, null);
111 do_check_neq(kpo.prime, null);
112 do_check_neq(kpo.subPrime, null);
113 do_check_neq(kpo.publicValue, null);
114
115 let sig = kpo.sign("This is a message to sign");
116
117 do_check_neq(sig, null);
118 do_check_eq(typeof sig, "string");
119 do_check_true(sig.length > 1);
120 */
121 do_test_finished();
122 run_next_test();
123 };
124
125 jwcrypto.generateKeyPair("DS160", checkDSA);
126 }
127
128 function test_get_assertion_with_offset() {
129 do_test_pending();
130
131
132 // Use an arbitrary date in the past to ensure we don't accidentally pass
133 // this test with current dates, missing offsets, etc.
134 let serverMsec = Date.parse("Tue Oct 31 2000 00:00:00 GMT-0800");
135
136 // local clock skew
137 // clock is 12 hours fast; -12 hours offset must be applied
138 let localtimeOffsetMsec = -1 * 12 * HOUR_MS;
139 let localMsec = serverMsec - localtimeOffsetMsec;
140
141 jwcrypto.generateKeyPair(
142 "DS160",
143 function(err, kp) {
144 jwcrypto.generateAssertion("fake-cert", kp, RP_ORIGIN,
145 { duration: MINUTE_MS,
146 localtimeOffsetMsec: localtimeOffsetMsec,
147 now: localMsec},
148 function(err, backedAssertion) {
149 do_check_null(err);
150
151 // properly formed
152 let cert;
153 let assertion;
154 [cert, assertion] = backedAssertion.split("~");
155
156 do_check_eq(cert, "fake-cert");
157 do_check_eq(assertion.split(".").length, 3);
158
159 let components = extractComponents(assertion);
160
161 // Expiry is within two minutes, corrected for skew
162 let exp = parseInt(components.payload.exp, 10);
163 do_check_true(exp - serverMsec === MINUTE_MS);
164
165 do_test_finished();
166 run_next_test();
167 }
168 );
169 }
170 );
171 }
172
173 function test_assertion_lifetime() {
174 do_test_pending();
175
176 jwcrypto.generateKeyPair(
177 "DS160",
178 function(err, kp) {
179 jwcrypto.generateAssertion("fake-cert", kp, RP_ORIGIN,
180 {duration: MINUTE_MS},
181 function(err, backedAssertion) {
182 do_check_null(err);
183
184 // properly formed
185 let cert;
186 let assertion;
187 [cert, assertion] = backedAssertion.split("~");
188
189 do_check_eq(cert, "fake-cert");
190 do_check_eq(assertion.split(".").length, 3);
191
192 let components = extractComponents(assertion);
193
194 // Expiry is within one minute, as we specified above
195 let exp = parseInt(components.payload.exp, 10);
196 do_check_true(Math.abs(Date.now() - exp) > 50 * SECOND_MS);
197 do_check_true(Math.abs(Date.now() - exp) <= MINUTE_MS);
198
199 do_test_finished();
200 run_next_test();
201 }
202 );
203 }
204 );
205 }
206
207 function test_audience_encoding_bug972582() {
208 let audience = "i-like-pie.com";
209
210 jwcrypto.generateKeyPair(
211 "DS160",
212 function(err, kp) {
213 do_check_null(err);
214 jwcrypto.generateAssertion("fake-cert", kp, audience,
215 function(err, backedAssertion) {
216 do_check_null(err);
217
218 let [cert, assertion] = backedAssertion.split("~");
219 let components = extractComponents(assertion);
220 do_check_eq(components.payload.aud, audience);
221
222 do_test_finished();
223 run_next_test();
224 }
225 );
226 }
227 );
228 }
229
230 // End of tests
231 // Helper function follow
232
233 function extractComponents(signedObject) {
234 if (typeof(signedObject) != 'string') {
235 throw new Error("malformed signature " + typeof(signedObject));
236 }
237
238 let parts = signedObject.split(".");
239 if (parts.length != 3) {
240 throw new Error("signed object must have three parts, this one has " + parts.length);
241 }
242
243 let headerSegment = parts[0];
244 let payloadSegment = parts[1];
245 let cryptoSegment = parts[2];
246
247 let header = JSON.parse(base64UrlDecode(headerSegment));
248 let payload = JSON.parse(base64UrlDecode(payloadSegment));
249
250 // Ensure well-formed header
251 do_check_eq(Object.keys(header).length, 1);
252 do_check_true(!!header.alg);
253
254 // Ensure well-formed payload
255 for (let field of ["exp", "aud"]) {
256 do_check_true(!!payload[field]);
257 }
258
259 return {header: header,
260 payload: payload,
261 headerSegment: headerSegment,
262 payloadSegment: payloadSegment,
263 cryptoSegment: cryptoSegment};
264 };
265
266 let TESTS = [
267 test_sanity,
268 test_generate,
269 test_get_assertion,
270 test_get_assertion_with_offset,
271 test_assertion_lifetime,
272 test_audience_encoding_bug972582,
273 ];
274
275 TESTS = TESTS.concat([test_rsa, test_dsa]);
276
277 TESTS.forEach(add_test);
278
279 function run_test() {
280 run_next_test();
281 }

mercurial