C-Netz SIM: Improve and use PIN input to program card

Imrovements are less memeory usage.

Card data can be programmed by using PIN input.
This commit is contained in:
Andreas Eversberg
2024-08-15 21:56:49 +02:00
parent c67dcc8170
commit 9d8c9d8986
5 changed files with 178 additions and 89 deletions

View File

@@ -49,10 +49,10 @@ static int baudrate = 9600;
static const char *eeprom_name = NULL;
static const char *futln = NULL;
static const char *sicherung = NULL;
static const char *karten = NULL;
static const char *sonder = NULL;
static const char *wartung = NULL;
static int sicherung = -1;
static int karten = -1;
static int sonder = -1;
static int wartung = -1;
static const char *pin = NULL;
#define MAX_DIR_COUNT 64
static int dir_count = 0;
@@ -89,13 +89,13 @@ static void print_help(const char *arg0)
printf(" -F --futln <phone number>\n");
printf(" Give 7 digits subscriber ID (default = '%s')\n", FUTLN_DEFAULT);
printf(" --sicherung <security code>\n");
printf(" Card's security code for simple authentication (default = '%s')\n", SICHERUNG_DEFAULT);
printf(" Card's security code for simple authentication (default = '%d')\n", SICHERUNG_DEFAULT);
printf(" --kartenkennung <card ID>\n");
printf(" Card's ID. Not relevant! (default = '%s')\n", KARTEN_DEFAULT);
printf(" Card's ID. Not relevant! (default = '%d')\n", KARTEN_DEFAULT);
printf(" --sonder <special code>\n");
printf(" Special codes are used for service cards (default = '%s')\n", SONDER_DEFAULT);
printf(" Special codes are used for service cards (default = '%d')\n", SONDER_DEFAULT);
printf(" --wartung <maitenance code>\n");
printf(" May define features of service cards (default = '%s')\n", WARTUNG_DEFAULT);
printf(" May define features of service cards (default = '%d')\n", WARTUNG_DEFAULT);
printf(" -P --pin <pin> | 0000\n");
printf(" Give 4 .. 8 digits of pin. Use '0000' to disable. (default = '%s')\n", PIN_DEFAULT);
printf(" This will also reset the PIN error counter and unlocks the card.\n");
@@ -165,16 +165,16 @@ static int handle_options(int short_option, int argi, char **argv)
futln = options_strdup(argv[argi]);
break;
case OPT_SICHERUNG:
sicherung = options_strdup(argv[argi]);
sicherung = atoi(argv[argi]);
break;
case OPT_KARTEN:
karten = options_strdup(argv[argi]);
karten = atoi(argv[argi]);
break;
case OPT_SONDER:
sonder = options_strdup(argv[argi]);
sonder = atoi(argv[argi]);
break;
case OPT_WARTUNG:
wartung = options_strdup(argv[argi]);
wartung = atoi(argv[argi]);
break;
case 'P':
pin = options_strdup(argv[argi]);

View File

@@ -103,7 +103,7 @@ static void write_flags(sim_sim_t *sim)
}
/* encode EBDT from strings */
int encode_ebdt(uint8_t *data, const char *futln, const char *sicherung, const char *karten, const char *sonder, const char *wartung)
int encode_ebdt(uint8_t *data, const char *futln, int32_t sicherung, int32_t karten, int32_t sonder, int32_t wartung)
{
uint32_t temp;
int i;
@@ -144,46 +144,46 @@ int encode_ebdt(uint8_t *data, const char *futln, const char *sicherung, const c
}
temp = my_strtoul(futln, NULL, 10);
if (i < 5 || temp > 65535) {
LOGP(DSIM7, LOGL_NOTICE, "Given FUTLN '%s' has invalid last digits. (Must be '00000' .. '65535')\n", futln);
LOGP(DSIM7, LOGL_NOTICE, "Given FUTLN '%d' has invalid last digits. (Must be '00000' .. '65535')\n", temp);
return -EINVAL;
}
data[1] = temp >> 8;
data[2] = temp;
}
if (sicherung) {
temp = my_strtoul(sicherung, NULL, 10);
if (sicherung >= 0) {
temp = sicherung;
if (temp > 65535) {
LOGP(DSIM7, LOGL_NOTICE, "Given security code '%s' has invalid digits. (Must be '0' .. '65535')\n", sicherung);
LOGP(DSIM7, LOGL_NOTICE, "Given security code '%d' has invalid digits. (Must be '0' .. '65535')\n", temp);
return -EINVAL;
}
data[3] = temp >> 8;
data[4] = temp;
}
if (karten) {
temp = my_strtoul(karten, NULL, 10);
if (karten >= 0) {
temp = karten;
if (temp > 7) {
LOGP(DSIM7, LOGL_NOTICE, "Given card number '%s' has invalid digit. (Must be '0' .. '7')\n", karten);
LOGP(DSIM7, LOGL_NOTICE, "Given card number '%d' has invalid digit. (Must be '0' .. '7')\n", temp);
return -EINVAL;
}
data[5] = (data[5] & 0x1f) | ((karten[0] - '0') << 5);
data[5] = (data[5] & 0x1f) | (temp << 5);
}
if (sonder) {
temp = my_strtoul(sonder, NULL, 10);
if (sonder >= 0) {
temp = sonder;
if (temp > 8191) {
LOGP(DSIM7, LOGL_NOTICE, "Given spacial code '%s' has invalid digits. (Must be '0' .. '8191')\n", sonder);
LOGP(DSIM7, LOGL_NOTICE, "Given spacial code '%d' has invalid digits. (Must be '0' .. '8191')\n", temp);
return -EINVAL;
}
data[5] = (data[5] & 0xe0) | (temp >> 8);
data[6] = temp;
}
if (wartung) {
temp = my_strtoul(wartung, NULL, 10);
if (wartung >= 0) {
temp = wartung;
if (temp > 65535) {
LOGP(DSIM7, LOGL_NOTICE, "Given maintenance code '%s' has invalid digits. (Must be '0' .. '65535')\n", wartung);
LOGP(DSIM7, LOGL_NOTICE, "Given maintenance code '%d' has invalid digits. (Must be '0' .. '65535')\n", temp);
return -EINVAL;
}
data[7] = temp >> 8;
@@ -358,27 +358,76 @@ static uint8_t get_aprc(sim_sim_t *sim)
/* validate PIN and change states */
static int validate_pin(sim_sim_t *sim, uint8_t *data, int length)
{
uint8_t valid = 0, program_mode = 0;
int i;
uint8_t valid = 0;
int i, rc;
if (!sim->pin_required)
return 0;
/* in PIN programming mode retrieve data from pin input */
if (sim->sim_mode == SIM_MODE_PIN) {
if (sim->pin_program_index == 0) {
memcpy(sim->pin_program_futln, data, length);
sim->pin_program_futln[length] = '\0';
} else {
uint8_t value_str[9];
memcpy(value_str, data, length);
value_str[length] = '\0';
sim->pin_program_values[sim->pin_program_index - 1] = my_strtoul((char *)value_str, NULL, 10);
}
sim->pin_program_index++;
valid = 1;
uint8_t ebdt_data[9];
rc = encode_ebdt(ebdt_data,
sim->pin_program_futln,
(sim->pin_program_index > 1) ? sim->pin_program_values[0] : -1,
(sim->pin_program_index > 2) ? sim->pin_program_values[1] : -1,
(sim->pin_program_index > 3) ? sim->pin_program_values[2] : -1,
(sim->pin_program_index > 4) ? sim->pin_program_values[3] : -1);
if (rc < 0) {
LOGP(DSIM1, LOGL_INFO, "Invalid data has been entered, using special FUTLN to indicate error.\n");
sim->sim_mode = SIM_MODE_ERROR;
} else if (sim->pin_program_index == 5) {
LOGP(DSIM1, LOGL_INFO, "Entering card #%d via PIN input is complete valid.\n", sim->card + 1);
sim->sim_mode = SIM_MODE_NONE;
eeprom_write(EEPROM_FUTLN_H + sim->card, ebdt_data[0]);
eeprom_write(EEPROM_FUTLN_M + sim->card, ebdt_data[1]);
eeprom_write(EEPROM_FUTLN_L + sim->card, ebdt_data[2]);
eeprom_write(EEPROM_SICH_H + sim->card, ebdt_data[3]);
eeprom_write(EEPROM_SICH_L + sim->card, ebdt_data[4]);
eeprom_write(EEPROM_SONDER_H + sim->card, ebdt_data[5]);
eeprom_write(EEPROM_SONDER_L + sim->card, ebdt_data[6]);
eeprom_write(EEPROM_WARTUNG_H + sim->card, ebdt_data[7]);
eeprom_write(EEPROM_WARTUNG_L + sim->card, ebdt_data[8]);
}
}
/* no PIN mode */
if (length == 4 && data[0] == '0' && data[1] == '0' && data[2] == '0' && data[3] >= '0' && data[3] <= '0' + MAX_CARDS) {
if (!valid && length == 4 && data[0] == '0' && data[1] == '0' && data[2] == '0' && data[3] >= '0' && data[3] <= '0' + MAX_CARDS) {
sim->sim_mode = SIM_MODE_NONE;
valid = 1;
if (data[3] > '0')
sim->card = data[3] - '1';
LOGP(DSIM1, LOGL_INFO, "System PIN '000%c' entered. Selecting card #%d.\n", data[3], sim->card + 1);
}
/* programming mode */
if (length == 4 && data[0] == '9' && data[1] == '9' && data[2] == '9' && data[3] >= '0' && data[3] <= '0' + MAX_CARDS) {
program_mode = 1;
/* phonebook programming mode (use phonebook to program card) */
if (!valid && length == 4 && data[0] == '9' && data[1] == '9' && data[2] == '9' && data[3] >= '0' && data[3] <= '0' + MAX_CARDS) {
sim->sim_mode = SIM_MODE_PHONEBOOK;
valid = 1;
if (data[3] > '0')
sim->card = data[3] - '1';
LOGP(DSIM1, LOGL_INFO, "Configuration PIN '999%c' entered. Selecting card #%d in configuration mode.\n", data[3], sim->card + 1);
LOGP(DSIM1, LOGL_INFO, "Configuration PIN '999%c' entered. Selecting card #%d in phonebook programming mode.\n", data[3], sim->card + 1);
}
/* PIN programming mode (use pin entering to program card) */
if (!valid && length == 4 && data[0] == '8' && data[1] == '8' && data[2] == '8' && data[3] >= '0' && data[3] <= '0' + MAX_CARDS) {
sim->sim_mode = SIM_MODE_PIN;
sim->pin_program_index = 0;
valid = 1;
if (data[3] > '0')
sim->card = data[3] - '1';
LOGP(DSIM1, LOGL_INFO, "Configuration PIN '888%c' entered. Selecting card #%d in PIN programming mode.\n", data[3], sim->card + 1);
}
/* if not 'program mode' and PIN matches EEPROM */
@@ -399,10 +448,10 @@ static int validate_pin(sim_sim_t *sim, uint8_t *data, int length)
sim->pin_try = MAX_PIN_TRY;
write_flags(sim);
}
sim->pin_required = 0;
if (program_mode)
sim->program_mode = 1;
return 0;
/* PIN is required in PIN programming mode */
sim->pin_required = (sim->sim_mode == SIM_MODE_PIN) ? 1 : 0;
/* Indicate 'invalid PIN' in PIN programming mode, so phone can provide next PIN */
return (sim->sim_mode == SIM_MODE_PIN) ? -EINVAL : 0;
} else {
LOGP(DSIM1, LOGL_INFO, "Wrong PIN was entered.\n");
#ifndef ARDUINO
@@ -561,8 +610,9 @@ static void rd_ebdt(sim_sim_t *sim)
/* respond */
data = alloc_msg(sim, 9);
if (sim->program_mode) {
/* SERVICE MODE */
switch (sim->sim_mode) {
case SIM_MODE_PHONEBOOK:
/* phonebook programming mode */
data[0] = 0;
data[1] = 0;
data[2] = sim->card + 1;
@@ -572,7 +622,13 @@ static void rd_ebdt(sim_sim_t *sim)
data[6] = 0;
data[7] = 0x0ff;
data[8] = 0x0ff;
} else {
break;
case SIM_MODE_ERROR:
/* display error mode */
encode_ebdt(data, "3333333", SICHERUNG_DEFAULT, KARTEN_DEFAULT, SONDER_DEFAULT, WARTUNG_DEFAULT);
break;
default:
/* emulation mode */
data[0] = eeprom_read(EEPROM_FUTLN_H + sim->card);
data[1] = eeprom_read(EEPROM_FUTLN_M + sim->card);
data[2] = eeprom_read(EEPROM_FUTLN_L + sim->card);
@@ -600,14 +656,14 @@ static void rd_rufn(sim_sim_t *sim, uint8_t *data, int length)
LOGP(DSIM7, LOGL_INFO, " RD-RUFN (loc=%d)\n", rufn);
/* SERVICE MODE */
if (sim->program_mode) {
/* PROGRAMMING MODE */
if (sim->sim_mode == SIM_MODE_PHONEBOOK) {
char number[16];
/* respond */
data = alloc_msg(sim, 24);
switch (rufn) {
case 0: /* send bitmap for service mode */
case 0: /* send bitmap for programming mode */
memset(data, 0xff, 24);
data[0] = 6; /* 6 entries */
data[1] = 0x03; /* upper 6 bits = 0 */
@@ -618,38 +674,38 @@ static void rd_rufn(sim_sim_t *sim, uint8_t *data, int length)
data[2] = eeprom_read(EEPROM_FUTLN_L + sim->card);
decode_ebdt(data, number, NULL, NULL, NULL, NULL);
encode_directory(data, number, "FUTLN");
LOGP(DSIM7, LOGL_INFO, "service mode: FUTLN = %s\n", number);
LOGP(DSIM7, LOGL_INFO, "programming mode: FUTLN = %s\n", number);
break;
case 2: /* security code */
data[3] = eeprom_read(EEPROM_SICH_H + sim->card);
data[4] = eeprom_read(EEPROM_SICH_L + sim->card);
decode_ebdt(data, NULL, number, NULL, NULL, NULL);
encode_directory(data, number, "Sicherungscode");
LOGP(DSIM7, LOGL_INFO, "service mode: security = %s\n", number);
LOGP(DSIM7, LOGL_INFO, "programming mode: security = %s\n", number);
break;
case 3: /* card ID */
data[5] = eeprom_read(EEPROM_SONDER_H + sim->card);
decode_ebdt(data, NULL, NULL, number, NULL, NULL);
encode_directory(data, number, "Kartenkennung");
LOGP(DSIM7, LOGL_INFO, "service mode: card = %s\n", number);
LOGP(DSIM7, LOGL_INFO, "programming mode: card = %s\n", number);
break;
case 4: /* special key */
data[5] = eeprom_read(EEPROM_SONDER_H + sim->card);
data[6] = eeprom_read(EEPROM_SONDER_L + sim->card);
decode_ebdt(data, NULL, NULL, NULL, number, NULL);
encode_directory(data, number, "Sonderheitsschl.");
LOGP(DSIM7, LOGL_INFO, "service mode: special = %s\n", number);
LOGP(DSIM7, LOGL_INFO, "programming mode: special = %s\n", number);
break;
case 5: /* maintenance key */
data[7] = eeprom_read(EEPROM_WARTUNG_H + sim->card);
data[8] = eeprom_read(EEPROM_WARTUNG_L + sim->card);
decode_ebdt(data, NULL, NULL, NULL, NULL, number);
encode_directory(data, number, "Wartungsschl.");
LOGP(DSIM7, LOGL_INFO, "service mode: maintenance = %s\n", number);
LOGP(DSIM7, LOGL_INFO, "programming mode: maintenance = %s\n", number);
break;
case 6: /* sim version */
encode_directory(data, SIM_VERSION, SIM_VERSION_NAME);
LOGP(DSIM7, LOGL_INFO, "service mode: display SIM version = %s\n", SIM_VERSION);
LOGP(DSIM7, LOGL_INFO, "programming mode: display SIM version = %s\n", SIM_VERSION);
break;
}
tx_sdu(sim, 0, data, 24);
@@ -684,10 +740,11 @@ static void wt_rufn(sim_sim_t *sim, uint8_t *data, int length)
LOGP(DSIM7, LOGL_INFO, " WT-RUFN (loc=%d)\n", rufn);
/* SERVICE MODE */
if (sim->program_mode) {
/* PROGRAMMING MODE */
if (sim->sim_mode == SIM_MODE_PHONEBOOK) {
int rc;
char number[17];
int value;
decode_directory(data + 1, number, NULL);
/* if number is cleared (no digits), we ignore that */
@@ -695,8 +752,8 @@ static void wt_rufn(sim_sim_t *sim, uint8_t *data, int length)
goto respond;
switch (rufn) {
case 1: /* FUTLN */
LOGP(DSIM7, LOGL_INFO, "service mode: FUTLN = %s\n", number);
rc = encode_ebdt(data, number, NULL, NULL, NULL, NULL);
LOGP(DSIM7, LOGL_INFO, "programming mode: FUTLN = %s\n", number);
rc = encode_ebdt(data, number, -1, -1, -1, -1);
if (rc < 0)
break;
eeprom_write(EEPROM_FUTLN_H + sim->card, data[0]);
@@ -704,33 +761,37 @@ static void wt_rufn(sim_sim_t *sim, uint8_t *data, int length)
eeprom_write(EEPROM_FUTLN_L + sim->card, data[2]);
break;
case 2: /* security code */
LOGP(DSIM7, LOGL_INFO, "service mode: security = %s\n", number);
rc = encode_ebdt(data, NULL, number, NULL, NULL, NULL);
LOGP(DSIM7, LOGL_INFO, "programming mode: security = %s\n", number);
value = my_strtoul(number, NULL, 10);
rc = encode_ebdt(data, NULL, value, -1, -1, -1);
if (rc < 0)
break;
eeprom_write(EEPROM_SICH_H + sim->card, data[3]);
eeprom_write(EEPROM_SICH_L + sim->card, data[4]);
break;
case 3: /* card ID */
LOGP(DSIM7, LOGL_INFO, "service mode: card = %s\n", number);
LOGP(DSIM7, LOGL_INFO, "programming mode: card = %s\n", number);
data[5] = eeprom_read(EEPROM_SONDER_H + sim->card);
rc = encode_ebdt(data, NULL, NULL, number, NULL, NULL);
value = my_strtoul(number, NULL, 10);
rc = encode_ebdt(data, NULL, -1, value, -1, -1);
if (rc < 0)
break;
eeprom_write(EEPROM_SONDER_H + sim->card, data[5]);
break;
case 4: /* special key */
LOGP(DSIM7, LOGL_INFO, "service mode: special = %s\n", number);
LOGP(DSIM7, LOGL_INFO, "programming mode: special = %s\n", number);
data[5] = eeprom_read(EEPROM_SONDER_H + sim->card);
rc = encode_ebdt(data, NULL, NULL, NULL, number, NULL);
value = my_strtoul(number, NULL, 10);
rc = encode_ebdt(data, NULL, -1, -1, value, -1);
if (rc < 0)
break;
eeprom_write(EEPROM_SONDER_H + sim->card, data[5]);
eeprom_write(EEPROM_SONDER_L + sim->card, data[6]);
break;
case 5: /* maintenance key */
LOGP(DSIM7, LOGL_INFO, "service mode: maintenance = %s\n", number);
rc = encode_ebdt(data, NULL, NULL, NULL, NULL, number);
LOGP(DSIM7, LOGL_INFO, "programming mode: maintenance = %s\n", number);
value = my_strtoul(number, NULL, 10);
rc = encode_ebdt(data, NULL, -1, -1, -1, value);
if (rc < 0)
break;
eeprom_write(EEPROM_WARTUNG_H + sim->card, data[7]);

View File

@@ -1,13 +1,13 @@
#define SIM_VERSION_NAME "TelecardVersion"
#define SIM_VERSION "3"
#define JOLLY_NAME "Jolly"
#define SIM_VERSION "4"
#define JOLLY_NAME "Jolly Zuhause"
#define JOLLY_PHONE "04644973171"
#define FUTLN_DEFAULT "2222001"
#define SICHERUNG_DEFAULT "3103"
#define KARTEN_DEFAULT "3"
#define SONDER_DEFAULT "0"
#define WARTUNG_DEFAULT "65535"
#define SICHERUNG_DEFAULT 3103
#define KARTEN_DEFAULT 3
#define SONDER_DEFAULT 0
#define WARTUNG_DEFAULT 65535
#define PIN_DEFAULT "0000"
#define AUTH_DEFAULT ((uint64_t)0x000000000badefee)
@@ -28,6 +28,13 @@ enum block_state {
BLOCK_STATE_DATA,
};
enum sim_mode {
SIM_MODE_NONE = 0, /* SIM from EEPROM */
SIM_MODE_PHONEBOOK, /* SIM that contains the phonebook */
SIM_MODE_PIN, /* entering SIM via PIN */
SIM_MODE_ERROR, /* SIM via PIN failed */
};
#define MAX_PIN_TRY 3
#define MAX_CARDS 8 /* must also be defined at eeprom.h */
@@ -53,25 +60,28 @@ typedef struct sim_sim {
int resync_sent;
/* ICL layer states */
int icl_online;
int icl_master;
int icl_chaining;
int icl_error;
uint8_t icl_online;
uint8_t icl_master;
uint8_t icl_chaining;
uint8_t icl_error;
/* layer 7 states */
int addr_src;
int addr_dst;
int sh_appl_count; /* counts applications for SH_APPL */
uint8_t addr_src;
uint8_t addr_dst;
uint8_t sh_appl_count; /* counts applications for SH_APPL */
/* CNETZ states */
int pin_required; /* pin required an not yet validated */
int program_mode; /* program mode active (special PIN entered) */
int pin_len; /* length of pin (4 .. 8) */
int pin_try; /* number of tries left (0 == card locked) */
int app; /* currently selected APP number */
int app_locked; /* application locked */
int gebz_locked; /* metering counter and phonebook locked */
int gebz_full; /* metering counter full (does this really happen?) */
uint8_t pin_required; /* pin required an not yet validated */
enum sim_mode sim_mode; /* sim mode active (programming mode) */
char pin_program_futln[9]; /* PIN program mode: FUTLN string with maximum of 8 characters */
int32_t pin_program_values[4]; /* PIN program mode: other 4 values */
uint8_t pin_program_index; /* PIN program mode: strin to be entered */
uint8_t pin_len; /* length of pin (4 .. 8) */
uint8_t pin_try; /* number of tries left (0 == card locked) */
uint8_t app; /* currently selected APP number */
uint8_t app_locked; /* application locked */
uint8_t gebz_locked; /* metering counter and phonebook locked */
uint8_t gebz_full; /* metering counter full (does this really happen?) */
} sim_sim_t;
/* layer 2 */
@@ -142,7 +152,7 @@ enum l2_cmd {
/* defined for main.c */
size_t eeprom_length(void);
int encode_ebdt(uint8_t *data, const char *futln, const char *sicherung, const char *karten, const char *sonder, const char *wartung);
int encode_ebdt(uint8_t *data, const char *futln, int32_t sicherung, int32_t karten, int32_t sonder, int32_t wartung);
void decode_ebdt(uint8_t *data, char *futln, char *sicherung, char *karten, char *sonder, char *wartung);
int directory_size(void);
int save_directory(int location, uint8_t *data);

View File

@@ -1,4 +1,4 @@
/* SIM card for ATMEL
/* C-Netz SIM card emulator for ATMEL
*
* (C) 2020 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved