Bug 914685 - 0001. Support GSM network pin authentication. r=vicamo
authorChuck Lee <chulee@mozilla.com>
Mon, 14 Oct 2013 14:47:50 +0800
changeset 165001 97fc306366aa620a2de1a4c77f224fbdb708cb8b
parent 165000 11a939307058260ac27ff2e39a8455c702c27be4
child 165002 4c913587603866c4af28b9da451467db5b323ce2
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvicamo
bugs914685
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 914685 - 0001. Support GSM network pin authentication. r=vicamo
dom/wappush/src/gonk/CpPduHelper.jsm
dom/wappush/src/gonk/WapPushManager.js
--- a/dom/wappush/src/gonk/CpPduHelper.jsm
+++ b/dom/wappush/src/gonk/CpPduHelper.jsm
@@ -6,16 +6,19 @@
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 let WSP = {};
 Cu.import("resource://gre/modules/WspPduHelper.jsm", WSP);
 let WBXML = {};
 Cu.import("resource://gre/modules/WbxmlPduHelper.jsm", WBXML);
 
+Cu.import("resource://services-crypto/utils.js");
+Cu.import("resource://services-common/utils.js");
+
 // set to true to see debug messages
 let DEBUG = WBXML.DEBUG_ALL | false;
 
 /**
  * Public identifier for CP
  *
  * @see http://technical.openmobilealliance.org/tech/omna/omna-wbxml-public-docid.aspx
  */
@@ -79,16 +82,138 @@ this.PduHelper = {
       msg.content = data.array;
     }
     return msg;
 
   }
 };
 
 /**
+ * SEC type values
+ *
+ * @see WAP-183-ProvCont-20010724-A, clause 5.3
+ */
+const AUTH_SEC_TYPE = (function () {
+  let names = {};
+  function add(name, number) {
+    names[number] = name;
+  }
+
+  add("NETWPIN",      0);
+  add("USERPIN",      1);
+  add("USERNETWPIN",  2);
+  add("USERPINMAC",   3);
+
+  return names;
+})();
+
+this.Authenticator = {
+  /**
+   * Format IMSI string into GSM format
+   *
+   * @param imsi
+   *        IMSI string
+   *
+   * @return IMSI in GSM format as string object
+   */
+  formatImsi: function formatImsi(imsi) {
+    let parityByte = ((imsi.length & 1) ? 9 : 1);
+
+    // Make sure length of IMSI is 15 digits.
+    // @see GSM 11.11, clause 10.2.2
+    let i = 0;
+    for (i = 15 - imsi.length; i > 0; i--) {
+      imsi += "F";
+    }
+
+    // char-by-char atoi
+    let imsiValue = [];
+    imsiValue.push(parityByte);
+    for (i = 0; i < imsi.length; i++) {
+      imsiValue.push(parseInt(imsi.substr(i, 1), 10));
+    }
+
+    // encoded IMSI
+    let imsiEncoded = "";
+    for (i = 0; i < imsiValue.length; i += 2) {
+      imsiEncoded += String.fromCharCode(imsiValue[i] | (imsiValue[i+1] << 4));
+    }
+
+    return imsiEncoded;
+  },
+
+  /**
+   * Perform HMAC check
+   *
+   * @param wbxml
+   *        Uint8 typed array of raw WBXML data.
+   * @param key
+   *        key string for HMAC check.
+   * @param mac
+   *        Expected MAC value.
+   *
+   * @return true for valid, false for invalid.
+   */
+  isValid: function isValid(wbxml, key, mac) {
+    let hasher = CryptoUtils.makeHMACHasher(Ci.nsICryptoHMAC.SHA1,
+                                            CryptoUtils.makeHMACKey(key));
+    hasher.update(wbxml, wbxml.length);
+    let result = CommonUtils.bytesAsHex(hasher.finish(false)).toUpperCase();
+    return mac == result;
+  },
+
+  /**
+   * Perform HMAC authentication.
+   *
+   * @param wbxml
+   *        Uint8 typed array of raw WBXML data.
+   * @param sec
+   *        Security method for HMAC check.
+   * @param mac
+   *        Expected MAC value.
+   * @param getNetworkPin
+   *        Callback function for getting network pin.
+   *
+   * @return true for valid, false for invalid.
+   */
+  check: function check_hmac(wbxml, sec, mac, getNetworkPin) {
+    // No security set.
+    if (sec == null || !mac) {
+      return null;
+    }
+
+    let authInfo = {
+      pass: false,
+      checked: false,
+      sec: AUTH_SEC_TYPE[sec],
+      mac: mac.toUpperCase(),
+      dataLength: wbxml.length,
+      data: wbxml
+    };
+
+    switch (authInfo.sec) {
+      case "NETWPIN":
+        let key = getNetworkPin();
+        authInfo.pass = this.isValid(wbxml, key, authInfo.mac);
+        authInfo.checked = true;
+        return authInfo;
+
+      case "USERPIN":
+      case "USERPINMAC":
+        // We can't check without USER PIN
+        return authInfo;
+
+      case "USERNETWPIN":
+      default:
+        return null;
+    }
+  }
+};
+
+/**
   * Tag tokens
   *
   * @see WAP-183-ProvCont-20010724-A, clause 8.1 for code page 0
   * @see OMA-WAP-TS-ProvCont-V1_1-20090421-C, clause 7.1 for code page 1
   */
 const CP_TAG_FIELDS = (function () {
   let names = {};
   function add(name, codepage, number) {
@@ -342,9 +467,11 @@ if (DEBUG) {
   };
 } else {
   debug = function (s) {};
 }
 
 this.EXPORTED_SYMBOLS = [
   // Parser
   "PduHelper",
+  // HMAC Authenticator
+  "Authenticator",
 ];
--- a/dom/wappush/src/gonk/WapPushManager.js
+++ b/dom/wappush/src/gonk/WapPushManager.js
@@ -32,16 +32,19 @@ XPCOMUtils.defineLazyGetter(this, "CP", 
   let CP = {};
   Cu.import("resource://gre/modules/CpPduHelper.jsm", CP);
   return CP;
 });
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
                                    "@mozilla.org/system-message-internal;1",
                                    "nsISystemMessagesInternal");
+XPCOMUtils.defineLazyServiceGetter(this, "gRIL",
+                                   "@mozilla.org/ril;1",
+                                   "nsIRadioInterfaceLayer");
 
 /**
  * Helpers for WAP PDU processing.
  */
 this.WapPushManager = {
 
   /**
    * Parse raw PDU data and deliver to a proper target.
@@ -86,25 +89,38 @@ this.WapPushManager = {
     * SL(WBXML)           "application/vnd.wap.slc"                 "x-wap-application:wml.ua"
     * Provisioning        "text/vnd.wap.connectivity-xml"           "x-wap-application:wml.ua"
     * Provisioning(WBXML) "application/vnd.wap.connectivity-wbxml"  "x-wap-application:wml.ua"
     *
     * @see http://technical.openmobilealliance.org/tech/omna/omna-wsp-content-type.aspx
     */
     let contentType = options.headers["content-type"].media;
     let msg;
+    let authInfo = null;
 
     if (contentType === "text/vnd.wap.si" ||
         contentType === "application/vnd.wap.sic") {
       msg = SI.PduHelper.parse(data, contentType);
     } else if (contentType === "text/vnd.wap.sl" ||
                contentType === "application/vnd.wap.slc") {
       msg = SL.PduHelper.parse(data, contentType);
     } else if (contentType === "text/vnd.wap.connectivity-xml" ||
                contentType === "application/vnd.wap.connectivity-wbxml") {
+      // Apply HMAC authentication on WBXML encoded CP message.
+      if (contentType === "application/vnd.wap.connectivity-wbxml") {
+        let params = options.headers["content-type"].params;
+        let sec = params && params.sec;
+        let mac = params && params.mac;
+        authInfo = CP.Authenticator.check(data.array.subarray(data.offset),
+                                          sec, mac, function getNetworkPin() {
+          let imsi = gRIL.getRadioInterface(0).rilContext.imsi;
+          return CP.Authenticator.formatImsi(imsi);
+        });
+      }
+
       msg = CP.PduHelper.parse(data, contentType);
     } else {
       // Unsupported type, provide raw data.
       msg = {
         contentType: contentType,
         content: data.array
       };
     }
@@ -113,17 +129,18 @@ this.WapPushManager = {
     let parsedSender = PhoneNumberUtils.parse(sender);
     if (parsedSender && parsedSender.internationalNumber) {
       sender = parsedSender.internationalNumber;
     }
 
     gSystemMessenger.broadcastMessage("wappush-received", {
       sender:         sender,
       contentType:    msg.contentType,
-      content:        msg.content
+      content:        msg.content,
+      authInfo:       authInfo
     });
   },
 
   /**
    * @param array
    *        A Uint8Array or an octet array representing raw PDU data.
    * @param length
    *        Length of the array.