view utils/fcsim1-mkprov.c @ 82:28fae57b3e29

fcsim1-mkprov: add OTA_C and OTA_D key generation
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 10 Apr 2021 23:21:47 +0000
parents 38c14fa89937
children 6041c601304d
line wrap: on
line source

/*
 * This utility is the provisioning data generator for FCSIM1 cards.
 */

#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static u_char iccid_bin[19], imsi_bin[15], msisdn_bin[20];
static int msisdn_set, msisdn_plus;
static unsigned num_cards = 1, access_class, msisdn_digits;
static char *random_file = "/dev/urandom";
static int random_fd;

static void
set_iccid(arg)
	char *arg;
{
	int rc;

	rc = parse_decimal_shorthand(arg, iccid_bin, 18);
	if (rc < 0)
		exit(1);	/* error msg already printed */
}

static void
set_imsi(arg)
	char *arg;
{
	int rc;

	rc = parse_decimal_shorthand(arg, imsi_bin, 15);
	if (rc < 0)
		exit(1);	/* error msg already printed */
}

static void
set_msisdn(arg)
	char *arg;
{
	int rc;

	if (*arg == '+') {
		msisdn_plus = 1;
		arg++;
	}
	rc = parse_decimal_string_arg(arg, msisdn_bin, 20);
	if (rc < 0)
		exit(1);	/* error msg already printed */
	msisdn_digits = rc;
	msisdn_set = 1;
}

static void
parse_cmdline(argc, argv)
	char **argv;
{
	extern int optind;
	extern char *optarg;
	int c;

	while ((c = getopt(argc, argv, "a:m:n:r:")) != EOF) {
		switch (c) {
		case 'a':
			if (optarg[0] < '0' || optarg[0] > '9' || optarg[1]) {
				fprintf(stderr, "error: invalid -a argument\n");
				exit(1);
			}
			access_class = optarg[0] - '0';
			continue;
		case 'm':
			set_msisdn(optarg);
			continue;
		case 'n':
			num_cards = atoi(optarg);
			continue;
		case 'r':
			random_file = optarg;
			continue;
		case '?':
		default:
usage:			fprintf(stderr,
				"usage: %s [options] start-iccid start-imsi\n",
				argv[0]);
			exit(1);
		}
	}
	if (argc - optind != 2)
		goto usage;
	set_iccid(argv[optind]);
	set_imsi(argv[optind+1]);
}

static unsigned
make_odd_parity(byte)
	unsigned byte;
{
	unsigned mask, p;

	p = 0;
	for (mask = 0x80; mask; mask >>= 1)
		if (byte & mask)
			p = !p;
	if (!p)
		byte ^= 0x01;
	return byte;
}

static void
get_random_key(strbuf, oddpar)
	char *strbuf;
{
	u_char bin[16];
	char *dp;
	unsigned n;
	int rc;

	rc = read(random_fd, bin, 16);
	if (rc != 16) {
		fprintf(stderr, "error reading from %s\n", random_file);
		exit(1);
	}
	if (oddpar) {
		for (n = 0; n < 16; n++)
			bin[n] = make_odd_parity(bin[n]);
	}
	dp = strbuf;
	for (n = 0; n < 16; n++) {
		sprintf(dp, "%02X", bin[n]);
		dp += 2;
	}
	*dp = '\0';
}

static void
make_one_card()
{
	unsigned acc_mask;
	char iccid_str[20], imsi_str[16], ki_str[33];
	char msisdn_str[21], otac_str[33], otad_str[33];

	nibbles_to_ascii(iccid_bin, 19, iccid_str);
	nibbles_to_ascii(imsi_bin, 15, imsi_str);
	acc_mask = 1 << access_class;
	get_random_key(ki_str, 0);
	get_random_key(otac_str, 1);
	get_random_key(otad_str, 1);
	printf("ICCID=%s IMSI=%s ACC=%04X Ki=%s OTA_C=%s OTA_D=%s", iccid_str,
		imsi_str, acc_mask, ki_str, otac_str, otad_str);
	if (msisdn_set) {
		fputs(" MSISDN=", stdout);
		if (msisdn_plus)
			putchar('+');
		nibbles_to_ascii(msisdn_bin, msisdn_digits, msisdn_str);
		fputs(msisdn_str, stdout);
	}
	putchar('\n');
}

main(argc, argv)
	char **argv;
{
	unsigned n;

	parse_cmdline(argc, argv);
	random_fd = open(random_file, O_RDONLY);
	if (random_fd < 0) {
		perror(random_file);
		exit(1);
	}
	for (n = 0; n < num_cards; n++) {
		iccid_bin[18] = compute_iccid_luhn(iccid_bin);
		make_one_card();
		decimal_string_increment(iccid_bin, 18);
		decimal_string_increment(imsi_bin, 15);
		if (msisdn_set)
			decimal_string_increment(msisdn_bin, msisdn_digits);
		access_class++;
		if (access_class >= 10)
			access_class = 0;
	}
	exit(0);
}