diff options
Diffstat (limited to 'dom/secureelement')
-rw-r--r-- | dom/secureelement/SEUtils.jsm | 116 | ||||
-rw-r--r-- | dom/secureelement/gonk/ACEService.js | 139 | ||||
-rw-r--r-- | dom/secureelement/gonk/ACEService.manifest | 2 | ||||
-rw-r--r-- | dom/secureelement/gonk/GPAccessRulesManager.js | 436 | ||||
-rw-r--r-- | dom/secureelement/gonk/GPAccessRulesManager.manifest | 2 | ||||
-rw-r--r-- | dom/secureelement/gonk/SecureElement.js | 514 | ||||
-rw-r--r-- | dom/secureelement/gonk/SecureElement.manifest | 18 | ||||
-rw-r--r-- | dom/secureelement/gonk/UiccConnector.js | 360 | ||||
-rw-r--r-- | dom/secureelement/gonk/UiccConnector.manifest | 17 | ||||
-rw-r--r-- | dom/secureelement/gonk/gp_consts.js | 62 | ||||
-rw-r--r-- | dom/secureelement/gonk/nsIAccessControlEnforcer.idl | 32 | ||||
-rw-r--r-- | dom/secureelement/gonk/nsIAccessRulesManager.idl | 50 | ||||
-rw-r--r-- | dom/secureelement/gonk/nsISecureElementConnector.idl | 124 | ||||
-rw-r--r-- | dom/secureelement/gonk/se_consts.js | 68 | ||||
-rw-r--r-- | dom/secureelement/moz.build | 24 |
15 files changed, 0 insertions, 1964 deletions
diff --git a/dom/secureelement/SEUtils.jsm b/dom/secureelement/SEUtils.jsm deleted file mode 100644 index d5980b19c..000000000 --- a/dom/secureelement/SEUtils.jsm +++ /dev/null @@ -1,116 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Copyright © 2015, Deutsche Telekom, Inc. */ - -"use strict"; - -this.SEUtils = { - byteArrayToHexString: function byteArrayToHexString(array) { - let hexStr = ""; - - let len = array ? array.length : 0; - for (let i = 0; i < len; i++) { - let hex = (array[i] & 0xff).toString(16); - hex = (hex.length === 1) ? "0" + hex : hex; - hexStr += hex; - } - - return hexStr.toUpperCase(); - }, - - hexStringToByteArray: function hexStringToByteArray(hexStr) { - if (typeof hexStr !== "string" || hexStr.length % 2 !== 0) { - return []; - } - - let array = []; - for (let i = 0, len = hexStr.length; i < len; i += 2) { - array.push(parseInt(hexStr.substr(i, 2), 16)); - } - - return array; - }, - - arraysEqual: function arraysEqual(a1, a2) { - if (!a1 || !a2) { - return false; - } - - if (a1.length !== a2.length) { - return false; - } - - for (let i = 0, len = a1.length; i < len; i++) { - if (a1[i] !== a2[i]) { - return false; - } - } - - return true; - }, - - ensureIsArray: function ensureIsArray(obj) { - return Array.isArray(obj) ? obj : [obj]; - }, - - /** - * parseTLV is intended primarily to be used to parse Global Platform Device - * Technology secure element access control data. - * - * The parsed result value is an internal format only. - * - * All tags will be treated as simple Tag Length Values (TLV), (i.e. with a - * plain value, not subject to further unpacking), unless those tags are - * listed in the containerTags array. - * - * @param bytes - byte array - * @param containerTags - byte array of tags - */ - parseTLV: function parseTLV(bytes, containerTags) { - let result = {}; - - if (typeof bytes === "string") { - bytes = this.hexStringToByteArray(bytes); - } - - if (!Array.isArray(bytes)) { - debug("Passed value is not an array nor a string."); - return null; - } - - for (let pos = 0; pos < bytes.length; ) { - let tag = bytes[pos], - length = bytes[pos + 1], - value = bytes.slice(pos + 2, pos + 2 + length), - parsed = null; - - // Support for 0xFF padded files (GPD 7.1.2) - if (tag === 0xFF) { - break; - } - - if (containerTags.indexOf(tag) >= 0) { - parsed = this.parseTLV(value, containerTags); - } else { - parsed = value; - } - - // Internal parsed format. - if (!result[tag]) { - result[tag] = parsed; - } else if (Array.isArray(result[tag])) { - result[tag].push(parsed); - } else { - result[tag] = [result[tag], parsed]; - } - - pos = pos + 2 + length; - } - - return result; - } -}; - -this.EXPORTED_SYMBOLS = ["SEUtils"]; diff --git a/dom/secureelement/gonk/ACEService.js b/dom/secureelement/gonk/ACEService.js deleted file mode 100644 index b52ba5fab..000000000 --- a/dom/secureelement/gonk/ACEService.js +++ /dev/null @@ -1,139 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Copyright © 2015, Deutsche Telekom, Inc. */ - -"use strict"; - -const { classes: Cc, interfaces: Ci, utils: Cu } = Components; -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "SEUtils", - "resource://gre/modules/SEUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "SE", function() { - let obj = {}; - Cu.import("resource://gre/modules/se_consts.js", obj); - return obj; -}); - -var DEBUG = SE.DEBUG_ACE; -function debug(msg) { - if (DEBUG) { - dump("ACEservice: " + msg + "\n"); - } -} - -/** - * Implements decision making algorithm as described in GPD specification, - * mostly in 3.1, 3.2 and 4.2.3. - * - * TODO: Bug 1137533: Implement GPAccessRulesManager APDU filters - */ -function GPAccessDecision(rules, certHash, aid) { - this.rules = rules; - this.certHash = certHash; - this.aid = aid; -} - -GPAccessDecision.prototype = { - isAccessAllowed: function isAccessAllowed() { - // GPD SE Access Control v1.1, 3.4.1, Table 3-2: (Conflict resolution) - // If a specific rule allows, all other non-specific access is denied. - // Conflicting specific rules will resolve to the first Allowed == "true" - // match. Given no specific rule, the global "All" rules will determine - // access. "Some", skips further processing if access Allowed == "true". - // - // Access must be decided before the SE connector openChannel, and the - // exchangeAPDU call. - // - // NOTE: This implementation may change with the introduction of APDU - // filters. - let decision = this.rules.some(this._decideAppAccess.bind(this)); - return decision; - }, - - _decideAppAccess: function _decideAppAccess(rule) { - let appMatched, appletMatched; - - // GPD SE AC 4.2.3: Algorithm for Applying Rules - // Specific rule overrides global rule. - // - // DeviceAppID is the application hash, and the AID is SE Applet ID: - // - // GPD SE AC 4.2.3 A: - // SearchRuleFor(DeviceAppID, AID) - // GPD SE AC 4.2.3 B: If no rule fits A: - // SearchRuleFor(<AllDeviceApplications>, AID) - // GPD SE AC 4.2.3 C: If no rule fits A or B: - // SearchRuleFor(DeviceAppID, <AllSEApplications>) - // GPD SE AC 4.2.3 D: If no rule fits A, B, or C: - // SearchRuleFor(<AllDeviceApplications>, <AllSEApplications>) - - // Device App - appMatched = Array.isArray(rule.application) ? - // GPD SE AC 4.2.3 A and 4.2.3 C (DeviceAppID rule) - this._appCertHashMatches(rule.application) : - // GPD SE AC 4.2.3 B and 4.2.3 D (All Device Applications) - rule.application === Ci.nsIAccessRulesManager.ALLOW_ALL; - - if (!appMatched) { - return false; // bail out early. - } - - // SE Applet - appletMatched = Array.isArray(rule.applet) ? - // GPD SE AC 4.2.3 A and 4.2.3 B (AID rule) - SEUtils.arraysEqual(rule.applet, this.aid) : - // GPD SE AC 4.2.3 C and 4.2.3 D (All AID) - rule.applet === Ci.nsIAccessRulesManager.ALL_APPLET; - - return appletMatched; - }, - - _appCertHashMatches: function _appCertHashMatches(hashArray) { - if (!Array.isArray(hashArray)) { - return false; - } - - return !!(hashArray.find((hash) => { - return SEUtils.arraysEqual(hash, this.certHash); - })); - } -}; - -function ACEService() { - this._rulesManagers = new Map(); - - this._rulesManagers.set( - SE.TYPE_UICC, - Cc["@mozilla.org/secureelement/access-control/rules-manager;1"] - .createInstance(Ci.nsIAccessRulesManager)); -} - -ACEService.prototype = { - _rulesManagers: null, - - isAccessAllowed: function isAccessAllowed(localId, seType, aid) { - if(!Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps")) { - debug("Certified apps debug enabled, allowing access"); - return Promise.resolve(true); - } - - throw Components.results.NS_ERROR_NOT_IMPLEMENTED; - }, - - _getDevCertHashForApp: function getDevCertHashForApp(manifestURL) { - throw Components.results.NS_ERROR_NOT_IMPLEMENTED; - }, - - classID: Components.ID("{882a7463-2ca7-4d61-a89a-10eb6fd70478}"), - contractID: "@mozilla.org/secureelement/access-control/ace;1", - QueryInterface: XPCOMUtils.generateQI([Ci.nsIAccessControlEnforcer]) -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ACEService]); - diff --git a/dom/secureelement/gonk/ACEService.manifest b/dom/secureelement/gonk/ACEService.manifest deleted file mode 100644 index 40949c83d..000000000 --- a/dom/secureelement/gonk/ACEService.manifest +++ /dev/null @@ -1,2 +0,0 @@ -component {882a7463-2ca7-4d61-a89a-10eb6fd70478} ACEService.js -contract @mozilla.org/secureelement/access-control/ace;1 {882a7463-2ca7-4d61-a89a-10eb6fd70478}
\ No newline at end of file diff --git a/dom/secureelement/gonk/GPAccessRulesManager.js b/dom/secureelement/gonk/GPAccessRulesManager.js deleted file mode 100644 index dce11ec09..000000000 --- a/dom/secureelement/gonk/GPAccessRulesManager.js +++ /dev/null @@ -1,436 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Copyright © 2015, Deutsche Telekom, Inc. */ - -"use strict"; - -const Ci = Components.interfaces; -const Cu = Components.utils; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); - -XPCOMUtils.defineLazyServiceGetter(this, "UiccConnector", - "@mozilla.org/secureelement/connector/uicc;1", - "nsISecureElementConnector"); - -XPCOMUtils.defineLazyModuleGetter(this, "SEUtils", - "resource://gre/modules/SEUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "SE", function() { - let obj = {}; - Cu.import("resource://gre/modules/se_consts.js", obj); - return obj; -}); - -XPCOMUtils.defineLazyGetter(this, "GP", function() { - let obj = {}; - Cu.import("resource://gre/modules/gp_consts.js", obj); - return obj; -}); - -var DEBUG = SE.DEBUG_ACE; -function debug(msg) { - if (DEBUG) { - dump("-*- GPAccessRulesManager " + msg); - } -} - -/** - * Based on [1] - "GlobalPlatform Device Technology - * Secure Element Access Control Version 1.0". - * GPAccessRulesManager reads and parses access rules from SE file system - * as defined in section #7 of [1]: "Structure of Access Rule Files (ARF)". - * Rules retrieval from ARA-M applet is not implmented due to lack of - * commercial implemenations of ARA-M. - * @todo Bug 1137537: Implement ARA-M support according to section #4 of [1] - */ -function GPAccessRulesManager() {} - -GPAccessRulesManager.prototype = { - // source [1] section 7.1.3 PKCS#15 Selection - PKCS_AID: "a000000063504b43532d3135", - - // APDUs (ISO 7816-4) for accessing rules on SE file system - // see for more details: http://www.cardwerk.com/smartcards/ - // smartcard_standard_ISO7816-4_6_basic_interindustry_commands.aspx - READ_BINARY: [GP.CLA_SM, GP.INS_RB, GP.P1_RB, GP.P2_RB], - GET_RESPONSE: [GP.CLA_SM, GP.INS_GR, GP.P1_GR, GP.P2_GR], - SELECT_BY_DF: [GP.CLA_SM, GP.INS_SF, GP.P1_SF_DF, GP.P2_SF_FCP], - - // Non-null if there is a channel open - channel: null, - - // Refresh tag path in the acMain file as described in GPD spec, - // sections 7.1.5 and C.1. - REFRESH_TAG_PATH: [GP.TAG_SEQUENCE, GP.TAG_OCTETSTRING], - refreshTag: null, - - // Contains rules as read from the SE - rules: [], - - // Returns the latest rules. Results are cached. - getAccessRules: function getAccessRules() { - debug("getAccessRules"); - - return new Promise((resolve, reject) => { - this._readAccessRules(() => resolve(this.rules)); - }); - }, - - _readAccessRules: Task.async(function*(done) { - try { - yield this._openChannel(this.PKCS_AID); - - let odf = yield this._readODF(); - let dodf = yield this._readDODF(odf); - - let acmf = yield this._readACMF(dodf); - let refreshTag = acmf[this.REFRESH_TAG_PATH[0]] - [this.REFRESH_TAG_PATH[1]]; - - // Update cached rules based on refreshTag. - if (SEUtils.arraysEqual(this.refreshTag, refreshTag)) { - debug("_readAccessRules: refresh tag equals to the one saved."); - yield this._closeChannel(); - return done(); - } - - this.refreshTag = refreshTag; - debug("_readAccessRules: refresh tag saved: " + this.refreshTag); - - let acrf = yield this._readACRules(acmf); - let accf = yield this._readACConditions(acrf); - this.rules = yield this._parseRules(acrf, accf); - - DEBUG && debug("_readAccessRules: " + JSON.stringify(this.rules, 0, 2)); - - yield this._closeChannel(); - done(); - } catch (error) { - debug("_readAccessRules: " + error); - this.rules = []; - yield this._closeChannel(); - done(); - } - }), - - _openChannel: function _openChannel(aid) { - if (this.channel !== null) { - debug("_openChannel: Channel already opened, rejecting."); - return Promise.reject(); - } - - return new Promise((resolve, reject) => { - UiccConnector.openChannel(aid, { - notifyOpenChannelSuccess: (channel, openResponse) => { - debug("_openChannel/notifyOpenChannelSuccess: Channel " + channel + - " opened, open response: " + openResponse); - this.channel = channel; - resolve(); - }, - notifyError: (error) => { - debug("_openChannel/notifyError: failed to open channel, error: " + - error); - reject(error); - } - }); - }); - }, - - _closeChannel: function _closeChannel() { - if (this.channel === null) { - debug("_closeChannel: Channel not opened, rejecting."); - return Promise.reject(); - } - - return new Promise((resolve, reject) => { - UiccConnector.closeChannel(this.channel, { - notifyCloseChannelSuccess: () => { - debug("_closeChannel/notifyCloseChannelSuccess: chanel " + - this.channel + " closed"); - this.channel = null; - resolve(); - }, - notifyError: (error) => { - debug("_closeChannel/notifyError: error closing channel, error" + - error); - reject(error); - } - }); - }); - }, - - _exchangeAPDU: function _exchangeAPDU(bytes) { - DEBUG && debug("apdu " + JSON.stringify(bytes)); - - let apdu = this._bytesToAPDU(bytes); - return new Promise((resolve, reject) => { - UiccConnector.exchangeAPDU(this.channel, apdu.cla, - apdu.ins, apdu.p1, apdu.p2, apdu.data, apdu.le, - { - notifyExchangeAPDUResponse: (sw1, sw2, data) => { - debug("APDU response is " + sw1.toString(16) + sw2.toString(16) + - " data: " + data); - - // 90 00 is "success" - if (sw1 !== 0x90 && sw2 !== 0x00) { - debug("rejecting APDU response"); - reject(new Error("Response " + sw1 + "," + sw2)); - return; - } - - resolve(this._parseTLV(data)); - }, - - notifyError: (error) => { - debug("_exchangeAPDU/notifyError " + error); - reject(error); - } - } - ); - }); - }, - - _readBinaryFile: function _readBinaryFile(selectResponse) { - DEBUG && debug("Select response: " + JSON.stringify(selectResponse)); - // 0x80 tag parameter - get the elementary file (EF) length - // without structural information. - let fileLength = selectResponse[GP.TAG_FCP][0x80]; - - // If file is empty, no need to attempt to read it. - if (fileLength[0] === 0 && fileLength[1] === 0) { - return Promise.resolve(null); - } - - // TODO READ BINARY with filelength not supported - // let readApdu = this.READ_BINARY.concat(fileLength); - return this._exchangeAPDU(this.READ_BINARY); - }, - - _selectAndRead: function _selectAndRead(df) { - return this._exchangeAPDU(this.SELECT_BY_DF.concat(df.length & 0xFF, df)) - .then((resp) => this._readBinaryFile(resp)); - }, - - _readODF: function _readODF() { - debug("_readODF"); - return this._selectAndRead(GP.ODF_DF); - }, - - _readDODF: function _readDODF(odfFile) { - debug("_readDODF, ODF file: " + odfFile); - - // Data Object Directory File (DODF) is used as an entry point to the - // Access Control data. It is specified in PKCS#15 section 6.7.6. - // DODF is referenced by the ODF file, which looks as follows: - // A7 06 - // 30 04 - // 04 02 XY WZ - // where [0xXY, 0xWZ] is a DF of DODF file. - let DODF_DF = odfFile[GP.TAG_EF_ODF][GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING]; - return this._selectAndRead(DODF_DF); - }, - - _readACMF: function _readACMF(dodfFile) { - debug("_readACMF, DODF file: " + dodfFile); - - // ACMF file DF is referenced in DODF file, which looks like this: - // - // A1 29 - // 30 00 - // 30 0F - // 0C 0D 47 50 20 53 45 20 41 63 63 20 43 74 6C - // A1 14 - // 30 12 - // 06 0A 2A 86 48 86 FC 6B 81 48 01 01 <-- GPD registered OID - // 30 04 - // 04 02 AB CD <-- ACMF DF - // A1 2B - // 30 00 - // 30 0F - // 0C 0D 53 41 54 53 41 20 47 54 4F 20 31 2E 31 - // A1 16 - // 30 14 - // 06 0C 2B 06 01 04 01 2A 02 6E 03 01 01 01 <-- some other OID - // 30 04 - // 04 02 XY WZ <-- some other file's DF - // - // DODF file consists of DataTypes with oidDO entries. Entry with OID - // equal to "1.2.840.114283.200.1.1" ("2A 86 48 86 FC 6B 81 48 01 01") - // contains DF of the ACMF. In the file above, it means that ACMF DF - // equals to [0xAB, 0xCD], and not [0xXY, 0xWZ]. - // - // Algorithm used to encode OID to an byte array: - // http://www.snmpsharpnet.com/?p=153 - - let gpdOid = [0x2A, // 1.2 - 0x86, 0x48, // 840 - 0x86, 0xFC, 0x6B, // 114283 - 0x81, 0x48, // 129 - 0x01, // 1 - 0x01]; // 1 - - let records = SEUtils.ensureIsArray(dodfFile[GP.TAG_EXTERNALDO]); - - // Look for the OID registered for GPD SE. - let gpdRecords = records.filter((record) => { - let oid = record[GP.TAG_EXTERNALDO][GP.TAG_SEQUENCE][GP.TAG_OID]; - return SEUtils.arraysEqual(oid, gpdOid); - }); - - // [1] 7.1.5: "There shall be only one ACMF file per Secure Element. - // If a Secure Element contains several ACMF files, then the security shall - // be considered compromised and the Access Control enforcer shall forbid - // access to all (...) apps." - if (gpdRecords.length !== 1) { - return Promise.reject(new Error(gpdRecords.length + " ACMF files found")); - } - - let ACMain_DF = gpdRecords[0][GP.TAG_EXTERNALDO][GP.TAG_SEQUENCE] - [GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING]; - return this._selectAndRead(ACMain_DF); - }, - - _readACRules: function _readACRules(acMainFile) { - debug("_readACRules, ACMain file: " + acMainFile); - - // ACMF looks like this: - // - // 30 10 - // 04 08 XX XX XX XX XX XX XX XX - // 30 04 - // 04 02 XY WZ - // - // where [XY, WZ] is a DF of ACRF, and XX XX XX XX XX XX XX XX is a refresh - // tag. - - let ACRules_DF = acMainFile[GP.TAG_SEQUENCE][GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING]; - return this._selectAndRead(ACRules_DF); - }, - - _readACConditions: function _readACConditions(acRulesFile) { - debug("_readACCondition, ACRules file: " + acRulesFile); - - let acRules = SEUtils.ensureIsArray(acRulesFile[GP.TAG_SEQUENCE]); - if (acRules.length === 0) { - debug("No rules found in ACRules file."); - return Promise.reject(new Error("No rules found in ACRules file")); - } - - // We first read all the condition files referenced in the ACRules file, - // because ACRules file might reference one ACCondition file more than - // once. Since reading it isn't exactly fast, we optimize here. - let acReadQueue = Promise.resolve({}); - - acRules.forEach((ruleEntry) => { - let df = ruleEntry[GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING]; - - // Promise chain read condition entries: - let readAcCondition = (acConditionFiles) => { - if (acConditionFiles[df] !== undefined) { - debug("Skipping previously read acCondition df: " + df); - return acConditionFiles; - } - - return this._selectAndRead(df) - .then((acConditionFileContents) => { - acConditionFiles[df] = acConditionFileContents; - return acConditionFiles; - }); - } - - acReadQueue = acReadQueue.then(readAcCondition); - }); - - return acReadQueue; - }, - - _parseRules: function _parseRules(acRulesFile, acConditionFiles) { - DEBUG && debug("_parseRules: acConditionFiles " + JSON.stringify(acConditionFiles)); - let rules = []; - - let acRules = SEUtils.ensureIsArray(acRulesFile[GP.TAG_SEQUENCE]); - acRules.forEach((ruleEntry) => { - DEBUG && debug("Parsing one rule: " + JSON.stringify(ruleEntry)); - let rule = {}; - - // 0xA0 and 0x82 tags as per GPD spec sections C.1 - C.3. 0xA0 means - // that rule describes access to one SE applet only (and its AID is - // given). 0x82 means that rule describes acccess to all SE applets. - let oneApplet = ruleEntry[GP.TAG_GPD_AID]; - let allApplets = ruleEntry[GP.TAG_GPD_ALL]; - - if (oneApplet) { - rule.applet = oneApplet[GP.TAG_OCTETSTRING]; - } else if (allApplets) { - rule.applet = Ci.nsIAccessRulesManager.ALL_APPLET; - } else { - throw Error("Unknown applet definition"); - } - - let df = ruleEntry[GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING]; - let condition = acConditionFiles[df]; - if (condition === null) { - rule.application = Ci.nsIAccessRulesManager.DENY_ALL; - } else if (condition[GP.TAG_SEQUENCE]) { - if (!Array.isArray(condition[GP.TAG_SEQUENCE]) && - !condition[GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING]) { - rule.application = Ci.nsIAccessRulesManager.ALLOW_ALL; - } else { - rule.application = SEUtils.ensureIsArray(condition[GP.TAG_SEQUENCE]) - .map((conditionEntry) => { - return conditionEntry[GP.TAG_OCTETSTRING]; - }); - } - } else { - throw Error("Unknown application definition"); - } - - DEBUG && debug("Rule parsed, adding to the list: " + JSON.stringify(rule)); - rules.push(rule); - }); - - DEBUG && debug("All rules parsed, we have those in total: " + JSON.stringify(rules)); - return rules; - }, - - _parseTLV: function _parseTLV(bytes) { - let containerTags = [ - GP.TAG_SEQUENCE, - GP.TAG_FCP, - GP.TAG_GPD_AID, - GP.TAG_EXTERNALDO, - GP.TAG_INDIRECT, - GP.TAG_EF_ODF - ]; - return SEUtils.parseTLV(bytes, containerTags); - }, - - // TODO consider removing if better format for storing - // APDU consts will be introduced - _bytesToAPDU: function _bytesToAPDU(arr) { - let apdu = { - cla: arr[0] & 0xFF, - ins: arr[1] & 0xFF, - p1: arr[2] & 0xFF, - p2: arr[3] & 0xFF, - p3: arr[4] & 0xFF, - le: 0 - }; - - let data = (apdu.p3 > 0) ? (arr.slice(5)) : []; - apdu.data = (data.length) ? SEUtils.byteArrayToHexString(data) : null; - return apdu; - }, - - classID: Components.ID("{3e046b4b-9e66-439a-97e0-98a69f39f55f}"), - contractID: "@mozilla.org/secureelement/access-control/rules-manager;1", - QueryInterface: XPCOMUtils.generateQI([Ci.nsIAccessRulesManager]) -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([GPAccessRulesManager]); diff --git a/dom/secureelement/gonk/GPAccessRulesManager.manifest b/dom/secureelement/gonk/GPAccessRulesManager.manifest deleted file mode 100644 index 2d7ea038b..000000000 --- a/dom/secureelement/gonk/GPAccessRulesManager.manifest +++ /dev/null @@ -1,2 +0,0 @@ -component {3e046b4b-9e66-439a-97e0-98a69f39f55f} GPAccessRulesManager.js -contract @mozilla.org/secureelement/access-control/rules-manager;1 {3e046b4b-9e66-439a-97e0-98a69f39f55f} diff --git a/dom/secureelement/gonk/SecureElement.js b/dom/secureelement/gonk/SecureElement.js deleted file mode 100644 index 144c6d8d6..000000000 --- a/dom/secureelement/gonk/SecureElement.js +++ /dev/null @@ -1,514 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Copyright © 2014, Deutsche Telekom, Inc. */ - -"use strict"; - -/* globals dump, Components, XPCOMUtils, SE, Services, UiccConnector, - SEUtils, ppmm, gMap, UUIDGenerator */ - -const { classes: Cc, interfaces: Ci, utils: Cu } = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); - -XPCOMUtils.defineLazyGetter(this, "SE", () => { - let obj = {}; - Cu.import("resource://gre/modules/se_consts.js", obj); - return obj; -}); - -// set to true in se_consts.js to see debug messages -var DEBUG = SE.DEBUG_SE; -function debug(s) { - if (DEBUG) { - dump("-*- SecureElement: " + s + "\n"); - } -} - -const SE_IPC_SECUREELEMENT_MSG_NAMES = [ - "SE:GetSEReaders", - "SE:OpenChannel", - "SE:CloseChannel", - "SE:TransmitAPDU" -]; - -const SECUREELEMENTMANAGER_CONTRACTID = - "@mozilla.org/secureelement/parent-manager;1"; -const SECUREELEMENTMANAGER_CID = - Components.ID("{48f4e650-28d2-11e4-8c21-0800200c9a66}"); -const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown"; - -XPCOMUtils.defineLazyServiceGetter(this, "ppmm", - "@mozilla.org/parentprocessmessagemanager;1", - "nsIMessageBroadcaster"); - -XPCOMUtils.defineLazyServiceGetter(this, "UUIDGenerator", - "@mozilla.org/uuid-generator;1", - "nsIUUIDGenerator"); - -XPCOMUtils.defineLazyModuleGetter(this, "SEUtils", - "resource://gre/modules/SEUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "UiccConnector", () => { - let uiccClass = Cc["@mozilla.org/secureelement/connector/uicc;1"]; - return uiccClass ? uiccClass.getService(Ci.nsISecureElementConnector) : null; -}); - -function getConnector(type) { - switch (type) { - case SE.TYPE_UICC: - return UiccConnector; - case SE.TYPE_ESE: - default: - debug("Unsupported SEConnector : " + type); - return null; - } -} - -/** - * 'gMap' is a nested dictionary object that manages all the information - * pertaining to channels for a given application (appId). It manages the - * relationship between given application and its opened channels. - */ -XPCOMUtils.defineLazyGetter(this, "gMap", function() { - return { - // example structure of AppInfoMap - // { - // "appId1": { - // target: target1, - // channels: { - // "channelToken1": { - // seType: "uicc", - // aid: "aid1", - // channelNumber: 1 - // }, - // "channelToken2": { ... } - // } - // }, - // "appId2": { ... } - // } - appInfoMap: {}, - - registerSecureElementTarget: function(appId, target) { - if (this.isAppIdRegistered(appId)) { - debug("AppId: " + appId + "already registered"); - return; - } - - this.appInfoMap[appId] = { - target: target, - channels: {} - }; - - debug("Registered a new SE target " + appId); - }, - - unregisterSecureElementTarget: function(target) { - let appId = Object.keys(this.appInfoMap).find((id) => { - return this.appInfoMap[id].target === target; - }); - - if (!appId) { - return; - } - - debug("Unregistered SE Target for AppId: " + appId); - delete this.appInfoMap[appId]; - }, - - isAppIdRegistered: function(appId) { - return this.appInfoMap[appId] !== undefined; - }, - - getChannelCountByAppIdType: function(appId, type) { - return Object.keys(this.appInfoMap[appId].channels) - .reduce((cnt, ch) => ch.type === type ? ++cnt : cnt, 0); - }, - - // Add channel to the appId. Upon successfully adding the entry - // this function will return the 'token' - addChannel: function(appId, type, aid, channelNumber) { - let token = UUIDGenerator.generateUUID().toString(); - this.appInfoMap[appId].channels[token] = { - seType: type, - aid: aid, - channelNumber: channelNumber - }; - return token; - }, - - removeChannel: function(appId, channelToken) { - if (this.appInfoMap[appId].channels[channelToken]) { - debug("Deleting channel with token : " + channelToken); - delete this.appInfoMap[appId].channels[channelToken]; - } - }, - - getChannel: function(appId, channelToken) { - if (!this.appInfoMap[appId].channels[channelToken]) { - return null; - } - - return this.appInfoMap[appId].channels[channelToken]; - }, - - getChannelsByTarget: function(target) { - let appId = Object.keys(this.appInfoMap).find((id) => { - return this.appInfoMap[id].target === target; - }); - - if (!appId) { - return []; - } - - return Object.keys(this.appInfoMap[appId].channels) - .map(token => this.appInfoMap[appId].channels[token]); - }, - - getTargets: function() { - return Object.keys(this.appInfoMap) - .map(appId => this.appInfoMap[appId].target); - }, - }; -}); - -/** - * 'SecureElementManager' is the main object that handles IPC messages from - * child process. It interacts with other objects such as 'gMap' & 'Connector - * instances (UiccConnector, eSEConnector)' to perform various - * SE-related (open, close, transmit) operations. - * @TODO: Bug 1118097 Support slot based SE/reader names - * @TODO: Bug 1118101 Introduce SE type specific permissions - */ -function SecureElementManager() { - this._registerMessageListeners(); - this._registerSEListeners(); - Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); - this._acEnforcer = - Cc["@mozilla.org/secureelement/access-control/ace;1"] - .getService(Ci.nsIAccessControlEnforcer); -} - -SecureElementManager.prototype = { - QueryInterface: XPCOMUtils.generateQI([ - Ci.nsIMessageListener, - Ci.nsISEListener, - Ci.nsIObserver]), - classID: SECUREELEMENTMANAGER_CID, - classInfo: XPCOMUtils.generateCI({ - classID: SECUREELEMENTMANAGER_CID, - classDescription: "SecureElementManager", - interfaces: [Ci.nsIMessageListener, - Ci.nsISEListener, - Ci.nsIObserver] - }), - - // Stores information about supported SE types and their presence. - // key: secure element type, value: (Boolean) is present/accessible - _sePresence: {}, - - _acEnforcer: null, - - _shutdown: function() { - this._acEnforcer = null; - this.secureelement = null; - Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); - this._unregisterMessageListeners(); - this._unregisterSEListeners(); - }, - - _registerMessageListeners: function() { - ppmm.addMessageListener("child-process-shutdown", this); - for (let msgname of SE_IPC_SECUREELEMENT_MSG_NAMES) { - ppmm.addMessageListener(msgname, this); - } - }, - - _unregisterMessageListeners: function() { - ppmm.removeMessageListener("child-process-shutdown", this); - for (let msgname of SE_IPC_SECUREELEMENT_MSG_NAMES) { - ppmm.removeMessageListener(msgname, this); - } - ppmm = null; - }, - - _registerSEListeners: function() { - let connector = getConnector(SE.TYPE_UICC); - if (!connector) { - return; - } - - this._sePresence[SE.TYPE_UICC] = false; - connector.registerListener(this); - }, - - _unregisterSEListeners: function() { - Object.keys(this._sePresence).forEach((type) => { - let connector = getConnector(type); - if (connector) { - connector.unregisterListener(this); - } - }); - - this._sePresence = {}; - }, - - notifySEPresenceChanged: function(type, isPresent) { - // we need to notify all targets, even those without open channels, - // app could've stored the reader without actually using it - debug("notifying DOM about SE state change"); - this._sePresence[type] = isPresent; - gMap.getTargets().forEach(target => { - let result = { type: type, isPresent: isPresent }; - target.sendAsyncMessage("SE:ReaderPresenceChanged", { result: result }); - }); - }, - - _canOpenChannel: function(appId, type) { - let opened = gMap.getChannelCountByAppIdType(appId, type); - let limit = SE.MAX_CHANNELS_ALLOWED_PER_SESSION; - // UICC basic channel is not accessible see comment in se_consts.js - limit = type === SE.TYPE_UICC ? limit - 1 : limit; - return opened < limit; - }, - - _handleOpenChannel: function(msg, callback) { - if (!this._canOpenChannel(msg.appId, msg.type)) { - debug("Max channels per session exceed"); - callback({ error: SE.ERROR_GENERIC }); - return; - } - - let connector = getConnector(msg.type); - if (!connector) { - debug("No SE connector available"); - callback({ error: SE.ERROR_NOTPRESENT }); - return; - } - - this._acEnforcer.isAccessAllowed(msg.appId, msg.type, msg.aid) - .then((allowed) => { - if (!allowed) { - callback({ error: SE.ERROR_SECURITY }); - return; - } - connector.openChannel(SEUtils.byteArrayToHexString(msg.aid), { - - notifyOpenChannelSuccess: (channelNumber, openResponse) => { - // Add the new 'channel' to the map upon success - let channelToken = - gMap.addChannel(msg.appId, msg.type, msg.aid, channelNumber); - if (channelToken) { - callback({ - error: SE.ERROR_NONE, - channelToken: channelToken, - isBasicChannel: (channelNumber === SE.BASIC_CHANNEL), - openResponse: SEUtils.hexStringToByteArray(openResponse) - }); - } else { - callback({ error: SE.ERROR_GENERIC }); - } - }, - - notifyError: (reason) => { - debug("Failed to open the channel to AID : " + - SEUtils.byteArrayToHexString(msg.aid) + - ", Rejected with Reason : " + reason); - callback({ error: SE.ERROR_GENERIC, reason: reason, response: [] }); - } - }); - }) - .catch((error) => { - debug("Failed to get info from accessControlEnforcer " + error); - callback({ error: SE.ERROR_SECURITY }); - }); - }, - - _handleTransmit: function(msg, callback) { - let channel = gMap.getChannel(msg.appId, msg.channelToken); - if (!channel) { - debug("Invalid token:" + msg.channelToken + ", appId: " + msg.appId); - callback({ error: SE.ERROR_GENERIC }); - return; - } - - let connector = getConnector(channel.seType); - if (!connector) { - debug("No SE connector available"); - callback({ error: SE.ERROR_NOTPRESENT }); - return; - } - - // Bug 1137533 - ACE GPAccessRulesManager APDU filters - connector.exchangeAPDU(channel.channelNumber, msg.apdu.cla, msg.apdu.ins, - msg.apdu.p1, msg.apdu.p2, - SEUtils.byteArrayToHexString(msg.apdu.data), - msg.apdu.le, { - notifyExchangeAPDUResponse: (sw1, sw2, response) => { - callback({ - error: SE.ERROR_NONE, - sw1: sw1, - sw2: sw2, - response: SEUtils.hexStringToByteArray(response) - }); - }, - - notifyError: (reason) => { - debug("Transmit failed, rejected with Reason : " + reason); - callback({ error: SE.ERROR_INVALIDAPPLICATION, reason: reason }); - } - }); - }, - - _handleCloseChannel: function(msg, callback) { - let channel = gMap.getChannel(msg.appId, msg.channelToken); - if (!channel) { - debug("Invalid token:" + msg.channelToken + ", appId:" + msg.appId); - callback({ error: SE.ERROR_GENERIC }); - return; - } - - let connector = getConnector(channel.seType); - if (!connector) { - debug("No SE connector available"); - callback({ error: SE.ERROR_NOTPRESENT }); - return; - } - - connector.closeChannel(channel.channelNumber, { - notifyCloseChannelSuccess: () => { - gMap.removeChannel(msg.appId, msg.channelToken); - callback({ error: SE.ERROR_NONE }); - }, - - notifyError: (reason) => { - debug("Failed to close channel with token: " + msg.channelToken + - ", reason: "+ reason); - callback({ error: SE.ERROR_BADSTATE, reason: reason }); - } - }); - }, - - _handleGetSEReadersRequest: function(msg, target, callback) { - gMap.registerSecureElementTarget(msg.appId, target); - let readers = Object.keys(this._sePresence).map(type => { - return { type: type, isPresent: this._sePresence[type] }; - }); - callback({ readers: readers, error: SE.ERROR_NONE }); - }, - - _handleChildProcessShutdown: function(target) { - let channels = gMap.getChannelsByTarget(target); - - let createCb = (seType, channelNumber) => { - return { - notifyCloseChannelSuccess: () => { - debug("closed " + seType + ", channel " + channelNumber); - }, - - notifyError: (reason) => { - debug("Failed to close " + seType + " channel " + - channelNumber + ", reason: " + reason); - } - }; - }; - - channels.forEach((channel) => { - let connector = getConnector(channel.seType); - if (!connector) { - return; - } - - connector.closeChannel(channel.channelNumber, - createCb(channel.seType, channel.channelNumber)); - }); - - gMap.unregisterSecureElementTarget(target); - }, - - _sendSEResponse: function(msg, result) { - let promiseStatus = (result.error === SE.ERROR_NONE) ? "Resolved" : "Rejected"; - result.resolverId = msg.data.resolverId; - msg.target.sendAsyncMessage(msg.name + promiseStatus, {result: result}); - }, - - _isValidMessage: function(msg) { - let appIdValid = gMap.isAppIdRegistered(msg.data.appId); - return msg.name === "SE:GetSEReaders" ? true : appIdValid; - }, - - /** - * nsIMessageListener interface methods. - */ - - receiveMessage: function(msg) { - DEBUG && debug("Received '" + msg.name + "' message from content process" + - ": " + JSON.stringify(msg.data)); - - if (msg.name === "child-process-shutdown") { - this._handleChildProcessShutdown(msg.target); - return null; - } - - if (SE_IPC_SECUREELEMENT_MSG_NAMES.indexOf(msg.name) !== -1) { - if (!msg.target.assertPermission("secureelement-manage")) { - debug("SecureElement message " + msg.name + " from a content process " + - "with no 'secureelement-manage' privileges."); - return null; - } - } else { - debug("Ignoring unknown message type: " + msg.name); - return null; - } - - let callback = (result) => this._sendSEResponse(msg, result); - if (!this._isValidMessage(msg)) { - debug("Message not valid"); - callback({ error: SE.ERROR_GENERIC }); - return null; - } - - switch (msg.name) { - case "SE:GetSEReaders": - this._handleGetSEReadersRequest(msg.data, msg.target, callback); - break; - case "SE:OpenChannel": - this._handleOpenChannel(msg.data, callback); - break; - case "SE:CloseChannel": - this._handleCloseChannel(msg.data, callback); - break; - case "SE:TransmitAPDU": - this._handleTransmit(msg.data, callback); - break; - } - return null; - }, - - /** - * nsIObserver interface methods. - */ - - observe: function(subject, topic, data) { - if (topic === NS_XPCOM_SHUTDOWN_OBSERVER_ID) { - this._shutdown(); - } - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SecureElementManager]); diff --git a/dom/secureelement/gonk/SecureElement.manifest b/dom/secureelement/gonk/SecureElement.manifest deleted file mode 100644 index a76fcfc11..000000000 --- a/dom/secureelement/gonk/SecureElement.manifest +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2012 Mozilla Foundation and Mozilla contributors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# SecureElementManager -component {48f4e650-28d2-11e4-8c21-0800200c9a66} SecureElement.js -contract @mozilla.org/secureelement/parent-manager;1 {48f4e650-28d2-11e4-8c21-0800200c9a66} -category profile-after-change SecureElementManager @mozilla.org/secureelement/parent-manager;1 diff --git a/dom/secureelement/gonk/UiccConnector.js b/dom/secureelement/gonk/UiccConnector.js deleted file mode 100644 index 517303de2..000000000 --- a/dom/secureelement/gonk/UiccConnector.js +++ /dev/null @@ -1,360 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Copyright © 2014, Deutsche Telekom, Inc. */ - -"use strict"; - -/* globals Components, XPCOMUtils, SE, dump, libcutils, Services, - iccService, SEUtils */ - -const { interfaces: Ci, utils: Cu, results: Cr } = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); - -XPCOMUtils.defineLazyGetter(this, "SE", function() { - let obj = {}; - Cu.import("resource://gre/modules/se_consts.js", obj); - return obj; -}); - -// set to true in se_consts.js to see debug messages -var DEBUG = SE.DEBUG_CONNECTOR; -function debug(s) { - if (DEBUG) { - dump("-*- UiccConnector: " + s + "\n"); - } -} - -XPCOMUtils.defineLazyModuleGetter(this, "SEUtils", - "resource://gre/modules/SEUtils.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, "iccService", - "@mozilla.org/icc/iccservice;1", - "nsIIccService"); - -const UICCCONNECTOR_CONTRACTID = - "@mozilla.org/secureelement/connector/uicc;1"; -const UICCCONNECTOR_CID = - Components.ID("{8e040e5d-c8c3-4c1b-ac82-c00d25d8c4a4}"); -const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown"; - -// TODO: Bug 1118099 - Add multi-sim support. -// In the Multi-sim, there is more than one client. -// For now, use default clientID as 0. Ideally, SE parent process would like to -// know which clients (uicc slot) are connected to CLF over SWP interface. -const PREFERRED_UICC_CLIENTID = - libcutils.property_get("ro.moz.se.def_client_id", "0"); - -/** - * 'UiccConnector' object is a wrapper over iccService's channel management - * related interfaces that implements nsISecureElementConnector interface. - */ -function UiccConnector() { - this._init(); -} - -UiccConnector.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsISecureElementConnector, - Ci.nsIIccListener]), - classID: UICCCONNECTOR_CID, - classInfo: XPCOMUtils.generateCI({ - classID: UICCCONNECTOR_CID, - contractID: UICCCONNECTOR_CONTRACTID, - classDescription: "UiccConnector", - interfaces: [Ci.nsISecureElementConnector, - Ci.nsIIccListener, - Ci.nsIObserver] - }), - - _SEListeners: [], - _isPresent: false, - - _init: function() { - Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); - let icc = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID); - icc.registerListener(this); - - // Update the state in order to avoid race condition. - // By this time, 'notifyCardStateChanged (with proper card state)' - // may have occurred already before this module initialization. - this._updatePresenceState(); - }, - - _shutdown: function() { - Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); - let icc = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID); - icc.unregisterListener(this); - }, - - _updatePresenceState: function() { - let uiccNotReadyStates = [ - Ci.nsIIcc.CARD_STATE_UNKNOWN, - Ci.nsIIcc.CARD_STATE_ILLEGAL, - Ci.nsIIcc.CARD_STATE_PERSONALIZATION_IN_PROGRESS, - Ci.nsIIcc.CARD_STATE_PERMANENT_BLOCKED, - Ci.nsIIcc.CARD_STATE_UNDETECTED - ]; - - let cardState = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID).cardState; - let uiccPresent = cardState !== null && - uiccNotReadyStates.indexOf(cardState) == -1; - - if (this._isPresent === uiccPresent) { - return; - } - - debug("Uicc presence changed " + this._isPresent + " -> " + uiccPresent); - this._isPresent = uiccPresent; - this._SEListeners.forEach((listener) => { - listener.notifySEPresenceChanged(SE.TYPE_UICC, this._isPresent); - }); - }, - - // See GP Spec, 11.1.4 Class Byte Coding - _setChannelToCLAByte: function(cla, channel) { - if (channel < SE.LOGICAL_CHANNEL_NUMBER_LIMIT) { - // b7 = 0 indicates the first interindustry class byte coding - cla = (cla & 0x9C) & 0xFF | channel; - } else if (channel < SE.SUPPLEMENTARY_LOGICAL_CHANNEL_NUMBER_LIMIT) { - // b7 = 1 indicates the further interindustry class byte coding - cla = (cla & 0xB0) & 0xFF | 0x40 | (channel - SE.LOGICAL_CHANNEL_NUMBER_LIMIT); - } else { - debug("Channel number must be within [0..19]"); - return SE.ERROR_GENERIC; - } - return cla; - }, - - _doGetOpenResponse: function(channel, length, callback) { - // Le value is set. It means that this is a request for all available - // response bytes. - let cla = this._setChannelToCLAByte(SE.CLA_GET_RESPONSE, channel); - this.exchangeAPDU(channel, cla, SE.INS_GET_RESPONSE, 0x00, 0x00, - null, length, { - notifyExchangeAPDUResponse: function(sw1, sw2, response) { - debug("GET Response : " + response); - if (callback) { - callback({ - error: SE.ERROR_NONE, - sw1: sw1, - sw2: sw2, - response: response - }); - } - }, - - notifyError: function(reason) { - debug("Failed to get open response: " + - ", Rejected with Reason : " + reason); - if (callback) { - callback({ error: SE.ERROR_INVALIDAPPLICATION, reason: reason }); - } - } - }); - }, - - _doIccExchangeAPDU: function(channel, cla, ins, p1, p2, p3, - data, appendResp, callback) { - let icc = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID); - icc.iccExchangeAPDU(channel, cla & 0xFC, ins, p1, p2, p3, data, { - notifyExchangeAPDUResponse: (sw1, sw2, response) => { - debug("sw1 : " + sw1 + ", sw2 : " + sw2 + ", response : " + response); - - // According to ETSI TS 102 221 , Section 7.2.2.3.1, - // Enforce 'Procedure bytes' checks before notifying the callback. - // Note that 'Procedure bytes'are special cases. - // There is no need to handle '0x60' procedure byte as it implies - // no-action from SE stack perspective. This procedure byte is not - // notified to application layer. - if (sw1 === 0x6C) { - // Use the previous command header with length as second procedure - // byte (SW2) as received and repeat the procedure. - - // Recursive! and Pass empty response '' as args, since '0x6C' - // procedure does not have to deal with appended responses. - this._doIccExchangeAPDU(channel, cla, ins, p1, p2, - sw2, data, "", callback); - } else if (sw1 === 0x61) { - // Since the terminal waited for a second procedure byte and - // received it (sw2), send a GET RESPONSE command header to the UICC - // with a maximum length of 'XX', where 'XX' is the value of the - // second procedure byte (SW2). - - let claWithChannel = this._setChannelToCLAByte(SE.CLA_GET_RESPONSE, - channel); - - // Recursive, with GET RESPONSE bytes and '0x61' procedure IS interested - // in appended responses. Pass appended response and note that p3=sw2. - this._doIccExchangeAPDU(channel, claWithChannel, SE.INS_GET_RESPONSE, - 0x00, 0x00, sw2, null, - (response ? response + appendResp : appendResp), - callback); - } else if (callback) { - callback.notifyExchangeAPDUResponse(sw1, sw2, response); - } - }, - - notifyError: (reason) => { - debug("Failed to trasmit C-APDU over the channel # : " + channel + - ", Rejected with Reason : " + reason); - if (callback) { - callback.notifyError(reason); - } - } - }); - }, - - /** - * nsISecureElementConnector interface methods. - */ - - /** - * Opens a channel on a default clientId - */ - openChannel: function(aid, callback) { - if (!this._isPresent) { - callback.notifyError(SE.ERROR_NOTPRESENT); - return; - } - - // TODO: Bug 1118106: Handle Resource management / leaks by persisting - // the newly opened channel in some persistent storage so that when this - // module gets restarted (say after opening a channel) in the event of - // some erroneous conditions such as gecko restart /, crash it can read - // the persistent storage to check if there are any held resources - // (opened channels) and close them. - let icc = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID); - icc.iccOpenChannel(aid, { - notifyOpenChannelSuccess: (channel) => { - this._doGetOpenResponse(channel, 0x00, function(result) { - if (callback) { - callback.notifyOpenChannelSuccess(channel, result.response); - } - }); - }, - - notifyError: (reason) => { - debug("Failed to open the channel to AID : " + aid + - ", Rejected with Reason : " + reason); - if (callback) { - callback.notifyError(reason); - } - } - }); - }, - - /** - * Transmit the C-APDU (command) on default clientId. - */ - exchangeAPDU: function(channel, cla, ins, p1, p2, data, le, callback) { - if (!this._isPresent) { - callback.notifyError(SE.ERROR_NOTPRESENT); - return; - } - - if (data && data.length % 2 !== 0) { - callback.notifyError("Data should be a hex string with length % 2 === 0"); - return; - } - - cla = this._setChannelToCLAByte(cla, channel); - let lc = data ? data.length / 2 : 0; - let p3 = lc || le; - - if (lc && (le !== -1)) { - data += SEUtils.byteArrayToHexString([le]); - } - - // Pass empty response '' as args as we are not interested in appended - // responses yet! - debug("exchangeAPDU on Channel # " + channel); - this._doIccExchangeAPDU(channel, cla, ins, p1, p2, p3, data, "", - callback); - }, - - /** - * Closes the channel on default clientId. - */ - closeChannel: function(channel, callback) { - if (!this._isPresent) { - callback.notifyError(SE.ERROR_NOTPRESENT); - return; - } - - let icc = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID); - icc.iccCloseChannel(channel, { - notifyCloseChannelSuccess: function() { - debug("closeChannel successfully closed the channel # : " + channel); - if (callback) { - callback.notifyCloseChannelSuccess(); - } - }, - - notifyError: function(reason) { - debug("Failed to close the channel # : " + channel + - ", Rejected with Reason : " + reason); - if (callback) { - callback.notifyError(reason); - } - } - }); - }, - - registerListener: function(listener) { - if (this._SEListeners.indexOf(listener) !== -1) { - throw Cr.NS_ERROR_UNEXPECTED; - } - - this._SEListeners.push(listener); - // immediately notify listener about the current state - listener.notifySEPresenceChanged(SE.TYPE_UICC, this._isPresent); - }, - - unregisterListener: function(listener) { - let idx = this._SEListeners.indexOf(listener); - if (idx !== -1) { - this._SEListeners.splice(idx, 1); - } - }, - - /** - * nsIIccListener interface methods. - */ - notifyStkCommand: function() {}, - - notifyStkSessionEnd: function() {}, - - notifyIccInfoChanged: function() {}, - - notifyCardStateChanged: function() { - debug("Card state changed, updating UICC presence."); - this._updatePresenceState(); - }, - - /** - * nsIObserver interface methods. - */ - - observe: function(subject, topic, data) { - if (topic === NS_XPCOM_SHUTDOWN_OBSERVER_ID) { - this._shutdown(); - } - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([UiccConnector]); diff --git a/dom/secureelement/gonk/UiccConnector.manifest b/dom/secureelement/gonk/UiccConnector.manifest deleted file mode 100644 index 5ac8b3b7b..000000000 --- a/dom/secureelement/gonk/UiccConnector.manifest +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2012 Mozilla Foundation and Mozilla contributors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# UiccConnector -component {8e040e5d-c8c3-4c1b-ac82-c00d25d8c4a4} UiccConnector.js -contract @mozilla.org/secureelement/connector/uicc;1 {8e040e5d-c8c3-4c1b-ac82-c00d25d8c4a4} diff --git a/dom/secureelement/gonk/gp_consts.js b/dom/secureelement/gonk/gp_consts.js deleted file mode 100644 index 7c3bc7165..000000000 --- a/dom/secureelement/gonk/gp_consts.js +++ /dev/null @@ -1,62 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Copyright © 2015, Deutsche Telekom, Inc. */ - -/* Object Directory File (ODF) is an elementary file which contain - pointers to other EFs. It is specified in PKCS#15 section 6.7. */ -this.ODF_DF = [0x50, 0x31]; - -/* ISO 7816-4: secure messaging */ -this.CLA_SM = 0x00; - -/* ISO 7816-4, 5.4.1 table 11 */ -this.INS_SF = 0xA4; // select file -this.INS_GR = 0xC0; // get response -this.INS_RB = 0xB0; // read binary - -/* ISO 7816-4: select file, see 6.11.3, table 58 & 59 */ -this.P1_SF_DF = 0x00; // select DF -this.P2_SF_FCP = 0x04; // return FCP - -/* ISO 7816-4: read binary, 6.1.3. P1 and P2 describe offset of the first byte - to be read. We always read the whole files at the moment. */ -this.P1_RB = 0x00; -this.P2_RB = 0x00; - -/* ISO 7816-4: get response, 7.1.3 table 74, P1-P2 '0000' (other values RFU) */ -this.P1_GR = 0x00; -this.P2_GR = 0x00; - -/* ISO 7816-4: 5.1.5 File Control Information, Table 1. For FCP and FMD. */ -this.TAG_PROPRIETARY = 0x00; -this.TAG_NON_TLV = 0x53; -this.TAG_BER_TLV = 0x73; - -/* ASN.1 tags */ -this.TAG_SEQUENCE = 0x30; -this.TAG_OCTETSTRING = 0x04; -this.TAG_OID = 0x06; // Object Identifier - -/* ISO 7816-4: 5.1.5 File Control Information, Templates. */ -this.TAG_FCP = 0x62; // File control parameters template -this.TAG_FMD = 0x64; // File management data template -this.TAG_FCI = 0x6F; // File control information template - -/* EF_DIR tags */ -this.TAG_APPLTEMPLATE = 0x61; -this.TAG_APPLIDENTIFIER = 0x4F; -this.TAG_APPLLABEL = 0x50; -this.TAG_APPLPATH = 0x51; - -this.TAG_GPD_ALL = 0x82; // EF-ACRules - GPD spec. "all applets" - -/* Generic TLVs that are parsed */ -this.TAG_GPD_AID = 0xA0; // AID in the EF-ACRules - GPD spec, "one applet" -this.TAG_EXTERNALDO = 0xA1; // External data objects - PKCS#15 -this.TAG_INDIRECT = 0xA5; // Indirect value. -this.TAG_EF_ODF = 0xA7; // Elemenetary File Object Directory File - -// Allow this file to be imported via Components.utils.import(). -this.EXPORTED_SYMBOLS = Object.keys(this); diff --git a/dom/secureelement/gonk/nsIAccessControlEnforcer.idl b/dom/secureelement/gonk/nsIAccessControlEnforcer.idl deleted file mode 100644 index 7ad1a97f6..000000000 --- a/dom/secureelement/gonk/nsIAccessControlEnforcer.idl +++ /dev/null @@ -1,32 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Copyright © 2015, Deutsche Telekom, Inc. */ - -#include "nsISupports.idl" - -interface nsIVariant; - -[scriptable, uuid(4994a960-26d9-4d71-82dd-4505bd97bf2a)] -interface nsIAccessControlEnforcer : nsISupports -{ - /** - * Determines whether application identified by its ID should be allowed - * to access Secure Element's applet identified by its AID. Decision - * is made according to the GPD specification. - * - * @param localId - * ID of an application accessing SE - * @param seType - * Type of the SE. - * @param aid - * AID of a SE applet - * @return Promise which is resolved to true if access should be allowed, - * false otherwise, and rejected if the application contains - * no developer certificate. - */ - jsval isAccessAllowed(in unsigned long localId, - in DOMString seType, - in DOMString aid); -}; diff --git a/dom/secureelement/gonk/nsIAccessRulesManager.idl b/dom/secureelement/gonk/nsIAccessRulesManager.idl deleted file mode 100644 index 173f57c90..000000000 --- a/dom/secureelement/gonk/nsIAccessRulesManager.idl +++ /dev/null @@ -1,50 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Copyright © 2015, Deutsche Telekom, Inc. */ - -#include "nsISupports.idl" - -[scriptable, uuid(7baedd2a-3189-4b03-b2a3-34016043b5e2)] -interface nsIAccessRulesManager : nsISupports -{ - /* Wildcard: rule allows all applications to access an SE applet */ - const unsigned short ALLOW_ALL = 1; - /* Wildcard: rule denies all applications to access an SE applet */ - const unsigned short DENY_ALL = 2; - /* Wildcard: rule allows application(s) access to all SE applets */ - const unsigned short ALL_APPLET = 3; - - /** - * Initiates Access Rules Manager, this should perform the initial - * reading of rules from access rule source - * @return Promise which is resolved if init is successful or rejected - * otherwise - */ - jsval init(); - - /** - * Retrieves all access rules. - * - * Rules are stored in an array. Each rule contains the following properties: - * - applet - describes an SE applet referenced by this rule. Might equal - * to an applet AID (as a byte array), or to a wildcard "all" - * meaning all applets. - * - application - describes an application referenced by this rule. Might - * be an array of developer certificate hashes (each as - * a byte array) in which case it lists all applications - * allowed access. Alternatively, might equal to wildcard - * "allowed-all" or "denied-all". - * - * Example rule format: - * [{ applet: ALL_APPLET, - * application: [[0x01, 0x02, ..., 0x20], - * [0x20, 0x19, ...., 0x01]], - * { applet: [0x00, 0x01, ..., 0x05], - * application: ALLOW_ALL}}] - * - * @return Promise which resolves with Array containing parsed access rules - */ - jsval getAccessRules(); -}; diff --git a/dom/secureelement/gonk/nsISecureElementConnector.idl b/dom/secureelement/gonk/nsISecureElementConnector.idl deleted file mode 100644 index 92cc1eb2b..000000000 --- a/dom/secureelement/gonk/nsISecureElementConnector.idl +++ /dev/null @@ -1,124 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(1ff3f35a-1b6f-4e65-a89e-a363b8604cd7)] -interface nsISEChannelCallback : nsISupports -{ - /** - * Callback function to notify on successfully opening a logical channel. - * - * @param channel - * The Channel Number/Handle that is successfully opened. - * @param openResponse - * Response from SE for OpenChannel operation. - */ - void notifyOpenChannelSuccess(in long channel, in DOMString openResponse); - - /** - * Callback function to notify on successfully closing the logical channel. - * - */ - void notifyCloseChannelSuccess(); - - /** - * Callback function to notify the status of 'seExchangeAPDU' command. - * - * @param sw1 - * Response's First Status Byte - * @param sw2 - * Response's Second Status Byte - * @param data - * Response's data - */ - void notifyExchangeAPDUResponse(in octet sw1, - in octet sw2, - in DOMString data); - - /** - * Callback function to notify error - * - * @param error - * Error describing the reason for failure. - */ - void notifyError(in DOMString error); -}; - -[scriptable, uuid(417f59ee-f582-45b9-9a4e-e9dcefecb4f7)] -interface nsISEListener : nsISupports -{ - void notifySEPresenceChanged(in DOMString seType, in boolean isPresent); -}; - -[scriptable, uuid(3cef313a-1d01-432d-9cd2-6610a80911f3)] -interface nsISecureElementConnector : nsISupports -{ - /** - * Open a logical communication channel with the specific secure element type - * - * @param aid - * Application Identifier of the Card Applet on the secure element. - * @param callback - * callback to notify the result of the operation. - */ - void openChannel(in DOMString aid, - in nsISEChannelCallback callback); - - /** - * Exchanges APDU channel with the specific secure element type - * - * @param channel - * Channel on which C-APDU to be transmitted. - * @param cla - Class Byte. - * @param ins - Instruction Byte - * @param p1 - Reference parameter first byte - * @param p2 - Reference parameter second byte - * Refer to 3G TS 31.101 , 10.2 'Command APDU Structure' for all the cases. - * @param data - Sequence of C-APDU data octets - * @param le [optional] - * le is the length of expected response. If the response is not expected, - it should be explicitly set to -1. - * @param callback - * callback to notify the result of the operation. - */ - void exchangeAPDU(in long channel, - in octet cla, - in octet ins, - in octet p1, - in octet p2, - in DOMString data, - in short le, - in nsISEChannelCallback callback); - - /** - * Closes the logical communication channel to the specific secure element type - * - * @param channel - * Channel to be closed. - * @param callback - * callback to notify the result of the operation. - */ - void closeChannel(in long channel, - in nsISEChannelCallback callback); - - /** - * Register a Secure Element listener - * - * @param listener - */ - void registerListener(in nsISEListener listener); - - /** - * Unregister a Secure Element listener - * - * @param listener - */ - void unregisterListener(in nsISEListener listener); -}; diff --git a/dom/secureelement/gonk/se_consts.js b/dom/secureelement/gonk/se_consts.js deleted file mode 100644 index 13489b7ae..000000000 --- a/dom/secureelement/gonk/se_consts.js +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Copyright © 2014, Deutsche Telekom, Inc. */ - -// Set to true to debug SecureElement (SE) stack -this.DEBUG_ALL = false; - -// Set individually to debug specific layers -this.DEBUG_CONNECTOR = DEBUG_ALL || false; -this.DEBUG_ACE = DEBUG_ALL || false ; -this.DEBUG_SE = DEBUG_ALL || false ; - -// Maximun logical channels per session. -// For 'uicc' SE type this value is 3, as opening a basic channel' : 0 -// is not allowed for security reasons. In such scenarios, possible -// supplementary logical channels available are : [1, 2, or 3]. -// However,Other SE types may support upto max 4 (including '0'). -this.MAX_CHANNELS_ALLOWED_PER_SESSION = 4; - -this.BASIC_CHANNEL = 0; - -// According GPCardSpec 2.2 -this.MAX_APDU_LEN = 255; // including APDU header - -// CLA (1 byte) + INS (1 byte) + P1 (1 byte) + P2 (1 byte) -this.APDU_HEADER_LEN = 4; - -this.LOGICAL_CHANNEL_NUMBER_LIMIT = 4; -this.SUPPLEMENTARY_LOGICAL_CHANNEL_NUMBER_LIMIT = 20; - -this.MIN_AID_LEN = 5; -this.MAX_AID_LEN = 16; - -this.CLA_GET_RESPONSE = 0x00; - -this.INS_SELECT = 0xA4; -this.INS_MANAGE_CHANNEL = 0x70; -this.INS_GET_RESPONSE = 0xC0; - -// Match the following errors with SecureElement.webidl's SEError enum values -this.ERROR_NONE = ""; -this.ERROR_SECURITY = "SESecurityError"; -this.ERROR_IO = "SEIoError"; -this.ERROR_BADSTATE = "SEBadStateError"; -this.ERROR_INVALIDCHANNEL = "SEInvalidChannelError"; -this.ERROR_INVALIDAPPLICATION = "SEInvalidApplicationError"; -this.ERROR_GENERIC = "SEGenericError"; -this.ERROR_NOTPRESENT = "SENotPresentError"; -this.ERROR_ILLEGALPARAMETER = "SEIllegalParameterError"; - -this.TYPE_UICC = "uicc"; -this.TYPE_ESE = "eSE"; - -// Allow this file to be imported via Components.utils.import(). -this.EXPORTED_SYMBOLS = Object.keys(this); diff --git a/dom/secureelement/moz.build b/dom/secureelement/moz.build index a2c87b014..973000512 100644 --- a/dom/secureelement/moz.build +++ b/dom/secureelement/moz.build @@ -11,30 +11,6 @@ if CONFIG['MOZ_SECUREELEMENT']: 'DOMSecureElement.manifest', ] -if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_SECUREELEMENT']: - EXTRA_COMPONENTS += [ - 'gonk/ACEService.js', - 'gonk/ACEService.manifest', - 'gonk/GPAccessRulesManager.js', - 'gonk/GPAccessRulesManager.manifest', - 'gonk/SecureElement.js', - 'gonk/SecureElement.manifest', - ] - XPIDL_MODULE = 'dom_secureelement' - XPIDL_SOURCES += [ - 'gonk/nsIAccessControlEnforcer.idl', - 'gonk/nsIAccessRulesManager.idl', - 'gonk/nsISecureElementConnector.idl', - ] - EXTRA_JS_MODULES += [ - 'gonk/gp_consts.js', - 'gonk/se_consts.js', - 'SEUtils.jsm' - ] - XPCSHELL_TESTS_MANIFESTS += [ - 'tests/unit/xpcshell.ini' - ] - include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' |