view sw/sniff-dec/command.c @ 55:5268246520de

simsniff-dec: decode command opcodes
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 04 Oct 2023 00:20:05 +0000
parents b0524d1dc6ef
children 966a54303d68
line wrap: on
line source

/*
 * Here we implement decoding of command APDU exchanges.
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "state.h"

extern char linebuf[];
extern int lineno;
extern unsigned rx_byte;
extern int state;

static char cmd_start_timestamp[18];
static int cmd_start_line;
static char data_start_timestamp[18];
static int data_start_line;
static char sw1_timestamp[18];
static int sw1_line;

static u_char cmd_hdr[5];
static unsigned hdr_byte_count;
static unsigned data_total, data_sofar, data_thistime;
static u_char data_buf[256], sw1;

void
start_cmd_header()
{
	strcpy(cmd_start_timestamp, linebuf);
	cmd_start_line = lineno;
	cmd_hdr[0] = rx_byte;
	hdr_byte_count = 1;
	state = STATE_CMD_HDR;
}

static void
decode_cmd_opcode()
{
	char *cmdname;

	switch (cmd_hdr[1]) {
	case 0xA4:
		cmdname = "SELECT";
		break;
	case 0xF2:
		cmdname = "STATUS";
		break;
	case 0xB0:
		cmdname = "READ BINARY";
		break;
	case 0xD6:
		cmdname = "UPDATE BINARY";
		break;
	case 0xB2:
		cmdname = "READ RECORD";
		break;
	case 0xDC:
		cmdname = "UPDATE RECORD";
		break;
	case 0xA2:
		cmdname = "SEEK";
		break;
	case 0x32:
		cmdname = "INCREASE";
		break;
	case 0x20:
		cmdname = "VERIFY PIN";
		break;
	case 0x24:
		cmdname = "CHANGE PIN";
		break;
	case 0x26:
		cmdname = "DISABLE PIN";
		break;
	case 0x28:
		cmdname = "ENABLE PIN";
		break;
	case 0x2C:
		cmdname = "UNBLOCK PIN";
		break;
	case 0x04:
		cmdname = "INVALIDATE";
		break;
	case 0x44:
		cmdname = "REHABILITATE";
		break;
	case 0x88:
		cmdname = "RUN GSM ALGO";
		break;
	case 0xFA:
		cmdname = "SLEEP";
		break;
	case 0xC0:
		cmdname = "GET RESPONSE";
		break;
	case 0x10:
		cmdname = "TERMINAL PROFILE";
		break;
	case 0xC2:
		cmdname = "ENVELOPE";
		break;
	case 0x12:
		cmdname = "FETCH";
		break;
	case 0x14:
		cmdname = "TERMINAL RESPONSE";
		break;
	default:
		cmdname = "Unknown!";
	}
	printf(" Command: %s\n", cmdname);
}

static void
print_cmd_hdr()
{
	unsigned n;

	printf("%s line %d: CMD", cmd_start_timestamp, cmd_start_line);
	for (n = 0; n < 5; n++)
		printf(" %02X", cmd_hdr[n]);
	putchar('\n');
}

void
cmd_hdr_byte_in()
{
	cmd_hdr[hdr_byte_count++] = rx_byte;
	if (hdr_byte_count < 5)
		return;
	print_cmd_hdr();
	if ((cmd_hdr[1] & 0xF0) == 0x60 || (cmd_hdr[1] & 0xF0) == 0x90) {
		printf(" ERROR: INS byte is invalid!\n");
		state = STATE_ERROR;
		return;
	}
	decode_cmd_opcode();
	if (cmd_hdr[4])
		data_total = cmd_hdr[4];
	else
		data_total = 256;
	data_sofar = 0;
	state = STATE_CMD_PROC;
}

static void
print_data()
{
	unsigned n;

	printf("%s line %d: DATA\n", data_start_timestamp, data_start_line);
	for (n = 0; n < data_sofar; n++) {
		printf(" %02X", data_buf[n]);
		if ((n & 15) == 15 || n == data_sofar - 1)
			putchar('\n');
	}
}

static void
handle_sw1()
{
	strcpy(sw1_timestamp, linebuf);
	sw1_line = lineno;
	sw1 = rx_byte;
	if (data_sofar)
		print_data();
	state = STATE_CMD_SW;
}

void
handle_ack(single)
{
	if (data_sofar >= data_total) {
		printf("%s line %d: ERROR: ACK for more data than possible\n",
			linebuf, lineno);
		state = STATE_ERROR;
		return;
	}
	if (!data_sofar) {
		strcpy(data_start_timestamp, linebuf);
		data_start_line = lineno;
	}
	if (single)
		data_thistime = 1;
	else
		data_thistime = data_total - data_sofar;
	state = STATE_CMD_DATA;
}

void
cmd_proc_byte_in()
{
	if (rx_byte == 0x60)
		return;
	if ((rx_byte & 0xF0) == 0x60 || (rx_byte & 0xF0) == 0x90) {
		handle_sw1();
		return;
	}
	if (rx_byte == cmd_hdr[1]) {
		handle_ack(0);
		return;
	}
	if (rx_byte == (cmd_hdr[1] ^ 0xFF)) {
		handle_ack(1);
		return;
	}
	printf("%s line %d: ERROR: invalid procedure byte\n", linebuf, lineno);
	state = STATE_ERROR;
}

void
cmd_data_byte_in()
{
	data_buf[data_sofar++] = rx_byte;
	data_thistime--;
	if (data_thistime)
		return;
	state = STATE_CMD_PROC;
}

void
cmd_sw2_byte_in()
{
	printf("%s line %d: SW %02X %02X\n", sw1_timestamp, sw1_line, sw1,
		rx_byte);
	state = STATE_READY_FOR_CMD;
}