|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 "use strict"; |
|
6 |
|
7 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; |
|
8 |
|
9 let WSP = {}; |
|
10 Cu.import("resource://gre/modules/WspPduHelper.jsm", WSP); |
|
11 let WBXML = {}; |
|
12 Cu.import("resource://gre/modules/WbxmlPduHelper.jsm", WBXML); |
|
13 |
|
14 Cu.import("resource://services-crypto/utils.js"); |
|
15 Cu.import("resource://services-common/utils.js"); |
|
16 |
|
17 // set to true to see debug messages |
|
18 let DEBUG = WBXML.DEBUG_ALL | false; |
|
19 |
|
20 /** |
|
21 * Public identifier for CP |
|
22 * |
|
23 * @see http://technical.openmobilealliance.org/tech/omna/omna-wbxml-public-docid.aspx |
|
24 */ |
|
25 const PUBLIC_IDENTIFIER_CP = "-//WAPFORUM//DTD PROV 1.0//EN"; |
|
26 |
|
27 this.PduHelper = { |
|
28 |
|
29 /** |
|
30 * @param data |
|
31 * A wrapped object containing raw PDU data. |
|
32 * @param contentType |
|
33 * Content type of incoming CP message, should be "text/vnd.wap.connectivity-xml" |
|
34 * or "application/vnd.wap.connectivity-wbxml". |
|
35 * |
|
36 * @return A message object containing attribute content and contentType. |
|
37 * |content| will contain string of decoded CP message if successfully |
|
38 * decoded, or raw data if failed. |
|
39 * |contentType| will be string representing corresponding type of |
|
40 * content. |
|
41 */ |
|
42 parse: function parse_cp(data, contentType) { |
|
43 // We only need content and contentType |
|
44 let msg = { |
|
45 contentType: contentType |
|
46 }; |
|
47 |
|
48 /** |
|
49 * Message is compressed by WBXML, decode into string. |
|
50 * |
|
51 * @see WAP-192-WBXML-20010725-A |
|
52 */ |
|
53 if (contentType === "application/vnd.wap.connectivity-wbxml") { |
|
54 let appToken = { |
|
55 publicId: PUBLIC_IDENTIFIER_CP, |
|
56 tagTokenList: CP_TAG_FIELDS, |
|
57 attrTokenList: CP_ATTRIBUTE_FIELDS, |
|
58 valueTokenList: CP_VALUE_FIELDS, |
|
59 globalTokenOverride: null |
|
60 } |
|
61 |
|
62 try { |
|
63 let parseResult = WBXML.PduHelper.parse(data, appToken, msg); |
|
64 msg.content = parseResult.content; |
|
65 msg.contentType = "text/vnd.wap.connectivity-xml"; |
|
66 } catch (e) { |
|
67 // Provide raw data if we failed to parse. |
|
68 msg.content = data.array; |
|
69 } |
|
70 |
|
71 return msg; |
|
72 } |
|
73 |
|
74 /** |
|
75 * Message is plain text, transform raw to string. |
|
76 */ |
|
77 try { |
|
78 let stringData = WSP.Octet.decodeMultiple(data, data.array.length); |
|
79 msg.content = WSP.PduHelper.decodeStringContent(stringData, "UTF-8"); |
|
80 } catch (e) { |
|
81 // Provide raw data if we failed to parse. |
|
82 msg.content = data.array; |
|
83 } |
|
84 return msg; |
|
85 |
|
86 } |
|
87 }; |
|
88 |
|
89 /** |
|
90 * SEC type values |
|
91 * |
|
92 * @see WAP-183-ProvCont-20010724-A, clause 5.3 |
|
93 */ |
|
94 const AUTH_SEC_TYPE = (function () { |
|
95 let names = {}; |
|
96 function add(name, number) { |
|
97 names[number] = name; |
|
98 } |
|
99 |
|
100 add("NETWPIN", 0); |
|
101 add("USERPIN", 1); |
|
102 add("USERNETWPIN", 2); |
|
103 add("USERPINMAC", 3); |
|
104 |
|
105 return names; |
|
106 })(); |
|
107 |
|
108 this.Authenticator = { |
|
109 /** |
|
110 * Format IMSI string into GSM format |
|
111 * |
|
112 * @param imsi |
|
113 * IMSI string |
|
114 * |
|
115 * @return IMSI in GSM format as string object |
|
116 */ |
|
117 formatImsi: function formatImsi(imsi) { |
|
118 let parityByte = ((imsi.length & 1) ? 9 : 1); |
|
119 |
|
120 // Make sure length of IMSI is 15 digits. |
|
121 // @see GSM 11.11, clause 10.2.2 |
|
122 let i = 0; |
|
123 for (i = 15 - imsi.length; i > 0; i--) { |
|
124 imsi += "F"; |
|
125 } |
|
126 |
|
127 // char-by-char atoi |
|
128 let imsiValue = []; |
|
129 imsiValue.push(parityByte); |
|
130 for (i = 0; i < imsi.length; i++) { |
|
131 imsiValue.push(parseInt(imsi.substr(i, 1), 10)); |
|
132 } |
|
133 |
|
134 // encoded IMSI |
|
135 let imsiEncoded = ""; |
|
136 for (i = 0; i < imsiValue.length; i += 2) { |
|
137 imsiEncoded += String.fromCharCode(imsiValue[i] | (imsiValue[i+1] << 4)); |
|
138 } |
|
139 |
|
140 return imsiEncoded; |
|
141 }, |
|
142 |
|
143 /** |
|
144 * Perform HMAC check |
|
145 * |
|
146 * @param wbxml |
|
147 * Uint8 typed array of raw WBXML data. |
|
148 * @param key |
|
149 * key string for HMAC check. |
|
150 * @param mac |
|
151 * Expected MAC value. |
|
152 * |
|
153 * @return true for valid, false for invalid. |
|
154 */ |
|
155 isValid: function isValid(wbxml, key, mac) { |
|
156 let hasher = CryptoUtils.makeHMACHasher(Ci.nsICryptoHMAC.SHA1, |
|
157 CryptoUtils.makeHMACKey(key)); |
|
158 hasher.update(wbxml, wbxml.length); |
|
159 let result = CommonUtils.bytesAsHex(hasher.finish(false)).toUpperCase(); |
|
160 return mac == result; |
|
161 }, |
|
162 |
|
163 /** |
|
164 * Perform HMAC authentication. |
|
165 * |
|
166 * @param wbxml |
|
167 * Uint8 typed array of raw WBXML data. |
|
168 * @param sec |
|
169 * Security method for HMAC check. |
|
170 * @param mac |
|
171 * Expected MAC value. |
|
172 * @param getNetworkPin |
|
173 * Callback function for getting network pin. |
|
174 * |
|
175 * @return true for valid, false for invalid. |
|
176 */ |
|
177 check: function check_hmac(wbxml, sec, mac, getNetworkPin) { |
|
178 // No security set. |
|
179 if (sec == null || !mac) { |
|
180 return null; |
|
181 } |
|
182 |
|
183 let authInfo = { |
|
184 pass: false, |
|
185 checked: false, |
|
186 sec: AUTH_SEC_TYPE[sec], |
|
187 mac: mac.toUpperCase(), |
|
188 data: wbxml |
|
189 }; |
|
190 |
|
191 switch (authInfo.sec) { |
|
192 case "NETWPIN": |
|
193 let key = getNetworkPin(); |
|
194 authInfo.pass = this.isValid(wbxml, key, authInfo.mac); |
|
195 authInfo.checked = true; |
|
196 return authInfo; |
|
197 |
|
198 case "USERPIN": |
|
199 case "USERPINMAC": |
|
200 // We can't check without USER PIN |
|
201 return authInfo; |
|
202 |
|
203 case "USERNETWPIN": |
|
204 default: |
|
205 return null; |
|
206 } |
|
207 } |
|
208 }; |
|
209 |
|
210 /** |
|
211 * Tag tokens |
|
212 * |
|
213 * @see OMA-WAP-TS-ProvCont-V1_1-20090421-C, clause 7.1 |
|
214 */ |
|
215 const CP_TAG_FIELDS = (function () { |
|
216 let names = {}; |
|
217 function add(name, codepage, number) { |
|
218 let entry = { |
|
219 name: name, |
|
220 number: number, |
|
221 }; |
|
222 if (!names[codepage]) { |
|
223 names[codepage] = {}; |
|
224 } |
|
225 names[codepage][number] = entry; |
|
226 } |
|
227 |
|
228 // Code page 0 |
|
229 add("wap-provisioningdoc", 0, 0x05); |
|
230 add("characteristic", 0, 0x06); |
|
231 add("parm", 0, 0x07); |
|
232 // Code page 1 |
|
233 add("characteristic", 1, 0x06); |
|
234 add("parm", 1, 0x07); |
|
235 |
|
236 return names; |
|
237 })(); |
|
238 |
|
239 /** |
|
240 * Attribute Tokens |
|
241 * |
|
242 * @see OMA-WAP-TS-ProvCont-V1_1-20090421-C, clause 7.2 |
|
243 */ |
|
244 const CP_ATTRIBUTE_FIELDS = (function () { |
|
245 let names = {}; |
|
246 function add(name, value, codepage, number) { |
|
247 let entry = { |
|
248 name: name, |
|
249 value: value, |
|
250 number: number, |
|
251 }; |
|
252 if (!names[codepage]) { |
|
253 names[codepage] = {}; |
|
254 } |
|
255 names[codepage][number] = entry; |
|
256 } |
|
257 |
|
258 // Code page 0 |
|
259 add("name", "", 0, 0x05); |
|
260 add("value", "", 0, 0x06); |
|
261 add("name", "NAME", 0, 0x07); |
|
262 add("name", "NAP-ADDRESS", 0, 0x08); |
|
263 add("name", "NAP-ADDRTYPE", 0, 0x09); |
|
264 add("name", "CALLTYPE", 0, 0x0A); |
|
265 add("name", "VALIDUNTIL", 0, 0x0B); |
|
266 add("name", "AUTHTYPE", 0, 0x0C); |
|
267 add("name", "AUTHNAME", 0, 0x0D); |
|
268 add("name", "AUTHSECRET", 0, 0x0E); |
|
269 add("name", "LINGER", 0, 0x0F); |
|
270 add("name", "BEARER", 0, 0x10); |
|
271 add("name", "NAPID", 0, 0x11); |
|
272 add("name", "COUNTRY", 0, 0x12); |
|
273 add("name", "NETWORK", 0, 0x13); |
|
274 add("name", "INTERNET", 0, 0x14); |
|
275 add("name", "PROXY-ID", 0, 0x15); |
|
276 add("name", "PROXY-PROVIDER-ID", 0, 0x16); |
|
277 add("name", "DOMAIN", 0, 0x17); |
|
278 add("name", "PROVURL", 0, 0x18); |
|
279 add("name", "PXAUTH-TYPE", 0, 0x19); |
|
280 add("name", "PXAUTH-ID", 0, 0x1A); |
|
281 add("name", "PXAUTH-PW", 0, 0x1B); |
|
282 add("name", "STARTPAGE", 0, 0x1C); |
|
283 add("name", "BASAUTH-ID", 0, 0x1D); |
|
284 add("name", "BASAUTH-PW", 0, 0x1E); |
|
285 add("name", "PUSHENABLED", 0, 0x1F); |
|
286 add("name", "PXADDR", 0, 0x20); |
|
287 add("name", "PXADDRTYPE", 0, 0x21); |
|
288 add("name", "TO-NAPID", 0, 0x22); |
|
289 add("name", "PORTNBR", 0, 0x23); |
|
290 add("name", "SERVICE", 0, 0x24); |
|
291 add("name", "LINKSPEED", 0, 0x25); |
|
292 add("name", "DNLINKSPEED", 0, 0x26); |
|
293 add("name", "LOCAL-ADDR", 0, 0x27); |
|
294 add("name", "LOCAL-ADDRTYPE", 0, 0x28); |
|
295 add("name", "CONTEXT-ALLOW", 0, 0x29); |
|
296 add("name", "TRUST", 0, 0x2A); |
|
297 add("name", "MASTER", 0, 0x2B); |
|
298 add("name", "SID", 0, 0x2C); |
|
299 add("name", "SOC", 0, 0x2D); |
|
300 add("name", "WSP-VERSION", 0, 0x2E); |
|
301 add("name", "PHYSICAL-PROXY-ID", 0, 0x2F); |
|
302 add("name", "CLIENT-ID", 0, 0x30); |
|
303 add("name", "DELIVERY-ERR-PDU", 0, 0x31); |
|
304 add("name", "DELIVERY-ORDER", 0, 0x32); |
|
305 add("name", "TRAFFIC-CLASS", 0, 0x33); |
|
306 add("name", "MAX-SDU-SIZE", 0, 0x34); |
|
307 add("name", "MAX-BITRATE-UPLINK", 0, 0x35); |
|
308 add("name", "MAX-BITRATE-DNLINK", 0, 0x36); |
|
309 add("name", "RESIDUAL-BER", 0, 0x37); |
|
310 add("name", "SDU-ERROR-RATIO", 0, 0x38); |
|
311 add("name", "TRAFFIC-HANDL-PRIO", 0, 0x39); |
|
312 add("name", "TRANSFER-DELAY", 0, 0x3A); |
|
313 add("name", "GUARANTEED-BITRATE-UPLINK", 0, 0x3B); |
|
314 add("name", "GUARANTEED-BITRATE-DNLINK", 0, 0x3C); |
|
315 add("name", "PXADDR-FQDN", 0, 0x3D); |
|
316 add("name", "PROXY-PW", 0, 0x3E); |
|
317 add("name", "PPGAUTH-TYPE", 0, 0x3F); |
|
318 add("version", "", 0, 0x45); |
|
319 add("version", "1.0", 0, 0x46); |
|
320 add("name", "PULLENABLED", 0, 0x47); |
|
321 add("name", "DNS-ADDR", 0, 0x48); |
|
322 add("name", "MAX-NUM-RETRY", 0, 0x49); |
|
323 add("name", "FIRST-RETRY-TIMEOUT", 0, 0x4A); |
|
324 add("name", "REREG-THRESHOLD", 0, 0x4B); |
|
325 add("name", "T-BIT", 0, 0x4C); |
|
326 add("name", "AUTH-ENTITY", 0, 0x4E); |
|
327 add("name", "SPI", 0, 0x4F); |
|
328 add("type", "", 0, 0x50); |
|
329 add("type", "PXLOGICAL", 0, 0x51); |
|
330 add("type", "PXPHYSICAL", 0, 0x52); |
|
331 add("type", "PORT", 0, 0x53); |
|
332 add("type", "VALIDITY", 0, 0x54); |
|
333 add("type", "NAPDEF", 0, 0x55); |
|
334 add("type", "BOOTSTRAP", 0, 0x56); |
|
335 /* |
|
336 * Mark out VENDORCONFIG so if it is contained in message, parse |
|
337 * will failed and raw data is returned. |
|
338 */ |
|
339 // add("type", "VENDORCONFIG", 0, 0x57); |
|
340 add("type", "CLIENTIDENTITY", 0, 0x58); |
|
341 add("type", "PXAUTHINFO", 0, 0x59); |
|
342 add("type", "NAPAUTHINFO", 0, 0x5A); |
|
343 add("type", "ACCESS", 0, 0x5B); |
|
344 |
|
345 // Code page 1 |
|
346 add("name", "", 1, 0x05); |
|
347 add("value", "", 1, 0x06); |
|
348 add("name", "NAME", 1, 0x07); |
|
349 add("name", "INTERNET", 1, 0x14); |
|
350 add("name", "STARTPAGE", 1, 0x1C); |
|
351 add("name", "TO-NAPID", 1, 0x22); |
|
352 add("name", "PORTNBR", 1, 0x23); |
|
353 add("name", "SERVICE", 1, 0x24); |
|
354 add("name", "AACCEPT", 1, 0x2E); |
|
355 add("name", "AAUTHDATA", 1, 0x2F); |
|
356 add("name", "AAUTHLEVEL", 1, 0x30); |
|
357 add("name", "AAUTHNAME", 1, 0x31); |
|
358 add("name", "AAUTHSECRET", 1, 0x32); |
|
359 add("name", "AAUTHTYPE", 1, 0x33); |
|
360 add("name", "ADDR", 1, 0x34); |
|
361 add("name", "ADDRTYPE", 1, 0x35); |
|
362 add("name", "APPID", 1, 0x36); |
|
363 add("name", "APROTOCOL", 1, 0x37); |
|
364 add("name", "PROVIDER-ID", 1, 0x38); |
|
365 add("name", "TO-PROXY", 1, 0x39); |
|
366 add("name", "URI", 1, 0x3A); |
|
367 add("name", "RULE", 1, 0x3B); |
|
368 add("type", "", 1, 0x50); |
|
369 add("type", "PORT", 1, 0x53); |
|
370 add("type", "APPLICATION", 1, 0x55); |
|
371 add("type", "APPADDR", 1, 0x56); |
|
372 add("type", "APPAUTH", 1, 0x57); |
|
373 add("type", "CLIENTIDENTITY", 1, 0x58); |
|
374 add("type", "RESOURCE", 1, 0x59); |
|
375 |
|
376 return names; |
|
377 })(); |
|
378 |
|
379 /** |
|
380 * Value Tokens |
|
381 * |
|
382 * @see OMA-WAP-TS-ProvCont-V1_1-20090421-C, clause 7.3 |
|
383 */ |
|
384 const CP_VALUE_FIELDS = (function () { |
|
385 let names = {}; |
|
386 function add(value, codepage, number) { |
|
387 let entry = { |
|
388 value: value, |
|
389 number: number, |
|
390 }; |
|
391 if (!names[codepage]) { |
|
392 names[codepage] = {}; |
|
393 } |
|
394 names[codepage][number] = entry; |
|
395 } |
|
396 |
|
397 // Code page 0 |
|
398 add("IPV4", 0, 0x85); |
|
399 add("IPV6", 0, 0x86); |
|
400 add("E164", 0, 0x87); |
|
401 add("ALPHA", 0, 0x88); |
|
402 add("APN", 0, 0x89); |
|
403 add("SCODE", 0, 0x8A); |
|
404 add("TETRA-ITSI", 0, 0x8B); |
|
405 add("MAN", 0, 0x8C); |
|
406 add("ANALOG-MODEM", 0, 0x90); |
|
407 add("V.120", 0, 0x91); |
|
408 add("V.110", 0, 0x92); |
|
409 add("X.31", 0, 0x93); |
|
410 add("BIT-TRANSPARENT", 0, 0x94); |
|
411 add("DIRECT-ASYNCHRONOUS-DATA-SERVICE", 0, 0x95); |
|
412 add("PAP", 0, 0x9A); |
|
413 add("CHAP", 0, 0x9B); |
|
414 add("HTTP-BASIC", 0, 0x9C); |
|
415 add("HTTP-DIGEST", 0, 0x9D); |
|
416 add("WTLS-SS", 0, 0x9E); |
|
417 add("MD5", 0, 0x9F); // Added in OMA, 7.3.3 |
|
418 add("GSM-USSD", 0, 0xA2); |
|
419 add("GSM-SMS", 0, 0xA3); |
|
420 add("ANSI-136-GUTS", 0, 0xA4); |
|
421 add("IS-95-CDMA-SMS", 0, 0xA5); |
|
422 add("IS-95-CDMA-CSD", 0, 0xA6); |
|
423 add("IS-95-CDMA-PAC", 0, 0xA7); |
|
424 add("ANSI-136-CSD", 0, 0xA8); |
|
425 add("ANSI-136-GPRS", 0, 0xA9); |
|
426 add("GSM-CSD", 0, 0xAA); |
|
427 add("GSM-GPRS", 0, 0xAB); |
|
428 add("AMPS-CDPD", 0, 0xAC); |
|
429 add("PDC-CSD", 0, 0xAD); |
|
430 add("PDC-PACKET", 0, 0xAE); |
|
431 add("IDEN-SMS", 0, 0xAF); |
|
432 add("IDEN-CSD", 0, 0xB0); |
|
433 add("IDEN-PACKET", 0, 0xB1); |
|
434 add("FLEX/REFLEX", 0, 0xB2); |
|
435 add("PHS-SMS", 0, 0xB3); |
|
436 add("PHS-CSD", 0, 0xB4); |
|
437 add("TETRA-SDS", 0, 0xB5); |
|
438 add("TETRA-PACKET", 0, 0xB6); |
|
439 add("ANSI-136-GHOST", 0, 0xB7); |
|
440 add("MOBITEX-MPAK", 0, 0xB8); |
|
441 add("CDMA2000-1X-SIMPLE-IP", 0, 0xB9); // Added in OMA, 7.3.4 |
|
442 add("CDMA2000-1X-MOBILE-IP", 0, 0xBA); // Added in OMA, 7.3.4 |
|
443 add("AUTOBOUDING", 0, 0xC5); |
|
444 add("CL-WSP", 0, 0xCA); |
|
445 add("CO-WSP", 0, 0xCB); |
|
446 add("CL-SEC-WSP", 0, 0xCC); |
|
447 add("CO-SEC-WSP", 0, 0xCD); |
|
448 add("CL-SEC-WTA", 0, 0xCE); |
|
449 add("CO-SEC-WTA", 0, 0xCF); |
|
450 add("OTA-HTTP-TO", 0, 0xD0); // Added in OMA, 7.3.6 |
|
451 add("OTA-HTTP-TLS-TO", 0, 0xD1); // Added in OMA, 7.3.6 |
|
452 add("OTA-HTTP-PO", 0, 0xD2); // Added in OMA, 7.3.6 |
|
453 add("OTA-HTTP-TLS-PO", 0, 0xD3); // Added in OMA, 7.3.6 |
|
454 add("AAA", 0, 0xE0); // Added in OMA, 7.3.8 |
|
455 add("HA", 0, 0xE1); // Added in OMA, 7.3.8 |
|
456 |
|
457 // Code page 1 |
|
458 add("IPV6", 1, 0x86); |
|
459 add("E164", 1, 0x87); |
|
460 add("ALPHA", 1, 0x88); |
|
461 add("APPSRV", 1, 0x8D); |
|
462 add("OBEX", 1, 0x8E); |
|
463 add(",", 1, 0x90); |
|
464 add("HTTP-", 1, 0x91); |
|
465 add("BASIC", 1, 0x92); |
|
466 add("DIGEST", 1, 0x93); |
|
467 |
|
468 return names; |
|
469 })(); |
|
470 |
|
471 let debug; |
|
472 if (DEBUG) { |
|
473 debug = function (s) { |
|
474 dump("-$- CpPduHelper: " + s + "\n"); |
|
475 }; |
|
476 } else { |
|
477 debug = function (s) {}; |
|
478 } |
|
479 |
|
480 this.EXPORTED_SYMBOLS = [ |
|
481 // Parser |
|
482 "PduHelper", |
|
483 // HMAC Authenticator |
|
484 "Authenticator", |
|
485 ]; |