This document contains the technical documentation of the software part
of the “Smart Card Sniffing and Debugging Tool” (SCSDT) project.
The software is used to log data that is being transmitted on a contact
interface between an ME and a smart card using a hardware unit developed
for this purpose. The software is able to – in one mode – to parse logged
data and present them in real-time in a readable format.
Contents
SCSDT – Smart Card Sniffing and Debugging Tool -
Documentation
Initial files (for communicating with the hardware)
USBPoller – The Producer for the HighlevelLogger
The software handles the setup, and communication with an Opal Kelly
XEM3001v2 board connected with a PC via a USB2 cable.
Figure 1: Sniffer connected via a connector to a ME to the left and via
an USB2 cable to a laptop on the right
A C# dynamic link library (DLL) along with an API was provided by the
manufacturer (Opal Kelly) for the board. This .dll along with the API
functions are the base foundation of the Sniffer Software.
The API provides the base for readings and initializations etc.
The Sniffer Software is built in the solution file Sniffer.sln.
The solution file (Sniffer.sln) consists of two projects:
OKUSBLib, handling the basic reading and writing using the basic API
functions provided.
Sniffer, providing a GUI to let the user interact with the sniffer
hardware as well as giving other features. There are two features
worth mentioning here.
Feature 1: Using the Sniffer software to analyze an already recorded
Sniffer log.
OKUSBLIB
The OKUSBLib project contains one class:
Class name | Description |
---|---|
OKUSB2.cs | Contains implemented functions as |
defined in the abstract class IUSB.cs. | |
It is this class that interfaces to the | |
Sniffer with the provided API functions | |
provided by Opal Kelly. |
Table 1: OKUSBLib classes
The OKUSBLib classes contain the interface code containing API function
calls for the initialization and resetting of the device along with
functions for reading buffer status and reading a specific number of
bytes from the hardware.
Either a single byte is read at the time, using ReadWireOut. This is
used when polling the device to check if there is data available.
Alternatively a range of bytes are read with ReadPipeOut.
The OKUSB2.cs contains a few functions for doing a few necessary
commands in order for the hardware to work as intended.
Function name | Description |
---|---|
EmptyBuffers | Empties the high level FIFO (handy |
when resetting a session) | |
ResetSnifferLogger | Resets the hardware and forces the |
sniffer to negotiate PPS. A note: | |
The processing of the ATR + PPS is | |
done in the Hardware (Sniffer) | |
itself. This is due to the fact, | |
that it is a time critical process | |
and therefore the processing of the | |
ATR /PPS is put on the HW side, | |
instead of requiring the SW to be | |
able to handle this | |
ReadWireOut | Reads data from a specified wire out |
address, (used when polling for a | |
status byte, bit coded, to indicate | |
if there is data ready and how much) | |
for example. | |
ReadPipeOut | Reads from a provided PipeOut |
Register, data into a byte array as | |
per argument. | |
WriteWireIn | Function for writing a data byte to |
a specified wire in address. | |
Currently not used. | |
WritePipeIn | Function for writing an array of |
data from a byte array into a wire | |
in address. Currently not used. |
On the hardware side of things – 2 FIFOs are used for providing data to
the software. The following is an overview of this.
The SCSDTGeneric project contains classes that are used by both the
OKUSBLib and by the Sniffer project.
In this way the software is not dependent on the existence of the
hardware.
Class name | Description |
---|---|
Constants.cs | Contains addresses of Wires/Pipes used for reading/writing |
data to the Sniffer. | |
It also contains data for transfer sizes and bit patterns | |
to be checked. | |
IUSB.cs | Abstract class that contains all the functions that is |
to be implemented to have a Sniffer. | |
It contains functions such as ResetSniffer, EmptyBuffers, | |
ReadBufferStatus, ReadNumberOfBytes |
The hardware is based on an Opal Kelly XEM3001 FPGA board.
With the base in the above board and with the addition of a few level
converters, a SIM probe, a DB9 plug and knowledge about 7813-3, a VHDL
design was created to sample on the IO/RST and CLK pins – to put it
short. Dennis Vitus Lajer Rasmussen has done all design, construction
and development of the Sniffer hardware.
In the Sniffer hardware design the following definition is used to
differentiate between the 2 types of data that can be read out from it:
The sample data is put into two FIFOs – FIFO2 and FIFO3, with addresses
as below and hardcoded in Constants.cs.
The direction IN is when data is sent to the FPGA.
The direction OUT is used when data is retrieved from the FPGA.
Wire In Name | Address value |
---|---|
SPEED_ENHANCEMENT_WIREIN | 0x10, (used to force the HW to do |
the PPS negotiation) putting the | |
weight on the HW instead of in the | |
software. | |
HIGH_LEVEL_LOGGER_STATUS_WIREIN | 0x35 (Used to check whether there is |
high level /low level data). | |
SET_SPEED_ENHANCEMENT_WIREIN | 0x90, 4 FFs are sent to this wirein |
to force PPS negotiation to happen | |
in the HW. | |
RESET_SNIFFER_HW_WIRE | 0x8E, (not used) |
HIGH_LEVEL_LOGGER_PIPE_OUT | 0xAF (after determining from the |
status byte that there is either 2 | |
or 2*512 bytes available), data is | |
fetched from this pipe out. | |
LOW_LEVEL_LOGGER_PIPE_OUT | 0xB0 (after determining from the |
status byte that there is either 6 | |
or 6*512 bytes available), data is | |
fetched from this pipe out. |
As mentioned several times, chunks of data is read from the hardware, by
reading of pipe outs, either for the high or the low level pipe.
But this is only done, when there is data to be fetched. Whether data is
available or not, is checked initially by polling 0x35, wire out.
The Wire out takes the pattern as indicated in Table 2.
B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | Description |
---|---|---|---|---|---|---|---|---|
1 | FIFO3 full,continue | |||||||
but report warning | ||||||||
1 | 512 events- 2*512 | |||||||
bytes available | ||||||||
1 | 1 event (2 bytes) | |||||||
are available | ||||||||
1 | Empty FIFO- at least | |||||||
1 event, 2 bytes | ||||||||
are available | ||||||||
1 | FIFO2 full, | |||||||
continue but | ||||||||
report warning | ||||||||
1 | 512 events- 6*512 | |||||||
bytes available | ||||||||
1 | Almost empty (not needed | |||||||
by the SW) | ||||||||
1 | Empty, at least 1 | |||||||
event (6 bytes | ||||||||
available) | ||||||||
Table 2: Bit pattern of wire out (0x35) |
If there is data available, data bytes are fetched. Following
description is made to clarify what is understood by high level and low
level data. And what exactly is being fetched.
1 event, consisting of 2 bytes – takes the form as depicted in Error!
Reference source not found.
For each event there is a status byte. The status byte is coded as
depicted in [Table 3]
B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | Description |
---|---|---|---|---|---|---|---|---|
1 | FIFO full, continue | |||||||
but report warning | ||||||||
1 | 512 events- | |||||||
2*512 | ||||||||
bytes available | ||||||||
1 | 1 event (2 bytes) | |||||||
are available | ||||||||
1 | Empty FIFO- | |||||||
at least 1 | ||||||||
more event | ||||||||
(2 bytes) | ||||||||
are available | ||||||||
RFU | ||||||||
1 | Parity error bit | |||||||
1 | Error signal bit | |||||||
1 | Reset detected bit |
Table 3: Content of status byte for an event
To summarize: The high level logger (which is the one described above)
gets its data from FIFO 3 on the hardware. The data is received by the
use of Read Wire Out as previously mentioned.
LowLevelLogger
Similarly for the low level logger, 1 event consists of 6 bytes
Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 |
---|---|---|---|---|---|
AA | BB | CC | DATA | DUMMY | SS |
Table 4: Low Level event illustration
Where
AA BB CC = 24 bits clock counter, AA=LSB.. CC=MSB, which is an
indicator for the number of clocks that has elapsed since the last
event.
DATA is coded as illustrated in Table 5
B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | Description |
---|---|---|---|---|---|---|---|---|
1 | x | x | x | x | x | x | x | 000 = 0V |
x | 1 | x | x | x | x | x | x | 001 = between 0V and 1.8V |
010 = 1.8V | ||||||||
011 = between 1.8V and 3.0V | ||||||||
x | x | 1 | x | x | x | x | x | 100 = 3.0V |
101 = between 3.0V and 5V | ||||||||
110 = 5V | ||||||||
x | x | x | 1 | x | x | x | x | RFU |
x | x | x | x | 1 | x | x | x | RFU |
x | x | x | x | x | 1 | IO state, high/low | ||
x | x | x | x | x | x | 1 | x | RFU |
x | x | x | x | x | x | x | 1 | Reset state, high/low |
Table 5: Data byte meaning for Low Level Logger
DUMMY byte is reserved for future use.
SS is a status byte and takes the following, almost identical
pattern as that of the high level logger, except it also contains
information about the high level logger, (to avoid having to poll
again).
B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | Description |
---|---|---|---|---|---|---|---|---|
1 | FIFO3 full, | |||||||
continue | ||||||||
but report warning | ||||||||
1 | 512 events- | |||||||
2*512 bytes | ||||||||
available | ||||||||
1 | 1 event (2 bytes) | |||||||
are available | ||||||||
1 | Empty FIFO- | |||||||
at least 1 | ||||||||
event, 2 bytes | ||||||||
are available | ||||||||
1 | FIFO2 full, | |||||||
continue but | ||||||||
report warning | ||||||||
1 | 512 events- | |||||||
6*512 | ||||||||
bytes available | ||||||||
1 | Almost empty | |||||||
(not needed | ||||||||
by the SW) | ||||||||
1 | Empty,at least 1 | |||||||
event (6 bytes | ||||||||
available) |
Table 6 Low Level Status Byte (SS) meaning
With an idea about the data generated from the hardware, a second
project, the Sniffer project was created.
The Sniffer project is built on the concept of a “producer –consumer”
design.
Producer | Consumer |
---|---|
USBPollerHigh | HighLevelLogger |
UBPollerLow | LowLevelLogger |
The USBPollerHigh/USBPollerLow class is the producer.
These two classes are both of the type, Poller. These are under the
control of a PollerController.
The HighlevelLogger/LowLevelLogger class is the consumer.
Table 7: Flowchart of the USBPoller mechanism
In the Sniffer, there is a GUI that interacts with the user. The GUI
will allow enabling/disabling polling and processing of both high and
low level data – so control is added to the main form that will create
an instance of PollerController for each of the logs requested.
Classes exist to poll the USB2 port on the Sniffer hardware for data.
This is done by using some of the functions created in the OKUSB2, as
described above.
Initially the USBPoller reads a WireOut on the Sniffer until data is
available indicated by a bit mask in the read value as illustrated in
Table 2
If data is available events are fetched and put on a list.
Either 1 event is fetched, giving rise to a 2 byte data array.
Alternatively, 512 events are fetched – giving rise to a 1024 byte
array.
Each event is built as illustrated in Error! Reference source not
found..Error! Reference source not found.If more data is available
– as detected in the status byte, more events will be fetched.
If no more events are available – the USBPoller will read data from a
WireOut – as initially - to check for available data. This will continue
forever until the user terminates the session.
The interaction between the USBPoller and the HighLevelLogger can be
described in the following manner:
The USBPoller continuously adds events, formed as byte arrays to a list.
The byte arrays added are either 2 events long or 512 events long.
The HighLevelLogger will read the entries from the list of byte arrays
and interpret data according to a state machine – first processing an
ATR, PPS and then APDUs as they appear. The formatting of the APDUs
occurs based on an xml file, indicating the type of command.
The interaction between the HighLevelLogger and the Sniffer is as
follows:
The idea is that the USBPoller should always provide data, and the
HighLevelLogger will read entries and interpret them one entry at the
time.
GUI related classes
Class name | Description |
---|---|
Changelog | Inside about box – containing |
information of what was done since | |
last release | |
Change | Class for defining what defines a |
change. | |
MainForm | Main GUI holding all buttons, radio |
buttons and also displays the live | |
stream of logged data. |
The Sniffer project also contains the following classes for handling all
the other functionality
Class name | Description |
---|---|
AnswerToReset | This class contains a state machine |
to decode the ATR (Answer To Reset). | |
The ATR is information presented by | |
the SIM to the ME in the beginning | |
of a card session. It is the way the | |
SIM can give information to the ME | |
about what it supports. | |
Command | This is a serializable class that is |
used in connection with the reading | |
of CommandInfo.xml. | |
CommandInfo is an xml file next to | |
the executable that takes the form | |
as displayed above. The xml file is | |
used when interpreting data on the | |
I: O: form, tagging the command and | |
splitting it accordingly into what | |
type it is. | |
DataPackage | Datapackage is a class created with |
the aim of separating a read event | |
read from a high level logger of the | |
form : [data, status] into two bytes | |
– where the second status byte can | |
be examined for whether a reset or a | |
parity error has occurred. | |
HighLevelLogger | HighLevelLogger is created in the |
MainForm on an initiation of a | |
logging session. | |
When the USBPoller has indicated | |
that there are events available, the | |
HighLevel logger will get data. It | |
will pack the data into data | |
packages and put data onto a | |
concurrent queue. Then the state | |
machine is called, which will put | |
the data onto the real time screen. | |
HighLevelLoggerFile | |
LowLevelLogger | |
PipeInfo | Explained in the table polling |
mechanism | |
Poller | Explained in the table polling |
mechanism | |
PollerController | Explained in the table polling |
mechanism | |
PPS | Contains a state machine that |
processes a PPS negotiation. It will | |
return true, when a full PPS has | |
been received. A PPS will take the | |
form : | |
PPS : PPSS PPS0 [PPS1 PPS2 PPS3] | |
PCKS - where PPS1..3 are optional | |
ProactiveCommand | Contains a state machine for |
determining when all bytes of a | |
command have been received. | |
Program | Main program for the application, |
does nothing except checks that | |
commandinfo.xml is present (more | |
files could be added here) and | |
starts the application. | |
ReleaseInformation | Called by MainForm as part of the |
Help/ChangeLog pressing. It is a | |
class with information about release | |
version number and changes (From the | |
Change.cs ) class that have occurred | |
since last. | |
Statemachine | Contains a state machine with states |
for ATR, possible PPS and APDUs. | |
This class is called from the High | |
Level Logger and will dequeue data | |
from a concurrent queue and write it | |
to an online real time box. | |
USB2Simulator | This class is merely designed from |
an existing log. It reads in data | |
already logged as if this is data | |
read live. It can then be used to | |
simulate a logging session and makes | |
it easy to debug code | |
USBPollerHigh | Explained in the table polling |
mechanism | |
USBPollerLow | Explained in the table polling |
mechanism | |
Filename | Description |
---|---|
PipeInfo | Class that holds a name, size and |
type to be used by the | |
PollerController when creating named | |
pipes. | |
PollerController.cs | Contains the constructor that makes |
sure to instantiate as many pollers | |
as required (low and high level) as | |
requested via the MainForm’s | |
checkboxes. Starts a thread that | |
reads the status byte from the wire | |
out (0x35) (High level logger status | |
byte to check if there is either low | |
or high level data and in that case, | |
how much). | |
Before actually fetching data, the | |
PollerController creates Named pipes | |
which are a way of piping data from | |
a server to a client, which is part | |
of the producer ->consumer | |
structure that the Sniffer project | |
uses. | |
Data is fetched with the following | |
priority. | |
Priority list: | |
-a lot of data from the low level | |
logger | |
-a lot of data from the high level | |
logger | |
-small amount of data from the low | |
level logger | |
-small amount of data from the high | |
level logger | |
Poller.cs | Abstract class with a few functions |
that applies to both the | |
USBPollerHigh and Low, which are of | |
this type. | |
USBPollerHigh.cs | Called by the Poller controller, |
reads either 2 or 2*512 bytes at | |
the time and writes data to a binary | |
writer =named pipe server. After | |
reading 2 or 2*512 bytes it reads | |
to check if there are more data to | |
be fetched. | |
USBPollerLow.cs | Called by the Poller controller, |
reads either 6 or 6*512 bytes at | |
the time and writes data to a binary | |
writer =named pipe server. After | |
reading 6 or 6*512 bytes it reads | |
to check if there are more data to | |
be fetched. |