There’s good and bad news for my project, the good news being I’m developing Smart Card programming skills at a reasonable pace. The slightly bad news is the programming’s done with raw machine code, and I’ll probably need to (somehow) create device drivers or kernel modules for doing stuff at the application level.
The thing is ‘Smart Cards’, aren’t exactly smart. The functions are provided by an internal chip containing sets of transistors in different configurations, and a machine code instruction (e.g. 0111) is just a reference to physical pins feeding the chip. When voltage is applied to the right pins, data is passed from a tiny diode array (memory register A), through a specific transistor configuration and into another diode array (memory register B). In turn, the memory registers themselves cache whatever data was fetched from RAM. This is the long and short of what’s happening at the hardware level, and ultimately what happens when people run any program/application on their computer.
APDUs and Machine Code
Communication with the microprocessor is done at a very low level, as byte strings called ‘Application Protocol Data Units’ (APDUs). The concept is vaguely similar to that of TCP packets, in that it involves a header and payload. The header is always 4 bytes in length (at least with the ACOS3), even when not all of them are used. The first byte is the machine code instruction itself, and because we’re dealing with direct memory addressing we also specify the number of bytes to be processed when the instruction executes.
While APDUs are pretty standard across most microprocessor-based cards, the instruction sets appear to be vendor-specfic. Knowing exactly how to put together an instruction demands a bit of research, being shit hot at hex-binary-ASCI-decimal conversion and the ability to keep track of memory addresses (or offsets) being used. Luckily SmartCard Focus had included enough documentation (especially the ACOS3 Smart Card Reference Manual) and an excellent range of diagnostic tools on the CD to make the task slightly easier.
ACOS3 Programming Overview
A typical instruction for the ACOS3’s microprocessor has the initial instruction and data length bytes, followed by the payload, which I estimate to have a max size of around 250-253 bytes.
To write data to the card’s EEPROM, the command must also specify the address to write to and how many bytes should be written there. This is important because we’re not dealing with files. Data is overwritten instead of deleted, and data blocks can only be addressed as offsets from the EEPROM’s start location (whatever that might be).
For the ACOS3 the write instruction is always 91h. As an example, if we wanted to write ‘Hello World’ to memory address 3Ah on the card’s EEPROM, the pseudocode would be something like:
WRITE: 11 BYTES TO 00 3Ah: HELLO WORLD
Which translates into the following instruction:
91 00 3A 48 65 6C 6C 6F 20 57 6F 72 6C 64
It’s a similar case with reading the data back off the card, as we must specify how many bytes to read from a given adress. Here the machine code instruction is 90h. If we wanted to read ‘Hello World’ from the address it was written to earlier, the pseudocode would be something like:
READ: 11 BYTES FROM 00 3Ah: 00
Which gives us:
90 00 00 00 3A 0A
There are a couple more things I tried out with the ACOS3 and some other cards. The crypto processor has a PRNG, and a 64-bit pseudo-random number (suffixed with a status code) is generated by sending instruction ’80 84 00 00 08′. It probably uses this to generate session keys for transactions, which would mean the Triple-DES function is only using a 64-bit key. If the processor’s PRNG is capable of generating a 128-bit value (which is a 16-bytes), we could get that by substituting the last byte with ’10’ (10h = 16).
If the card’s messed up, it could be reset to its factory state with ’80 30 00 00 00′. The ’80 24 00 00 08 5555′ command changes the PIN to ‘5555’. What we should start to notice is a pattern in the instruction set, where ’80h’ refers to control operations, ’90h’ refers to read operations, and ’91h’ instructions write data.
Is there an IDE for writing machine code to a Smart Card? Well, there sort of is one, in the form of (g)scriptor. This tool can run a sequence of predefined bytestrings as a ‘script’, so a series of operations could be automated. It’s important to confirm the reader is connected and the card’s processor is functioning, by selecting ‘Reader — Status…’.
Now we can send bytes to the card and see what’s returned. Here I think I’ve established that ‘6E 00′ is an error message or no response, while ’90 00’ is okay message.
Unfortunately I haven’t got very far writing decent Smart Card programs for Python, for the reasons above. At the moment I only have a script, using the PysCard module, that does generic card reader detection and ATR reading.