Created
September 19, 2014 12:42
-
-
Save RomanKharin/62419218414a8b83ac1a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Read FOMS (Russian Health Card) http://www.openscdp.org/scsh3/index.html | |
// with emulator | |
// Romam Kharin <[email protected]>, 2014 | |
// based on explore.js | |
function SimFOMS () { | |
this.fsel = 0; // 0 - none, num - num | |
this.data0201 = new ByteString("", HEX); | |
this.data0202 = new ByteString("", HEX); | |
} | |
SimFOMS.prototype.retBinary = function(capdu, data) { | |
print("Read " + capdu); | |
// calc offset | |
var offset = capdu.bytes(2, 2).toUnsigned(); | |
if (offset & 0x8000) // short EF unsupported | |
return new ByteString("6B00", HEX); // Wrong parametres | |
var len = capdu.bytes(4, 1).toUnsigned(); | |
print("Offset " + offset + ", len " + len); | |
return data.bytes(offset, len).concat(new ByteString("9000", HEX)); | |
} | |
// The simulator needs a processAPDU method | |
SimFOMS.prototype.processAPDU = function(capdu) { | |
print("Recv: " + capdu); | |
if (new ByteString("00A4040C09666f6d735f726f6f74", HEX).equals(capdu)) | |
return new ByteString("9000", HEX); | |
if (new ByteString("00A4040C07464f4d535f4944", HEX).equals(capdu)) | |
return new ByteString("9000", HEX); | |
if (new ByteString("00A4020C020201", HEX).equals(capdu)) { | |
this.fsel = 0x0201; | |
return new ByteString("9000", HEX); | |
} | |
if (new ByteString("00A4020C020202", HEX).equals(capdu)) { | |
this.fsel = 0x0202; | |
return new ByteString("9000", HEX); | |
} | |
if (capdu.left(2).equals(new ByteString("00B0", HEX))) { | |
if (this.fsel == 0x0201) return this.retBinary(capdu, this.data0201); | |
if (this.fsel == 0x0202) return this.retBinary(capdu, this.data0202); | |
} | |
return new ByteString("6700", HEX); // Wrong length | |
} | |
// Reset | |
SimFOMS.prototype.reset = function(type) { | |
print("Reset type: " + type); | |
this.fsel = 0; | |
var atr = new ByteString("3BF71300008131FE45464F4D534F4D53A9", | |
HEX); // FOMSOMS | |
return atr; | |
} | |
// Uncomment following 3 lines to enable simulation | |
//var sa = new CardSimulationAdapter("JCOPSimulation", "8050"); | |
//sa.setSimulationObject(new SimFOMS()); | |
//sa.start(); | |
// Start explore card | |
load("tools/OutlineCore.js"); | |
function OutlineCard() { | |
this.Tags = { | |
"ICCID": [ | |
["ICCID_ROOT", 0x0000, 0, ""], | |
["ISSUER_CODE", 0x0000, 1, ""], | |
["ICCID_ISSUER_DATA", 0x0000, 2, ""], | |
], | |
"OwnerInfo": [ | |
["ROOT", 0x0201, 2, ""], | |
["Identity_1", 0x0201, 0x21, "utf8"], | |
["Identity_2", 0x0201, 0x22, "utf8"], | |
["Identity_3", 0x0201, 0x23, "utf8"], | |
["BirthDate", 0x0201, 0x24, "date"], | |
["Sex", 0x0201, 0x25, "sex"], | |
["PolicyNumber", 0x0201, 0x26, "utf8"], | |
["SNILS", 0x0201, 0x27, "utf8"], | |
["ExpireDate", 0x0201, 0x28, "date"], | |
["BirthPlace", 0x0201, 0x29, "utf8"], | |
["RegistrationDate", 0x0201, 0x2a, "date"], | |
], | |
"OwnerPhoto": [ | |
["ROOT", 0x0000, 0x40, ""], | |
["Type", 0x0000, 0x41, ""], | |
["Image", 0x0000, 0x42, ""], | |
], | |
"CardID": [ | |
["ROOT", 0x0000, 1, ""], | |
["UniqNumber", 0x0000, 0x11, ""], | |
["CardType", 0x0000, 0x12, ""], | |
["CardVersion", 0x0000, 0x13, ""], | |
["InstitutionID", 0x0000, 0x14, ""], | |
["AdditionalInfo", 0x0000, 0x15, ""], | |
], | |
"Citizenship": [ | |
["ROOT", 0x0201, 0x30, ""], | |
["CountryCode", 0x0201, 0x31, "utf8"], | |
["CountryCyrillicName", 0x0201, 0x32, "utf8"], | |
], | |
"SMO": [ | |
["Policy_ROOT", 0x0000, 2, ""], | |
["ROOT", 0x0000, 4, ""], | |
["OGRN", 0x0000, 0x51, ""], | |
["OKATO", 0x0000, 0x52, ""], | |
["InsuranceStartDate", 0x0000, 0x53, "date"], | |
["InsuranceExpireDate", 0x0000, 0x54, "date"], | |
["EDS", 0x0000, 0x60, ""], | |
["EDS_Value", 0x0000, 0x61, ""], | |
["EDS_Certificate", 0x0000, 0x62, ""], | |
], | |
} | |
this.tag_ref = {}; | |
for (var sect in this.Tags) { | |
var lst = this.Tags[sect]; | |
for (var i = 0; i < lst.length; i++) { | |
this.tag_ref[[lst[i][1], lst[i][2]]] = [sect, lst[i][0], lst[i][3]]; | |
} | |
} | |
// Create card object | |
var card = new Card(_scsh3.reader); | |
this.atr = card.reset(Card.RESET_COLD); | |
this.card = card; | |
// Create OutlineNode object and register in object | |
var view = new OutlineNode("Card"); | |
view.setUserObject(this); | |
this.view = view; | |
} | |
OutlineCard.prototype.printTLV = function(filenum, tlv, sub) { | |
var tt = tlv.getTag() >> 8; | |
var ta = tlv.getTag() & 0xFF; | |
var value = tlv.getValue(); | |
if (this.tag_ref.hasOwnProperty([filenum, ta])) { | |
var namtp = this.tag_ref[[filenum, ta]]; | |
var namsect = sub + namtp[0] + "_" + namtp[1]; | |
if (namtp[2] == "utf8") { | |
print(namsect + ": " + value.toString(UTF8)); | |
} else if (namtp[2] == "ascii") { | |
print(namsect + ": " + value.toString(ASCII)); | |
} else if (namtp[2] == "sex") { | |
var s = "hex=" + value; | |
if (value.toString(HEX) == "01") s = "M"; | |
if (value.toString(HEX) == "02") s = "F"; | |
print(namsect + ": " + s); | |
} else if (namtp[2] == "date") { | |
var s = "" + value.toString(HEX); | |
print(namsect + ": " + s.substr(0, 2) + "." + | |
s.substr(2, 2) + "." + s.substr(4)); | |
} else | |
print(namsect + ": " + tt + "," + ta + "(" + tlv.getL() + ")=" + tlv.getValue()); | |
} else { | |
print(tt + "," + ta + "(" + tlv.getL() + ")=" + value.toString(HEX)); | |
} | |
if (tt == 127) { | |
// subarray | |
var sublst = new TLVList(new ByteString(value.toString(ASCII), | |
ASCII), TLV.EMV); | |
for (var i = 0; i < sublst.length; i++) { | |
var stlv = sublst.index(i); | |
this.printTLV(filenum, stlv, sub + " "); | |
} | |
} | |
} | |
OutlineCard.prototype.printFile = function(name, filenum, data) { | |
print("Info: " + name + " (" + data.length + ")"); | |
for (var i = 0; i < data.length; i++) { | |
var tlv = data.index(i); | |
this.printTLV(filenum, tlv, ""); | |
} | |
} | |
OutlineCard.prototype.expandListener = function() { | |
if (this.expanded) | |
return; | |
var view = this.view; | |
var card = this.card; | |
// Display ATR | |
var atrnode = new OutlineATR(this.atr); | |
view.insert(atrnode.view); | |
this.expanded = true; | |
// build list | |
for (var key in this.Tags) { | |
var node = new OutlineNode(key); | |
view.insert(node); | |
} | |
// Select foms_root | |
try { | |
var fl = new CardFile(card, "#666f6d735f726f6f74"); // foms_root | |
this.foms_root = new OutlineNode("foms_root"); | |
view.insert(this.foms_root); | |
} | |
catch(e) { | |
print("Card does not seem to have a foms_root\n" + e); | |
} | |
// Select FOMS_FD | |
try { | |
var fl = new CardFile(card, "#464f4d535f4944"); // FOMS_FD | |
this.foms_fd = new OutlineNode("FOMS_FD"); | |
this.foms_root.insert(this.foms_fd); | |
} | |
catch(e) { | |
print("Card does not seem to have a FOMS_FD\n" + e); | |
} | |
// Select file 0x0201 | |
try { | |
var fl = new CardFile(card, ":0201"); | |
print("FCP: " + fl.getFCPBytes()); | |
var info1 = fl.readBinary(0, 1); | |
print("Info 1: " + info1); | |
var info2 = fl.readBinary(1, 1); | |
print("Info 2: " + info2); | |
var infolen = fl.readBinary(2, 1).toUnsigned(); | |
print("Info len: " + infolen); | |
var info = new TLVList(fl.readBinary(3, infolen), TLV.EMV); | |
} | |
catch(e) { | |
print("Card does not seem to have a info\n" + e); | |
} | |
this.printFile("0x0201", 0x0201, info); | |
try { | |
var fl = new CardFile(card, ":0202"); | |
print("FCP: " + fl.getFCPBytes()); | |
var info1 = fl.readBinary(0, 1); | |
print("Info 1: " + info1); | |
var info2 = fl.readBinary(1, 1); | |
print("Info 2: " + info2); | |
var infolen = fl.readBinary(2, 2).toUnsigned() + 4; | |
print("Info len: " + infolen); | |
var off = 0; | |
var data = new ByteString("", ASCII); | |
while (infolen > 0) { | |
var rlen = infolen; | |
if (rlen > 0xdc) { | |
rlen = 0xdc; | |
} | |
infolen -= rlen; | |
data = data.concat(fl.readBinary(off, rlen)); | |
off += rlen; | |
} | |
//print("Info len: " + infolen); | |
//var info = new TLVList(data, TLV.EMV); | |
//this.printFile("0x0202", 0x0202, info); | |
} | |
catch(e) { | |
print("Card does not seem to have a info-2\n" + e); | |
} | |
} | |
// Outline root node | |
var cardoutline = new OutlineCard(); | |
cardoutline.view.show(); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment