/CommandCaseSupportTester.linq Secret
Last active
July 13, 2018 07:52
Script used with https://github.com/zetoken/command-case-applet Java Card applet
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
static byte[] appletAid = "F00102030405".FromHexa(); | |
static byte[] defaultUdc = "B1B2B3B4B5".FromHexa(); | |
const byte Cla = 0x80; | |
const byte InsGetBuffer = 0xCB; | |
const byte InsGetLc = 0xCC; | |
const byte InsGetLe = 0xCE; | |
static CommandAPDU selectCommand = new SelectCommand( | |
SelectCommand.SelectionMode.SelectDFName, | |
SelectCommand.FileOccurrence.FirstOrOnly, | |
SelectCommand.FileControlInformation.ReturnFci, | |
appletAid | |
); | |
void Main() | |
{ | |
var context = new CardContext(); | |
context.Establish().Dump("establish"); | |
context.ListReaders("").Dump("listReaders"); | |
context.Readers.Dump(); | |
try | |
{ | |
ProcessCommandCase("CC1", 0xC1, context); | |
ProcessCommandCase("CC2", 0xC2, context); | |
ProcessCommandCase("CC3", 0xC3, context); | |
ProcessCommandCase("CC4", 0xC4, context); | |
} | |
finally | |
{ | |
context.Release().Dump("release"); | |
} | |
} | |
void ProcessCommandCase(string label, byte ins, ICardContext context) | |
{ | |
var cc1 = new CommandAPDU(Cla, ins, 0x00, 0x00); | |
ProcessSafely(context, channel => ProcessCommand("When a CC1 is sent", cc1, channel).Dump($"CC1 sent to a {label} applet command")); | |
var cc2 = new CommandAPDU(Cla, ins, 0x00, 0x00, 0x40); | |
ProcessSafely(context, channel => ProcessCommand("When a CC2 is sent", cc2, channel).Dump($"CC2 (outgoing length: le) sent to a {label} applet command")); | |
if (label == "CC2" || label == "CC4") | |
{ | |
var cc2WithFixedOutgoingLength = new CommandAPDU(Cla, ins, 0x01, 0x03, 0x40); | |
ProcessSafely(context, channel => ProcessCommand("When a CC2 is sent", cc2WithFixedOutgoingLength, channel).Dump($"CC2 (outgoing length: P2) sent to a {label} applet command")); | |
var cc2WithMinOutgoingLength = new CommandAPDU(Cla, ins, 0x02, 0x03, 0x40); | |
ProcessSafely(context, channel => ProcessCommand("When a CC2 is sent", cc2WithMinOutgoingLength, channel).Dump($"CC2 (outgoing length: min(le, P2)) sent to a {label} applet command")); | |
} | |
var cc3 = new CommandAPDU(Cla, ins, 0x00, 0x00, 0x05, defaultUdc); | |
ProcessSafely(context, channel => ProcessCommand("When a CC3 is sent", cc3, channel).Dump($"CC3 sent to a {label} applet command")); | |
var cc4 = new CommandAPDU(Cla, ins, 0x00, 0x00, (byte)defaultUdc.Length, defaultUdc, 0x40); | |
ProcessSafely(context, channel => ProcessCommand("When a CC4 is sent", cc4, channel).Dump($"CC4 (outgoing length: le) sent to a {label} applet command")); | |
if (label == "CC2" || label == "CC4") | |
{ | |
var cc4WithFixedOutgoingLength = new CommandAPDU(Cla, ins, 0x01, 0x03, (byte)defaultUdc.Length, defaultUdc, 0x40); | |
ProcessSafely(context, channel => ProcessCommand("When a CC2 is sent", cc4WithFixedOutgoingLength, channel).Dump($"CC4 (outgoing length: P2) sent to a {label} applet command")); | |
var cc4WithMinOutgoingLength = new CommandAPDU(Cla, ins, 0x02, 0x03, (byte)defaultUdc.Length, defaultUdc, 0x40); | |
ProcessSafely(context, channel => ProcessCommand("When a CC2 is sent", cc4WithMinOutgoingLength, channel).Dump($"CC4 (outgoing length: min(le, P2)) sent to a {label} applet command")); | |
} | |
} | |
void ProcessSafely(ICardContext context, Action<ICardChannel> action) | |
{ | |
var rawChannel = new CardChannel(context, context.Readers.First()); | |
var channel = new CardChannelIso7816(rawChannel); | |
try | |
{ | |
channel.Connect(ShareMode.Exclusive, Protocol.Any); | |
var crpSelect = new CommandResponsePair(selectCommand); | |
crpSelect.Transmit(channel); | |
action(channel); | |
} | |
catch (Exception exception) | |
{ | |
exception.Dump("Something went wrong"); | |
throw; | |
} | |
finally | |
{ | |
channel.Disconnect(Disposition.UnpowerCard); | |
} | |
} | |
LastCommand ProcessCommand(string label, CommandAPDU capdu, ICardChannel channel) | |
{ | |
var crp = new CommandResponsePair(capdu); | |
var status = crp.Transmit(channel); | |
if (status == ErrorCode.Success) | |
{ | |
return new LastCommand( | |
channel.Protocol, | |
capdu, | |
crp.RApdu, | |
status, | |
GetLastX(InsGetBuffer, 0x40, channel), | |
GetLastX(InsGetLc, 0x02, channel), | |
GetLastX(InsGetLe, 0x02, channel) | |
); | |
} | |
else | |
{ | |
return new LastCommand( | |
channel.Protocol, | |
capdu, | |
crp.RApdu, | |
status, | |
new byte[] { }, | |
new byte[] { }, | |
new byte[] { } | |
); | |
} | |
} | |
byte[] GetLastX(byte ins, byte le, ICardChannel channel) | |
{ | |
var capdu = new CommandAPDU(Cla, ins, 0x00, 0x00, le); | |
var crp = new CommandResponsePair(capdu); | |
crp.Transmit(channel); | |
return crp.RApdu.Udr; | |
} | |
struct LastCommand | |
{ | |
byte[] RawBuffer; | |
byte[] RawLc; | |
byte[] RawLe; | |
CommandAPDU rawCommand; | |
ResponseAPDU rawResponse; | |
public Protocol Protocol { get; } | |
public string Command => rawCommand.ToString(); | |
public string Response => rawResponse.ToString(); | |
public ErrorCode Status { get; } | |
public string Buffer => RawBuffer.ToHexa(); | |
public string Lc => RawLc.ToHexa(); | |
public string Le => RawLe.ToHexa(); | |
public LastCommand(Protocol protocol, CommandAPDU command, ResponseAPDU response, ErrorCode status, byte[] buffer, byte[] lc, byte[] le) | |
{ | |
Protocol = protocol; | |
rawCommand = command; | |
rawResponse = response; | |
Status = status; | |
RawBuffer = buffer; | |
RawLc = lc; | |
RawLe = le; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment