Adventures in ISO7816 “Smart” I/O Triggering

I recently wanted to build something to help me trigger off ISO7816 traffic. This led to a week of learning-through-failure, and this post talks through some of the learning experiences, and provides a solution for anyone else attempting to solve the same problem (not a true “smart” trigger, but at least something to land you in the right general place).

An initial design constraint for me was to not use a host emulation approach: while it would be simple to build a “smartcard proxy” which sent the appropriate trigger whenever I wanted, I think this would be extremely limiting in cases where the smartcard tries to verify the host via something like baud rate support or similar.

ISO7816 communication can be summarized as a synchronous one-line serial protocol with a non-standard baud rate that may change over the lifetime of a session (derived off the clock line). It can be decoded using UART, but you’ll need to experiment with baud rate to get a clear reading (the following traffic was at 149K).

Furthermore, there are quirks like the client will “echo” one byte of a command back to the reader, typically before arguments are provided, which may not be visible at first glance.

Upon initially facing the problem, I immediately entered a fit of madness, and decided I would use an ATMega168’s external interrupts to count IO edges. I suspect primarily wanted to do this:

This was a learning adventure in using external interrupts on the ATMega168/328, which I had not actually done before. In a nutshell, they can be used by configuring two registers:

  • EICRA, which configures when an interrupt should occur (rising edge, falling edge, any change).
  • EIMSK, which configures which interrupts are permitted

The actual interrupt routine is defined as a special function (in the below example, for interrupt 0).

ISR (INT0_vect)
PORTB ^= (1 << PINB1);
PORTD ^= (1 << PIND0);

While aesthetically pleasing in it’s own hot-glue-and-duct-tape way, the ATmega168 solution is unfortunately a bit too slow for this work. At 3.3V, we’re able to run at 8Mhz at best, which isn’t enough to do clock-cycle-level triggering on something running at just over >4Mhz. We can’t really use a higher voltage, otherwise at 5V, we’ll miss the 1.8V logic signal (and I didn’t have any level shifters handy, and a grand total of 3 2N3904’s left).

On rethinking the problem, I took the more sane approach of using an FPGA for this task. I started with a simple edge counter, which worked fine for static traffic – but I needed to be able to send somewhat variable traffic to the target for the task at hand. I dug out my old workhorse Arty board and a Saleae for debugging, and got to work:

I settled on a hybrid approach, where I first counted rising edges on the I/O line to get me “close”, then counted clock edges wherever variable data (but fixed-length data) was present. This can be represented by the following logic diagram:

This unfortuantely resulted in a stack of errors around the “multi-driven nets”. To debug this error, I could refer to the Schematic, under “Open Elaborated Design” on the navigation menu in Vivado 2018.3. This opens up a schematic representing which inputs drive which outputs:

A correct flow graph looks like this, with your inputs driving all outputs (i.e. connected left/right). Any outputs which are driven multiple times (which Vivado turns into driven once, and ignored) should stick out pretty quickly.

I tackled this hurdle by fixing my code to use scard_clk as a “Master External Clock” controlling the sampling of all other inputs, and then using state machine model to drive state transitions between waiting for IO edges and waiting for clock edges. Truly, FPGA programming is always a breath of fresh air and fresh thinking onto a problem.

The result is a nice, clean consistent trigger, down to the clock cycle (lines are CLK/IO/trigger):

15 minutes of SPA (what a fancy name for “looking at it”) later, and we are able to identify the 14 rounds of the first full-size software AES operation (in this case, testing of a supplied AUTN parameter as part of MILENAGE – what exciting times we live in!).

The code is available in the “x/” directory of As a future improvement, I’m keen to make a re-usable, on-the-fly configurable core (though this seems to be a rock-and-a-wierd-place choice between convenience vs overhead – I will study the chipwhisperer source code for clues).

I am keen to hear more about other people’s approaches to this problem – I am sure there are more elegant solutions out there. If you have a different implementation strategy, please do get in touch (or just comment below).

About Norman

Sometimes, I write code. Occasionally, it even works.
This entry was posted in Bards, Computers, Jesting. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.