view serial/exchange.c @ 99:97ba63d9361a

scripts/fcsim1-sst: turn off STK & OTA services In the initial unprogrammed state of the cards from Grcard, SST has services 25 through 29 set to allocated and activated. However, these cards appear to not actually support OTA, ENVELOPE commands do nothing (just return SW 9000), and they were never observed issuing any proactive SIM commands, even after a feature-generous TERMINAL PROFILE. Therefore, let's list these STK & OTA services as allocated, but not activated in our FCSIM1 SST.
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 05 May 2021 04:26:07 +0000
parents be27d1c85861
children
line wrap: on
line source

/*
 * This module implements the main function of our back end:
 * exchanging APDUs with the SIM.
 */

#include <sys/types.h>
#include <stdio.h>

static
collect_one_byte()
{
	u_char buf;
	int rc;

	rc = collect_bytes_from_sim(&buf, 1);
	if (rc < 0)
		return rc;
	else
		return buf;
}

static void
finish_sw(sw1, data, datalen)
	unsigned sw1, datalen;
	u_char *data;
{
	unsigned sw2, n;
	int rc;

	rc = collect_one_byte();
	if (rc < 0) {
		printf("back end error at SW2 Rx step\n");
		return;
	}
	sw2 = rc;
	for (n = 0; n < datalen; n++)
		printf("%02X", data[n]);
	printf("%02X%02X\n", sw1, sw2);
}

static void
exchange_data_out(ins, data, datalen)
	unsigned ins, datalen;
	u_char *data;
{
	int rc;
	unsigned null_count, bytes_sent, ack, ack1;

	ack = ins & 0xFE;
	ack1 = ~ins & 0xFE;
	bytes_sent = 0;
	null_count = 0;
	for (;;) {
		rc = collect_one_byte();
		if (rc < 0) {
			printf("back end error at procedure byte step\n");
			return;
		}
		if (rc == 0x60) {
			null_count++;
			if (null_count >= 32) {
				printf(
		"ERROR: too many stalling NULL bytes received from SIM\n");
				return;
			}
			continue;
		}
		if ((rc & 0xF0) == 0x60 || (rc & 0xF0) == 0x90) {
			finish_sw(rc, 0, 0);
			return;
		}
		if ((rc & 0xFE) == ack) {
			if (bytes_sent >= datalen) {
bad_xfer_req:			printf(
		"ERROR: SIM requests more xfer after we sent everything\n");
				return;
			}
			rc = send_bytes_to_sim(data + bytes_sent,
						datalen - bytes_sent);
			if (rc < 0) {
				printf("back end error at data output step\n");
				return;
			}
			bytes_sent = datalen;
			continue;
		}
		if ((rc & 0xFE) == ack1) {
			if (bytes_sent >= datalen)
				goto bad_xfer_req;
			rc = send_bytes_to_sim(data + bytes_sent, 1);
			if (rc < 0) {
				printf("back end error at data output step\n");
				return;
			}
			bytes_sent++;
			continue;
		}
		printf("ERROR: non-understood procedure byte %02X\n", rc);
		return;
	}
}

static void
exchange_data_in(ins, datalen)
	unsigned ins, datalen;
{
	int rc;
	unsigned null_count, bytes_rcvd, ack, ack1;
	u_char data[256];

	if (!datalen)
		datalen = 256;
	ack = ins & 0xFE;
	ack1 = ~ins & 0xFE;
	bytes_rcvd = 0;
	null_count = 0;
	for (;;) {
		rc = collect_one_byte();
		if (rc < 0) {
			printf("back end error at procedure byte step\n");
			return;
		}
		if (rc == 0x60) {
			null_count++;
			if (null_count >= 32) {
				printf(
		"ERROR: too many stalling NULL bytes received from SIM\n");
				return;
			}
			continue;
		}
		if ((rc & 0xF0) == 0x60 || (rc & 0xF0) == 0x90) {
			finish_sw(rc, data, bytes_rcvd);
			return;
		}
		if ((rc & 0xFE) == ack) {
			if (bytes_rcvd >= datalen) {
bad_xfer_req:			printf(
	"ERROR: SIM requests more xfer after we received all expected data\n");
				return;
			}
			rc = collect_bytes_from_sim(data + bytes_rcvd,
						    datalen - bytes_rcvd);
			if (rc < 0) {
				printf("back end error at data input step\n");
				return;
			}
			bytes_rcvd = datalen;
			continue;
		}
		if ((rc & 0xFE) == ack1) {
			if (bytes_rcvd >= datalen)
				goto bad_xfer_req;
			rc = collect_one_byte();
			if (rc < 0) {
				printf("back end error at data input step\n");
				return;
			}
			data[bytes_rcvd++] = rc;
			continue;
		}
		printf("ERROR: non-understood procedure byte %02X\n", rc);
		return;
	}
}

void
apdu_exchange(cmd_apdu, cmd_apdu_len)
	u_char *cmd_apdu;
	unsigned cmd_apdu_len;
{
	int rc;

	rc = send_bytes_to_sim(cmd_apdu, 5);
	if (rc < 0) {
		printf("back end error at the command sending step\n");
		return;
	}
	if (cmd_apdu_len > 5)
		exchange_data_out(cmd_apdu[1], cmd_apdu + 5, cmd_apdu_len - 5);
	else
		exchange_data_in(cmd_apdu[1], cmd_apdu[4]);
}