diff options
Diffstat (limited to 'dom/secureelement/gonk/SecureElement.js')
-rw-r--r-- | dom/secureelement/gonk/SecureElement.js | 514 |
1 files changed, 0 insertions, 514 deletions
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]); |