#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include "internal.h"
#include "log.h"
#include <time.h>
static long t1, t2, tot_read = 0, tot_dur = 0, dur;
#define BELPIC_VERSION "1.4"
#define BELPIC_MAX_FILE_SIZE 65535
#define BELPIC_PIN_BUF_SIZE 8
#define BELPIC_MIN_USER_PIN_LEN 4
#define BELPIC_MAX_USER_PIN_LEN 12
#define BELPIC_PIN_ENCODING SC_PIN_ENCODING_GLP
#define BELPIC_PAD_CHAR 0xFF
#define BELPIC_KEY_REF_NONREP 0x83
#define BELPIC_CARDDATA_OFF_SERIALNUM 0
#define BELPIC_CARDDATA_OFF_COMPCODE 16
#define BELPIC_CARDDATA_OFF_OSNUM 17
#define BELPIC_CARDDATA_OFF_OSVER 18
#define BELPIC_CARDDATA_OFF_SMNUM 19
#define BELPIC_CARDDATA_OFF_SMVER 20
#define BELPIC_CARDDATA_OFF_APPLETVERS 21
#define BELPIC_CARDDATA_OFF_GL_OSVE 22
#define BELPIC_CARDDATA_OFF_APPINTVERS 24
#define BELPIC_CARDDATA_OFF_PKCS1 25
#define BELPIC_CARDDATA_OFF_KEYX 26
#define BELPIC_CARDDATA_OFF_APPLCYCLE 27
#define BELPIC_CARDDATA_RESP_LEN 28
static size_t next_idx = (size_t)-1;
static const struct sc_atr_table belpic_atrs[] = {
{ "3B:98:13:40:0A:A5:03:01:01:01:AD:13:11", NULL, NULL, SC_CARD_TYPE_BELPIC_EID, 0, NULL },
{ "3B:98:94:40:0A:A5:03:01:01:01:AD:13:10", NULL, NULL, SC_CARD_TYPE_BELPIC_EID, 0, NULL },
{ "3B:98:94:40:FF:A5:03:01:01:01:AD:13:10", NULL, NULL, SC_CARD_TYPE_BELPIC_EID, 0, NULL },
{ NULL, NULL, NULL, 0, 0, NULL }
};
static struct sc_card_operations belpic_ops;
static struct sc_card_driver belpic_drv = {
"Belpic cards",
"belpic",
&belpic_ops,
NULL, 0, NULL
};
static const struct sc_card_operations *iso_ops = NULL;
static int get_carddata(sc_card_t *card, u8* carddata_loc, unsigned int carddataloc_len)
{
sc_apdu_t apdu;
u8 carddata_cmd[] = { 0x80, 0xE4, 0x00, 0x00, 0x1C };
int r;
assert(carddataloc_len == BELPIC_CARDDATA_RESP_LEN);
r = sc_bytes2apdu(card->ctx, carddata_cmd, sizeof(carddata_cmd), &apdu);
if(r) {
sc_log(card->ctx, "bytes to APDU conversion failed: %d\n", r);
return r;
}
apdu.resp = carddata_loc;
apdu.resplen = carddataloc_len;
r = sc_transmit_apdu(card, &apdu);
if(r) {
sc_log(card->ctx, "GetCardData command failed: %d\n", r);
return r;
}
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
if(r) {
sc_log(card->ctx, "GetCardData: card returned %d\n", r);
return r;
}
if(apdu.resplen < carddataloc_len) {
sc_log(card->ctx,
"GetCardData: card returned %"SC_FORMAT_LEN_SIZE_T"u bytes rather than expected %d\n",
apdu.resplen, carddataloc_len);
return SC_ERROR_WRONG_LENGTH;
}
return 0;
}
static int belpic_match_card(sc_card_t *card)
{
int i;
i = _sc_match_atr(card, belpic_atrs, &card->type);
if (i < 0)
return 0;
return 1;
}
static int belpic_init(sc_card_t *card)
{
int key_size = 1024;
int r;
sc_log(card->ctx, "Belpic V%s\n", BELPIC_VERSION);
if (card->type < 0)
card->type = SC_CARD_TYPE_BELPIC_EID;
card->cla = 0x00;
if (card->type == SC_CARD_TYPE_BELPIC_EID) {
u8 carddata[BELPIC_CARDDATA_RESP_LEN];
memset(carddata, 0, sizeof(carddata));
if((r = get_carddata(card, carddata, sizeof(carddata))) < 0) {
return SC_ERROR_INVALID_CARD;
}
if (carddata[BELPIC_CARDDATA_OFF_APPLETVERS] >= 0x17) {
key_size = 2048;
}
_sc_card_add_rsa_alg(card, key_size,
SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE, 0);
}
card->caps |= SC_CARD_CAP_RNG;
card->max_pin_len = BELPIC_MAX_USER_PIN_LEN;
return 0;
}
static int belpic_select_file(sc_card_t *card,
const sc_path_t *in_path, sc_file_t **file_out)
{
sc_apdu_t apdu;
u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
int r, pathlen;
sc_file_t *file = NULL;
assert(card != NULL && in_path != NULL);
memcpy(path, in_path->value, in_path->len);
pathlen = in_path->len;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x08, 0x0C);
apdu.lc = pathlen;
apdu.data = path;
apdu.datalen = pathlen;
apdu.resplen = 0;
apdu.le = 0;
r = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(card->ctx, r, "Select File APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (r)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
next_idx = (size_t)-1;
if (file_out != NULL) {
file = sc_file_new();
file->path = *in_path;
if (pathlen >= 2)
file->id = (in_path->value[pathlen - 2] << 8) | in_path->value[pathlen - 1];
file->size = BELPIC_MAX_FILE_SIZE;
file->shareable = 1;
file->ef_structure = SC_FILE_EF_TRANSPARENT;
if (pathlen == 2 && memcmp("\x3F\x00", in_path->value, 2) == 0)
file->type = SC_FILE_TYPE_DF;
else
file->type = SC_FILE_TYPE_WORKING_EF;
*file_out = file;
}
return 0;
}
static int belpic_read_binary(sc_card_t *card,
unsigned int idx, u8 * buf, size_t count, unsigned long flags)
{
int r;
if (next_idx == idx)
return 0;
t1 = clock();
r = iso_ops->read_binary(card, idx, buf, count, flags);
t2 = clock();
if (r == SC_ERROR_INCORRECT_PARAMETERS)
return 0;
if (r >= 0 && (size_t)r < count)
next_idx = idx + (size_t)r;
dur = t2 - t1;
tot_dur += dur;
tot_read += r;
return r;
}
static int belpic_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left)
{
data->pin1.encoding = data->pin2.encoding = BELPIC_PIN_ENCODING;
data->pin1.pad_char = data->pin2.pad_char = BELPIC_PAD_CHAR;
data->pin1.min_length = data->pin2.min_length = BELPIC_MIN_USER_PIN_LEN;
data->pin1.max_length = data->pin2.max_length = BELPIC_MAX_USER_PIN_LEN;
data->apdu = NULL;
return iso_ops->pin_cmd(card, data, tries_left);
}
static int belpic_set_security_env(sc_card_t *card,
const sc_security_env_t *env, int se_num)
{
sc_apdu_t apdu;
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
int r;
sc_log(card->ctx, "belpic_set_security_env(), keyRef = 0x%0x, algo = 0x%0x\n",
*env->key_ref, env->algorithm_flags);
assert(card != NULL && env != NULL);
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0);
switch (env->operation) {
case SC_SEC_OPERATION_SIGN:
apdu.p1 = 0x41;
apdu.p2 = 0xB6;
sbuf[0] = 0x04;
sbuf[1] = 0x80;
if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1)
sbuf[2] = 0x01;
else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
sbuf[2] = 0x02;
else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_MD5)
sbuf[2] = 0x04;
else {
sc_log(card->ctx, "Set Sec Env: unsupported algo 0X%0X\n",
env->algorithm_flags);
return SC_ERROR_INVALID_ARGUMENTS;
}
sbuf[3] = 0x84;
sbuf[4] = *env->key_ref;
apdu.lc = 5;
apdu.datalen = 5;
break;
default:
return SC_ERROR_INVALID_ARGUMENTS;
}
apdu.le = 0;
apdu.data = sbuf;
apdu.resplen = 0;
r = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(card->ctx, r, "Set Security Env APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_TEST_RET(card->ctx, r, "Card's Set Security Env command returned error");
if (*env->key_ref == BELPIC_KEY_REF_NONREP) {
sc_log(card->ctx, "No GUI for NonRep key present, signature cancelled\n");
return SC_ERROR_NOT_SUPPORTED;
}
return r;
}
static struct sc_card_driver *sc_get_driver(void)
{
if (iso_ops == NULL)
iso_ops = sc_get_iso7816_driver()->ops;
belpic_ops.match_card = belpic_match_card;
belpic_ops.init = belpic_init;
belpic_ops.update_binary = iso_ops->update_binary;
belpic_ops.select_file = belpic_select_file;
belpic_ops.read_binary = belpic_read_binary;
belpic_ops.pin_cmd = belpic_pin_cmd;
belpic_ops.set_security_env = belpic_set_security_env;
belpic_ops.compute_signature = iso_ops->compute_signature;
belpic_ops.get_challenge = iso_ops->get_challenge;
belpic_ops.get_response = iso_ops->get_response;
belpic_ops.check_sw = iso_ops->check_sw;
return &belpic_drv;
}
#if 1
struct sc_card_driver *sc_get_belpic_driver(void)
{
return sc_get_driver();
}
#endif