зеркало из https://github.com/mozilla/gecko-dev.git
Bug 884594 - Part 2.1: GPAccessRulesManager and nsIAccessRulesManager.idl. Add utils to SEUtils.jsm. r=allstars.chh
This commit is contained in:
Родитель
0e3b1068eb
Коммит
678b572d0f
|
@ -50,6 +50,67 @@ this.SEUtils = {
|
|||
|
||||
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"];
|
||||
|
|
|
@ -0,0 +1,436 @@
|
|||
/* 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;
|
||||
});
|
||||
|
||||
let 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]);
|
|
@ -0,0 +1,2 @@
|
|||
component {3e046b4b-9e66-439a-97e0-98a69f39f55f} GPAccessRulesManager.js
|
||||
contract @mozilla.org/secureelement/access-control/rules-manager;1 {3e046b4b-9e66-439a-97e0-98a69f39f55f}
|
|
@ -0,0 +1,62 @@
|
|||
/* 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);
|
|
@ -0,0 +1,50 @@
|
|||
/* 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();
|
||||
};
|
Загрузка…
Ссылка в новой задаче