iasecc: SM add related procedures

This commit is contained in:
Viktor Tarasov 2012-06-04 11:18:23 +02:00
parent cfd5aaba7d
commit ea5a19e27e
7 changed files with 1314 additions and 294 deletions

View File

@ -37,7 +37,7 @@ libopensc_la_SOURCES = \
card-asepcos.c card-akis.c card-gemsafeV1.c card-rutoken.c \
card-rtecp.c card-westcos.c card-myeid.c card-ias.c \
card-javacard.c card-itacns.c card-authentic.c \
card-iasecc.c iasecc-sdo.c \
card-iasecc.c iasecc-sdo.c iasecc-sm.c \
\
pkcs15-openpgp.c pkcs15-infocamere.c pkcs15-starcert.c \
pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafeGPK.c \

View File

@ -21,7 +21,7 @@ OBJECTS = \
card-asepcos.obj card-akis.obj card-gemsafeV1.obj card-rutoken.obj \
card-rtecp.obj card-westcos.obj card-myeid.obj card-ias.obj \
card-javacard.obj card-itacns.obj card-authentic.obj \
card-iasecc.obj iasecc-sdo.obj \
card-iasecc.obj iasecc-sdo.obj iasecc-sm.obj \
\
pkcs15-openpgp.obj pkcs15-infocamere.obj pkcs15-starcert.obj \
pkcs15-tcos.obj pkcs15-esteid.obj pkcs15-postecert.obj pkcs15-gemsafeGPK.obj \

View File

@ -48,8 +48,6 @@
#include "iasecc.h"
#define ALLOW_IGNORE_EXTERNAL_AUTHENTICATION
#define IASECC_CARD_DEFAULT_FLAGS ( 0 \
| SC_ALGORITHM_ONBOARD_KEY_GEN \
| SC_ALGORITHM_RSA_PAD_ISO9796 \
@ -81,6 +79,12 @@ static struct sc_atr_table iasecc_known_atrs[] = {
"IAS/ECC v1.0.1 Sagem MDW-IAS-CARD2", SC_CARD_TYPE_IASECC_SAGEM, 0, NULL },
{ "3B:7F:18:00:00:00:31:B8:64:50:23:EC:C1:73:94:01:80:82:90:00", NULL,
"IAS/ECC v1.0.1 Sagem ypsID S3", SC_CARD_TYPE_IASECC_SAGEM, 0, NULL },
{ "3B:DF:18:FF:81:91:FE:1F:C3:00:31:B8:64:0C:01:EC:C1:73:94:01:80:82:90:00:B3", NULL,
"IAS/ECC v1.0.1 Amos", SC_CARD_TYPE_IASECC_AMOS, 0, NULL },
{ "3B:DC:18:FF:81:91:FE:1F:C3:80:73:C8:21:13:66:02:04:03:55:00:02:34", NULL,
"IAS/ECC v1.0.1 Amos", SC_CARD_TYPE_IASECC_AMOS, 0, NULL },
{ "3B:DC:18:FF:81:91:FE:1F:C3:80:73:C8:21:13:66:01:0B:03:52:00:05:38", NULL,
"IAS/ECC v1.0.1 Amos", SC_CARD_TYPE_IASECC_AMOS, 0, NULL },
{ NULL, NULL, NULL, 0, 0, NULL }
};
@ -113,6 +117,8 @@ static int iasecc_pin_is_verified(struct sc_card *card, struct sc_pin_cmd_data *
static int iasecc_get_free_reference(struct sc_card *card, struct iasecc_ctl_get_free_reference *ctl_data);
static int iasecc_sdo_put_data(struct sc_card *card, struct iasecc_sdo_update *update);
static int _iasecc_sm_read_binary(struct sc_card *card, unsigned int offs, unsigned char *buf, size_t count);
static int _iasecc_sm_update_binary(struct sc_card *card, unsigned int offs, const unsigned char *buff, size_t count);
static int
iasecc_chv_cache_verified(struct sc_card *card, struct sc_pin_cmd_data *pin_cmd)
@ -225,6 +231,7 @@ static int
iasecc_select_mf(struct sc_card *card, struct sc_file **file_out)
{
struct sc_context *ctx = card->ctx;
struct sc_file *mf_file = NULL;
struct sc_path path;
int rv;
@ -235,28 +242,59 @@ iasecc_select_mf(struct sc_card *card, struct sc_file **file_out)
memset(&path, 0, sizeof(struct sc_path));
if (!card->ef_atr || !card->ef_atr->aid.len) {
struct sc_apdu apdu;
unsigned char apdu_resp[SC_MAX_APDU_BUFFER_SIZE];
/* ISO 'select' command failes when not FCP data returned */
sc_format_path("3F00", &path);
path.type = SC_PATH_TYPE_FILE_ID;
rv = iso_ops->select_file(card, &path, file_out);
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x00, 0x00);
apdu.lc = path.len;
apdu.data = path.value;
apdu.datalen = path.len;
apdu.resplen = sizeof(apdu_resp);
apdu.resp = apdu_resp;
rv = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_TEST_RET(card->ctx, rv, "Cannot select MF");
}
else {
memset(&path, 0, sizeof(path));
path.type = SC_PATH_TYPE_DF_NAME;
memcpy(path.value, card->ef_atr->aid.value, card->ef_atr->aid.len);
path.len = card->ef_atr->aid.len;
rv = iasecc_select_file(card, &path, file_out);
LOG_TEST_RET(ctx, rv, "Unable to ROOT selection");
}
/* When selecting Root DF Oberthur's IAS/ECC card do not returns FCI data */
if (file_out && *file_out == NULL) {
struct sc_file *mf_file = sc_file_new();
/* Ignore the FCP of the MF, because:
* - some cards do not return it;
* - there is not need of it -- create/delete of the files in MF is not invisaged.
*/
mf_file = sc_file_new();
if (mf_file == NULL)
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate MF file");
mf_file->type = SC_FILE_TYPE_DF;
mf_file->path = path;
if (card->cache.valid && card->cache.current_df)
sc_file_free(card->cache.current_df);
card->cache.current_df = NULL;
if (card->cache.valid && card->cache.current_ef)
sc_file_free(card->cache.current_ef);
card->cache.current_ef = NULL;
sc_file_dup(&card->cache.current_df, mf_file);
card->cache.valid = 1;
if (file_out && *file_out == NULL)
*file_out = mf_file;
}
}
else
sc_file_free(mf_file);
LOG_FUNC_RETURN(ctx, rv);
}
@ -489,35 +527,54 @@ iasecc_init_sagem(struct sc_card *card)
rv = iasecc_parse_ef_atr(card);
}
LOG_TEST_RET(ctx, rv, "ECC: ATR parse failed");
LOG_TEST_RET(ctx, rv, "IASECC: ATR parse failed");
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
static int
iasecc_init_amos(struct sc_card *card)
{
struct sc_context *ctx = card->ctx;
unsigned int flags;
int rv = 0;
LOG_FUNC_CALLED(ctx);
flags = IASECC_CARD_DEFAULT_FLAGS;
_sc_card_add_rsa_alg(card, 1024, flags, 0x10001);
_sc_card_add_rsa_alg(card, 2048, flags, 0x10001);
card->caps = SC_CARD_CAP_RNG;
card->caps |= SC_CARD_CAP_APDU_EXT;
card->caps |= SC_CARD_CAP_USE_FCI_AC;
rv = iasecc_parse_ef_atr(card);
if (rv == SC_ERROR_FILE_NOT_FOUND) {
rv = iasecc_select_mf(card, NULL);
LOG_TEST_RET(ctx, rv, "MF selection error");
rv = iasecc_parse_ef_atr(card);
}
LOG_TEST_RET(ctx, rv, "IASECC: ATR parse failed");
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
static int
iasecc_init(struct sc_card *card)
{
struct sc_context *ctx = card->ctx;
struct iasecc_private_data *private_data = NULL;
int ii, rv = SC_ERROR_NO_CARD_SUPPORT;
int rv = SC_ERROR_NO_CARD_SUPPORT;
LOG_FUNC_CALLED(ctx);
private_data = (struct iasecc_private_data *) calloc(1, sizeof(struct iasecc_private_data));
if (private_data == NULL)
LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
for(ii=0;iasecc_known_atrs[ii].atr;ii++) {
if (card->type == iasecc_known_atrs[ii].type) {
card->name = iasecc_known_atrs[ii].name;
card->flags = iasecc_known_atrs[ii].flags;
break;
}
}
if (!iasecc_known_atrs[ii].atr)
LOG_FUNC_RETURN(ctx, SC_ERROR_NO_CARD_SUPPORT);
card->cla = 0x00;
card->drv_data = private_data;
@ -527,6 +584,11 @@ iasecc_init(struct sc_card *card)
rv = iasecc_init_oberthur(card);
else if (card->type == SC_CARD_TYPE_IASECC_SAGEM)
rv = iasecc_init_sagem(card);
else if (card->type == SC_CARD_TYPE_IASECC_AMOS)
rv = iasecc_init_amos(card);
else
LOG_FUNC_RETURN(ctx, SC_ERROR_NO_CARD_SUPPORT);
if (!rv) {
if (card->ef_atr && card->ef_atr->aid.len) {
@ -545,6 +607,12 @@ iasecc_init(struct sc_card *card)
rv = iasecc_get_serialnr(card, NULL);
}
#ifdef ENABLE_SM
card->sm_ctx.ops.read_binary = _iasecc_sm_read_binary;
card->sm_ctx.ops.update_binary = _iasecc_sm_update_binary;
#endif
if (!rv)
sc_log(ctx, "EF.ATR(aid:'%s')", sc_dump_hex(card->ef_atr->aid.value, card->ef_atr->aid.len));
LOG_FUNC_RETURN(ctx, rv);
}
@ -574,10 +642,6 @@ iasecc_read_binary(struct sc_card *card, unsigned int offs,
LOG_TEST_RET(ctx, rv, "APDU transmit failed");
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_TEST_RET(ctx, rv, "iasecc_read_binary() failed");
/*
if (apdu.resplen == 0)
SC_FUNC_RETURN(ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
*/
sc_log(ctx, "iasecc_read_binary() apdu.resplen %i", apdu.resplen);
if (apdu.resplen == IASECC_READ_BINARY_LENGTH_MAX && apdu.resplen < count) {
@ -596,41 +660,92 @@ static int
iasecc_erase_binary(struct sc_card *card, unsigned int offs, size_t count, unsigned long flags)
{
struct sc_context *ctx = card->ctx;
const struct sc_acl_entry *entry = NULL;
unsigned char buf_zero[0x400];
size_t sz;
unsigned char *tmp = NULL;
int rv;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "iasecc_erase_binary(card:%p) count %i", card, count);
if (!count)
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "'ERASE BINARY' with ZERO count not supported");
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "'ERASE BINARY' failed: invalid size to erase");
tmp = malloc(count);
if (!tmp)
LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate temporary buffer");
memset(tmp, 0xFF, count);
rv = sc_update_binary(card, offs, tmp, count, flags);
free(tmp);
LOG_TEST_RET(ctx, rv, "iasecc_erase_binary() update binary error");
LOG_FUNC_RETURN(ctx, rv);
}
static int
_iasecc_sm_read_binary(struct sc_card *card, unsigned int offs,
unsigned char *buff, size_t count)
{
struct sc_context *ctx = card->ctx;
const struct sc_acl_entry *entry = NULL;
int rv;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "iasecc_sm_read_binary() card:%p offs:%i count:%i ", card, offs, count);
if (offs > 0x7fff)
LOG_TEST_RET(ctx, SC_ERROR_OFFSET_TOO_LARGE, "Invalid arguments");
if (count == 0)
return 0;
sc_print_cache(card);
if (card->cache.valid && card->cache.current_ef) {
entry = sc_file_get_acl_entry(card->cache.current_ef, SC_AC_OP_UPDATE);
sc_log(ctx, "UPDATE method/reference %X/%X", entry->method, entry->key_ref);
entry = sc_file_get_acl_entry(card->cache.current_ef, SC_AC_OP_READ);
if (!entry)
LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_FOUND, "iasecc_sm_read() 'READ' ACL not present");
if (entry->method == SC_AC_SCB && (entry->key_ref & IASECC_SCB_METHOD_SM))
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Not yet");
}
sc_log(ctx, "READ method/reference %X/%X", entry->method, entry->key_ref);
if ((entry->method == SC_AC_SCB) && (entry->key_ref & IASECC_SCB_METHOD_SM)) {
unsigned char se_num = (entry->method == SC_AC_SCB) ? (entry->key_ref & IASECC_SCB_METHOD_MASK_REF) : 0;
memset(buf_zero, 0, sizeof(buf_zero));
while (count) {
sc_log(ctx, "count %i, max_send_size %i", count, card->max_send_size);
sz = count > card->max_send_size ? card->max_send_size : count;
rv = iso_ops->update_binary(card, offs, buf_zero, sz, flags);
LOG_TEST_RET(ctx, rv, "write empty buffer failed");
offs += sz;
count -= sz;
}
rv = SC_SUCCESS;
rv = iasecc_sm_read_binary(card, se_num, offs, buff, count);
LOG_FUNC_RETURN(ctx, rv);
}
}
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
static int
_iasecc_sm_update_binary(struct sc_card *card, unsigned int offs,
const unsigned char *buff, size_t count)
{
struct sc_context *ctx = card->ctx;
const struct sc_acl_entry *entry = NULL;
int rv;
if (count == 0)
return SC_SUCCESS;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "iasecc_sm_read_binary() card:%p offs:%i count:%i ", card, offs, count);
sc_print_cache(card);
if (card->cache.valid && card->cache.current_ef) {
entry = sc_file_get_acl_entry(card->cache.current_ef, SC_AC_OP_UPDATE);
if (!entry)
LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_FOUND, "iasecc_sm_update() 'UPDATE' ACL not present");
sc_log(ctx, "UPDATE method/reference %X/%X", entry->method, entry->key_ref);
if (entry->method == SC_AC_SCB && (entry->key_ref & IASECC_SCB_METHOD_SM)) {
unsigned char se_num = entry->method == SC_AC_SCB ? entry->key_ref & IASECC_SCB_METHOD_MASK_REF : 0;
rv = iasecc_sm_update_binary(card, se_num, offs, buff, count);
LOG_FUNC_RETURN(ctx, rv);
}
}
LOG_FUNC_RETURN(ctx, 0);
}
@ -664,16 +779,22 @@ iasecc_emulate_fcp(struct sc_context *ctx, struct sc_apdu *apdu)
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
/* TODO: redesign using of cache
* TODO: do not keep inermediate results in 'file_out' argument */
static int
iasecc_select_file(struct sc_card *card, const struct sc_path *path,
struct sc_file **file_out)
{
struct sc_context *ctx = card->ctx;
struct sc_path lpath;
int cache_valid = card->cache.valid, df_from_cache = 0;
int rv, ii;
LOG_FUNC_CALLED(ctx);
memcpy(&lpath, path, sizeof(struct sc_path));
if (file_out)
*file_out = NULL;
sc_log(ctx, "iasecc_select_file(card:%p) path.len %i; path.type %i; aid_len %i",
card, path->len, path->type, path->aid.len);
@ -681,9 +802,6 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path,
sc_print_cache(card);
if (lpath.len >= 2 && lpath.value[0] == 0x3F && lpath.value[1] == 0x00) {
struct sc_path mfpath;
memset(&mfpath, 0, sizeof(struct sc_path));
sc_log(ctx, "EF.ATR(aid:'%s')", card->ef_atr ? sc_dump_hex(card->ef_atr->aid.value, card->ef_atr->aid.len) : "");
rv = iasecc_select_mf(card, file_out);
@ -706,6 +824,11 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path,
ppath.len = lpath.aid.len;
ppath.type = SC_PATH_TYPE_DF_NAME;
if (card->cache.valid && card->cache.current_df
&& card->cache.current_df->path.len == lpath.aid.len
&& !memcmp(card->cache.current_df->path.value, lpath.aid.value, lpath.aid.len))
df_from_cache = 1;
rv = iasecc_select_file(card, &ppath, &file);
LOG_TEST_RET(ctx, rv, "select AID path failed");
@ -730,10 +853,17 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path,
&& card->cache.current_df->path.len == lpath.len
&& !memcmp(card->cache.current_df->path.value, lpath.value, lpath.len)) {
sc_log(ctx, "returns current DF path %s", sc_print_path(&card->cache.current_df->path));
if (file_out)
if (file_out) {
if (*file_out)
sc_file_free(*file_out);
sc_file_dup(file_out, card->cache.current_df);
}
else {
sc_print_cache(card);
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
do {
struct sc_apdu apdu;
struct sc_file *file = NULL;
unsigned char rbuf[SC_MAX_APDU_BUFFER_SIZE];
@ -743,7 +873,8 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path,
if (card->type != SC_CARD_TYPE_IASECC_GEMALTO
&& card->type != SC_CARD_TYPE_IASECC_OBERTHUR
&& card->type != SC_CARD_TYPE_IASECC_SAGEM)
&& card->type != SC_CARD_TYPE_IASECC_SAGEM
&& card->type != SC_CARD_TYPE_IASECC_AMOS)
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported card");
if (lpath.type == SC_PATH_TYPE_FILE_ID) {
@ -752,11 +883,15 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path,
apdu.p1 = 0x01;
apdu.p2 = 0x04;
}
if (card->type == SC_CARD_TYPE_IASECC_AMOS)
apdu.p2 = 0x04;
}
else if (lpath.type == SC_PATH_TYPE_FROM_CURRENT) {
apdu.p1 = 0x09;
if (card->type == SC_CARD_TYPE_IASECC_OBERTHUR)
apdu.p2 = 0x04;
if (card->type == SC_CARD_TYPE_IASECC_AMOS)
apdu.p2 = 0x04;
}
else if (lpath.type == SC_PATH_TYPE_PARENT) {
apdu.p1 = 0x03;
@ -765,6 +900,8 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path,
}
else if (lpath.type == SC_PATH_TYPE_DF_NAME) {
apdu.p1 = 0x04;
if (card->type == SC_CARD_TYPE_IASECC_AMOS)
apdu.p2 = 0x04;
}
else {
sc_log(ctx, "Invalid PATH type: 0x%X", lpath.type);
@ -798,6 +935,23 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path,
break;
}
/*
* Using of the cached DF and EF can cause problems in the multi-thread environment.
* FIXME: introduce config. option that invalidates this cache outside the locked card session,
* (or invent something else)
*/
if (rv == SC_ERROR_FILE_NOT_FOUND && cache_valid && df_from_cache) {
card->cache.valid = 0;
sc_log(ctx, "iasecc_select_file() file not found, retry without cached DF");
if (file_out && *file_out) {
sc_file_free(*file_out);
*file_out = NULL;
}
rv = iasecc_select_file(card, path, file_out);
LOG_FUNC_RETURN(ctx, rv);
}
LOG_TEST_RET(ctx, rv, "iasecc_select_file() check SW failed");
sc_log(ctx, "iasecc_select_file() apdu.resp %i", apdu.resplen);
@ -843,11 +997,15 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path,
sc_file_dup(&card->cache.current_ef, file);
}
if (file_out)
if (file_out) {
if (*file_out)
sc_file_free(*file_out);
*file_out = file;
else
}
else {
sc_file_free(file);
}
}
else if (lpath.type == SC_PATH_TYPE_DF_NAME) {
if (card->cache.current_df)
sc_file_free(card->cache.current_df);
@ -859,7 +1017,7 @@ iasecc_select_file(struct sc_card *card, const struct sc_path *path,
card->cache.valid = 1;
}
}
} while(0);
sc_print_cache(card);
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
@ -999,8 +1157,10 @@ iasecc_fcp_encode(struct sc_card *card, struct sc_file *file, unsigned char *out
continue;
entry = sc_file_get_acl_entry(file, ops[ii]);
sc_log(ctx, "method %X; reference %X", entry->method, entry->key_ref);
if (!entry)
continue;
sc_log(ctx, "method %X; reference %X", entry->method, entry->key_ref);
if (entry->method == SC_AC_NEVER)
continue;
else if (entry->method == SC_AC_NONE)
@ -1021,7 +1181,8 @@ iasecc_fcp_encode(struct sc_card *card, struct sc_file *file, unsigned char *out
}
printf("TODO: Encode contactless ACLs and life cycle status for all IAS/ECC cards\n");
if (card->type == SC_CARD_TYPE_IASECC_SAGEM) {
if (card->type == SC_CARD_TYPE_IASECC_SAGEM ||
card->type == SC_CARD_TYPE_IASECC_AMOS ) {
unsigned char status = 0;
buf[offs++] = IASECC_FCP_TAG_ACLS;
@ -1034,7 +1195,7 @@ iasecc_fcp_encode(struct sc_card *card, struct sc_file *file, unsigned char *out
offs += nn_smb;
/* Same ACLs for contactless */
buf[offs++] = IASECC_DOCP_TAG_ACLS_CONTACTLESS;
buf[offs++] = IASECC_FCP_TAG_ACLS_CONTACTLESS;
buf[offs++] = nn_smb + 1;
buf[offs++] = amb;
memcpy(buf + offs, smbs, nn_smb);
@ -1096,10 +1257,19 @@ iasecc_create_file(struct sc_card *card, struct sc_file *file)
if (card->cache.valid && card->cache.current_df) {
entry = sc_file_get_acl_entry(card->cache.current_df, SC_AC_OP_CREATE);
if (!entry)
LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_FOUND, "iasecc_create_file() 'CREATE' ACL not present");
sc_log(ctx, "iasecc_create_file() 'CREATE' method/reference %X/%X", entry->method, entry->key_ref);
sc_log(ctx, "iasecc_create_file() create data: '%s'", sc_dump_hex(sbuf, sbuf_len + 2));
if (entry->method == SC_AC_SCB && (entry->key_ref & IASECC_SCB_METHOD_SM))
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Not yet");
if (entry->method == SC_AC_SCB && (entry->key_ref & IASECC_SCB_METHOD_SM)) {
rv = iasecc_sm_create_file(card, entry->key_ref & IASECC_SCB_METHOD_MASK_REF, sbuf, sbuf_len + 2);
LOG_TEST_RET(ctx, rv, "iasecc_create_file() SM create file error");
rv = iasecc_select_file(card, &file->path, NULL);
LOG_FUNC_RETURN(ctx, rv);
}
}
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0, 0);
@ -1147,13 +1317,16 @@ iasecc_finish(struct sc_card *card)
{
struct sc_context *ctx = card->ctx;
struct iasecc_private_data *private_data = (struct iasecc_private_data *)card->drv_data;
struct iasecc_se_info *se_info = private_data->se_info, *next;
LOG_FUNC_CALLED(ctx);
if (private_data->se_info) {
if (private_data->se_info->df)
sc_file_free(private_data->se_info->df);
free(private_data->se_info);
while (se_info) {
if (se_info->df)
sc_file_free(se_info->df);
next = se_info->next;
free(se_info);
se_info = next;
}
free(card->drv_data);
@ -1181,11 +1354,15 @@ iasecc_delete_file(struct sc_card *card, const struct sc_path *path)
LOG_TEST_RET(ctx, rv, "Cannot select file to delete");
entry = sc_file_get_acl_entry(file, SC_AC_OP_DELETE);
if (!entry)
LOG_TEST_RET(ctx, SC_ERROR_OBJECT_NOT_FOUND, "Cannot delete file: no 'DELETE' acl");
sc_log(ctx, "DELETE method/reference %X/%X", entry->method, entry->key_ref);
if (entry->method == SC_AC_SCB && (entry->key_ref & IASECC_SCB_METHOD_SM))
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Not yet");
if (entry->method == SC_AC_SCB && (entry->key_ref & IASECC_SCB_METHOD_SM)) {
unsigned char se_num = (entry->method == SC_AC_SCB) ? (entry->key_ref & IASECC_SCB_METHOD_MASK_REF) : 0;
rv = iasecc_sm_delete_file(card, se_num, file->id);
}
else {
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xE4, 0x00, 0x00);
rv = sc_transmit_apdu(card, &apdu);
@ -1196,13 +1373,10 @@ iasecc_delete_file(struct sc_card *card, const struct sc_path *path)
if (card->cache.valid && card->cache.current_ef)
sc_file_free(card->cache.current_ef);
card->cache.current_ef = NULL;
}
sc_file_free(file);
LOG_FUNC_RETURN(ctx, rv);
LOG_FUNC_CALLED(ctx);
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
@ -1322,7 +1496,7 @@ iasecc_se_get_info_from_cache(struct sc_card *card, struct iasecc_se_info *se)
}
static int
int
iasecc_se_get_info(struct sc_card *card, struct iasecc_se_info *se)
{
struct sc_context *ctx = card->ctx;
@ -1595,11 +1769,18 @@ iasecc_chv_verify(struct sc_card *card, struct sc_pin_cmd_data *pin_cmd,
int *tries_left)
{
struct sc_context *ctx = card->ctx;
struct sc_acl_entry acl = pin_cmd->pin1.acls[IASECC_ACLS_CHV_VERIFY];
struct sc_apdu apdu;
int rv;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "CHV PIN reference %i, data_len %i", pin_cmd->pin_reference, pin_cmd->pin1.len);
sc_log(ctx, "Verify CHV PIN(ref:%i,len:%i,acl:%X:%X)", pin_cmd->pin_reference, pin_cmd->pin1.len,
acl.method, acl.key_ref);
if (acl.method & IASECC_SCB_METHOD_SM) {
rv = iasecc_sm_pin_verify(card, acl.key_ref, pin_cmd, tries_left);
LOG_FUNC_RETURN(ctx, rv);
}
if (pin_cmd->pin1.data && !pin_cmd->pin1.len) {
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0, pin_cmd->pin_reference);
@ -1709,7 +1890,11 @@ iasecc_pin_verify(struct sc_card *card, unsigned type, unsigned reference,
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "Verify PIN(type:%X,ref:%i,data(len:%i,%p)", type, reference, data_len, data);
if (type == SC_AC_SCB) {
if (type == SC_AC_AUT) {
rv = iasecc_sm_external_authentication(card, reference, tries_left);
LOG_FUNC_RETURN(ctx, rv);
}
else if (type == SC_AC_SCB) {
if (reference & IASECC_SCB_METHOD_USER_AUTH) {
type = SC_AC_SEN;
reference = reference & IASECC_SCB_METHOD_MASK_REF;
@ -1937,7 +2122,7 @@ iasecc_pin_get_policy (struct sc_card *card, struct sc_pin_cmd_data *data)
crt_num++;
}
if (scb & (IASECC_SCB_METHOD_SM || IASECC_SCB_METHOD_EXT_AUTH)) {
if (scb & (IASECC_SCB_METHOD_SM | IASECC_SCB_METHOD_EXT_AUTH)) {
sc_log(ctx, "'SM' and 'EXTERNAL AUTHENTICATION' protection methods are not supported: SCB:0x%X", scb);
/* Set to 'NEVER' if all conditions are needed or
* there is no user authentication method allowed */
@ -1993,6 +2178,108 @@ iasecc_pin_get_policy (struct sc_card *card, struct sc_pin_cmd_data *data)
}
static int
iasecc_keyset_change(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_left)
{
struct sc_context *ctx = card->ctx;
struct iasecc_sdo_update update;
struct iasecc_sdo sdo;
unsigned scb;
int rv;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "Change keyset(ref:%i,lengths:%i)", data->pin_reference, data->pin2.len);
if (!data->pin2.data || data->pin2.len < 32)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Needs at least 32 bytes for a new keyset value");
memset(&sdo, 0, sizeof(sdo));
sdo.sdo_class = IASECC_SDO_CLASS_KEYSET;
sdo.sdo_ref = data->pin_reference;
rv = iasecc_sdo_get_data(card, &sdo);
LOG_TEST_RET(ctx, rv, "Cannot get keyset data");
if (sdo.docp.acls_contact.size == 0)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Bewildered ... there are no ACLs");
scb = sdo.docp.scbs[IASECC_ACLS_KEYSET_PUT_DATA];
iasecc_sdo_free_fields(card, &sdo);
sc_log(ctx, "SCB:0x%X", scb);
if (!(scb & IASECC_SCB_METHOD_SM))
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Other then protected by SM, the keyset change is not supported");
memset(&update, 0, sizeof(update));
update.magic = SC_CARDCTL_IASECC_SDO_MAGIC_PUT_DATA;
update.sdo_class = sdo.sdo_class;
update.sdo_ref = sdo.sdo_ref;
update.fields[0].parent_tag = IASECC_SDO_KEYSET_TAG;
update.fields[0].tag = IASECC_SDO_KEYSET_TAG_MAC;
update.fields[0].value = data->pin2.data;
update.fields[0].size = 16;
update.fields[1].parent_tag = IASECC_SDO_KEYSET_TAG;
update.fields[1].tag = IASECC_SDO_KEYSET_TAG_ENC;
update.fields[1].value = data->pin2.data + 16;
update.fields[1].size = 16;
rv = iasecc_sm_sdo_update(card, (scb & IASECC_SCB_METHOD_MASK_REF), &update);
LOG_FUNC_RETURN(ctx, rv);
}
static int
iasecc_pin_change(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_left)
{
struct sc_context *ctx = card->ctx;
struct sc_apdu apdu;
unsigned reference = data->pin_reference;
unsigned char pin_data[0x100];
int rv;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "Change PIN(ref:%i,type:0x%X,lengths:%i/%i)", reference, data->pin_type, data->pin1.len, data->pin2.len);
if ((card->reader->capabilities & SC_READER_CAP_PIN_PAD)) {
if (!data->pin1.data && !data->pin1.len && &data->pin2.data && !data->pin2.len) {
rv = iasecc_chv_change_pinpad(card, reference, tries_left);
sc_log(ctx, "iasecc_pin_cmd(SC_PIN_CMD_CHANGE) chv_change_pinpad returned %i", rv);
LOG_FUNC_RETURN(ctx, rv);
}
}
if (!data->pin1.data && data->pin1.len)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid PIN1 arguments");
if (!data->pin2.data && data->pin2.len)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid PIN2 arguments");
rv = iasecc_pin_verify(card, data->pin_type, reference, data->pin1.data, data->pin1.len, tries_left);
sc_log(ctx, "iasecc_pin_cmd(SC_PIN_CMD_CHANGE) pin_verify returned %i", rv);
LOG_TEST_RET(ctx, rv, "PIN verification error");
if ((unsigned)(data->pin1.len + data->pin2.len) > sizeof(pin_data))
LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "Buffer too small for the 'Change PIN' data");
if (data->pin1.data)
memcpy(pin_data, data->pin1.data, data->pin1.len);
if (data->pin2.data)
memcpy(pin_data + data->pin1.len, data->pin2.data, data->pin2.len);
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0, reference);
apdu.data = pin_data;
apdu.datalen = data->pin1.len + data->pin2.len;
apdu.lc = apdu.datalen;
rv = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(ctx, rv, "APDU transmit failed");
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_TEST_RET(ctx, rv, "PIN cmd failed");
LOG_FUNC_RETURN(ctx, rv);
}
static int
iasecc_pin_reset(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_left)
{
@ -2006,10 +2293,12 @@ iasecc_pin_reset(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "Reset PIN(ref:%i,lengths:%i/%i)", data->pin_reference, data->pin1.len, data->pin2.len);
if (data->pin_type != SC_AC_CHV)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unblock procedure can be used only with the PINs of type CHV");
reference = data->pin_reference;
if (!(data->pin_reference & IASECC_OBJECT_REF_LOCAL)
&& card->cache.valid && card->cache.current_df) {
if (!(data->pin_reference & IASECC_OBJECT_REF_LOCAL) && card->cache.valid && card->cache.current_df) {
struct sc_path path;
sc_file_dup(&save_current, card->cache.current_df);
@ -2030,32 +2319,33 @@ iasecc_pin_reset(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_
LOG_TEST_RET(ctx, rv, "Cannot get PIN data");
if (sdo.docp.acls_contact.size == 0)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Extremely strange ... there is no ACLs");
LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Extremely strange ... there are no ACLs");
scb = sdo.docp.scbs[IASECC_ACLS_CHV_RESET];
do {
unsigned need_all = scb & IASECC_SCB_METHOD_NEED_ALL ? 1 : 0;
int ignore_ext_auth = 0;
unsigned char se_num = scb & IASECC_SCB_METHOD_MASK_REF;
#ifdef ALLOW_IGNORE_EXTERNAL_AUTHENTICATION
ignore_ext_auth = ((scb & IASECC_SCB_METHOD_EXT_AUTH) && !need_all && (scb & IASECC_SCB_METHOD_SM));
#endif
if (scb & IASECC_SCB_METHOD_USER_AUTH) {
sc_log(ctx, "Try to verify PUK code: pin1.data:%p, pin1.len:%i", data->pin1.data, data->pin1.len);
rv = iasecc_pin_verify(card, SC_AC_SEN, scb & IASECC_SCB_METHOD_MASK_REF,
data->pin1.data, data->pin1.len, tries_left);
sc_log(ctx, "Verify PUK code returned %i", rv);
LOG_TEST_RET(ctx, rv, "iasecc_pin_reset() PIN verification error");
rv = iasecc_pin_verify(card, SC_AC_SEN, se_num, data->pin1.data, data->pin1.len, tries_left);
LOG_TEST_RET(ctx, rv, "iasecc_pin_reset() verify PUK error");
if (!need_all)
break;
}
if ((scb & IASECC_SCB_METHOD_EXT_AUTH) && !ignore_ext_auth)
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Not yet");
if (scb & IASECC_SCB_METHOD_SM) {
rv = iasecc_sm_pin_reset(card, se_num, data);
LOG_FUNC_RETURN(ctx, rv);
if (scb & IASECC_SCB_METHOD_SM)
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Not yet");
if (!need_all)
break;
}
if (scb & IASECC_SCB_METHOD_EXT_AUTH) {
rv = iasecc_sm_external_authentication(card, reference, tries_left);
LOG_TEST_RET(ctx, rv, "iasecc_pin_reset() external authentication error");
}
} while(0);
iasecc_sdo_free_fields(card, &sdo);
@ -2100,66 +2390,26 @@ iasecc_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, int *tries_le
{
struct sc_context *ctx = card->ctx;
struct sc_apdu apdu;
unsigned reference;
unsigned char pin_data[0x100];
int rv;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "iasecc_pin_cmd(card:%p) cmd 0x%X, PIN type 0x%X, PIN reference %i, PIN-1 %p:%i, PIN-2 %p:%i",
card, data->cmd, data->pin_type, data->pin_reference,
sc_log(ctx, "iasecc_pin_cmd() cmd 0x%X, PIN type 0x%X, PIN reference %i, PIN-1 %p:%i, PIN-2 %p:%i",
data->cmd, data->pin_type, data->pin_reference,
data->pin1.data, data->pin1.len, data->pin2.data, data->pin2.len);
reference = data->pin_reference;
switch (data->cmd) {
case SC_PIN_CMD_VERIFY:
rv = iasecc_pin_verify(card, data->pin_type, reference, data->pin1.data, data->pin1.len, tries_left);
LOG_TEST_RET(ctx, rv, "PIN verification error");
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
case SC_PIN_CMD_CHANGE:
if ((card->reader->capabilities & SC_READER_CAP_PIN_PAD)) {
if (!data->pin1.data && !data->pin1.len && &data->pin2.data && !data->pin2.len) {
rv = iasecc_chv_change_pinpad(card, reference, tries_left);
sc_log(ctx, "iasecc_pin_cmd(SC_PIN_CMD_CHANGE) chv_change_pinpad returned %i", rv);
rv = iasecc_pin_verify(card, data->pin_type, data->pin_reference, data->pin1.data, data->pin1.len, tries_left);
LOG_FUNC_RETURN(ctx, rv);
case SC_PIN_CMD_CHANGE:
if (data->pin_type == SC_AC_AUT)
rv = iasecc_keyset_change(card, data, tries_left);
else
rv = iasecc_pin_change(card, data, tries_left);
LOG_FUNC_RETURN(ctx, rv);
}
}
if (!data->pin1.data && data->pin1.len)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid PIN1 arguments");
if (!data->pin2.data && data->pin2.len)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Invalid PIN2 arguments");
rv = iasecc_pin_verify(card, data->pin_type, reference, data->pin1.data, data->pin1.len, tries_left);
sc_log(ctx, "iasecc_pin_cmd(SC_PIN_CMD_CHANGE) pin_verify returned %i", rv);
LOG_TEST_RET(ctx, rv, "PIN verification error");
if ((unsigned)(data->pin1.len + data->pin2.len) > sizeof(pin_data))
LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "Buffer too small for the 'Change PIN' data");
if (data->pin1.data)
memcpy(pin_data, data->pin1.data, data->pin1.len);
if (data->pin2.data)
memcpy(pin_data + data->pin1.len, data->pin2.data, data->pin2.len);
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0, reference);
apdu.data = pin_data;
apdu.datalen = data->pin1.len + data->pin2.len;
apdu.lc = apdu.datalen;
break;
case SC_PIN_CMD_UNBLOCK:
if (data->pin_type != SC_AC_CHV) {
sc_log(ctx, "To unblock PIN it's CHV reference should be presented");
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
}
rv = iasecc_pin_reset(card, data, tries_left);
LOG_TEST_RET(ctx, rv, "PIN unblock error");
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
LOG_FUNC_RETURN(ctx, rv);
case SC_PIN_CMD_GET_INFO:
rv = iasecc_pin_get_policy(card, data);
LOG_FUNC_RETURN(ctx, rv);
@ -2420,7 +2670,7 @@ iasecc_sdo_key_rsa_put_data(struct sc_card *card, struct iasecc_sdo_rsa_update *
sc_log(ctx, "reference of the private key to store: %X", update->sdo_prv_key->sdo_ref);
if (update->sdo_prv_key->docp.acls_contact.size == 0)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "extremely strange ... there is no ACLs");
LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "extremely strange ... there are no ACLs");
scb = update->sdo_prv_key->docp.scbs[IASECC_ACLS_RSAKEY_PUT_DATA];
sc_log(ctx, "'UPDATE PRIVATE RSA' scb 0x%X", scb);
@ -2434,8 +2684,14 @@ iasecc_sdo_key_rsa_put_data(struct sc_card *card, struct iasecc_sdo_rsa_update *
if (scb & IASECC_SCB_METHOD_EXT_AUTH)
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Not yet");
if (scb & IASECC_SCB_METHOD_SM)
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Not yet");
if (scb & IASECC_SCB_METHOD_SM) {
#ifdef ENABLE_SM
rv = iasecc_sm_rsa_update(card, scb & IASECC_SCB_METHOD_MASK_REF, update);
LOG_FUNC_RETURN(ctx, rv);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
#endif
}
} while(0);
rv = iasecc_sdo_put_data(card, &update->update_prv);
@ -2561,23 +2817,24 @@ iasecc_sdo_generate(struct sc_card *card, struct iasecc_sdo *sdo)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "For a moment, only RSA_PRIVATE class can be accepted for the SDO generation");
if (sdo->docp.acls_contact.size == 0)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "iasecc_sdo_generate() Extremely strange ... there is no ACLs");
LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Bewildered ... there are no ACLs");
scb = sdo->docp.scbs[IASECC_ACLS_RSAKEY_GENERATE];
sc_log(ctx, "'generate RSA key' SCB 0x%X", scb);
do {
unsigned all_conditions = scb & IASECC_SCB_METHOD_NEED_ALL ? 1 : 0;
if (scb & IASECC_SCB_METHOD_USER_AUTH) {
if (scb & IASECC_SCB_METHOD_USER_AUTH)
if (!all_conditions)
break;
}
if (scb & IASECC_SCB_METHOD_EXT_AUTH)
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Not yet");
if (scb & IASECC_SCB_METHOD_SM)
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Not yet");
if (scb & IASECC_SCB_METHOD_SM) {
rv = iasecc_sm_rsa_generate(card, scb & IASECC_SCB_METHOD_MASK_REF, sdo);
LOG_FUNC_RETURN(ctx, rv);
}
} while(0);
memset(&update_pubkey, 0, sizeof(update_pubkey));
@ -2643,6 +2900,8 @@ iasecc_get_chv_reference_from_se(struct sc_card *card, int *se_reference)
rv = iasecc_se_get_crt(card, &se, &crt);
LOG_TEST_RET(ctx, rv, "Cannot get 'USER PASSWORD' authentication template");
if (se.df)
sc_file_free(se.df);
LOG_FUNC_RETURN(ctx, crt.refs[0]);
}
@ -2717,7 +2976,7 @@ iasecc_decipher(struct sc_card *card,
apdu.lc = offs;
apdu.resp = resp;
apdu.resplen = sizeof(resp);
apdu.le = in_len - (in_len % 8);
apdu.le = 256;
rv = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(ctx, rv, "APDU transmit failed");
@ -3110,8 +3369,10 @@ iasecc_get_free_reference(struct sc_card *card, struct iasecc_ctl_get_free_refer
sz = *(sdo->docp.size.value + 0) * 0x100 + *(sdo->docp.size.value + 1);
sc_log(ctx, "SDO(idx:%i) size %i; key_size %i", idx, sz, ctl_data->key_size);
if (sz != ctl_data->key_size / 8)
if (sz != ctl_data->key_size / 8) {
sc_log(ctx, "key index %i ignored: different key sizes %i/%i", idx, sz, ctl_data->key_size / 8);
continue;
}
if (sdo->docp.non_repudiation.value) {
sc_log(ctx, "non repudiation flag %X", sdo->docp.non_repudiation.value[0]);
@ -3145,19 +3406,18 @@ iasecc_get_free_reference(struct sc_card *card, struct iasecc_ctl_get_free_refer
continue;
}
}
else {
if (ctl_data->usage & (SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP)) {
if (sdo->docp.scbs[IASECC_ACLS_RSAKEY_PSO_DECIPHER] == IASECC_SCB_NEVER) {
sc_log(ctx, "key index %i ignored: PSO DECIPHER not allowed", idx);
continue;
}
}
if (ctl_data->usage & SC_PKCS15_PRKEY_USAGE_SIGN) {
else if (ctl_data->usage & SC_PKCS15_PRKEY_USAGE_SIGN) {
if (sdo->docp.scbs[IASECC_ACLS_RSAKEY_INTERNAL_AUTH] == IASECC_SCB_NEVER) {
sc_log(ctx, "key index %i ignored: INTERNAL AUTHENTICATE not allowed", idx);
continue;
}
}
if (ctl_data->usage & (SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP)) {
if (sdo->docp.scbs[IASECC_ACLS_RSAKEY_PSO_DECIPHER] == IASECC_SCB_NEVER) {
sc_log(ctx, "key index %i ignored: PSO DECIPHER not allowed", idx);
continue;
}
}
break;

View File

@ -186,6 +186,7 @@ enum {
SC_CARD_TYPE_IASECC_GEMALTO,
SC_CARD_TYPE_IASECC_OBERTHUR,
SC_CARD_TYPE_IASECC_SAGEM,
SC_CARD_TYPE_IASECC_AMOS
};
extern sc_card_driver_t *sc_get_default_driver(void);

View File

@ -244,8 +244,6 @@ struct iasecc_sdo_update {
struct iasecc_extended_tlv fields[IASECC_SDO_TAGS_UPDATE_MAX];
unsigned char acl_method, acl_ref;
unsigned magic;
};
@ -294,6 +292,16 @@ enum IASECC_KEY_TYPE {
IASECC_SDO_CLASS_RSA_PUB = 0x20
};
struct iasecc_sm_cmd_update_binary {
const unsigned char *data;
size_t offs, count;
};
struct iasecc_sm_cmd_create_file {
const unsigned char *data;
size_t size;
};
struct sc_card;
int iasecc_sdo_convert_acl(struct sc_card *, struct iasecc_sdo *, unsigned char, unsigned *, unsigned *);
void iasecc_sdo_free_fields(struct sc_card *, struct iasecc_sdo *);
@ -311,4 +319,16 @@ int iasecc_se_get_crt_by_usage(struct sc_card *, struct iasecc_se_info *,
int iasecc_sdo_encode_rsa_update(struct sc_context *, struct iasecc_sdo *, struct sc_pkcs15_prkey_rsa *, struct iasecc_sdo_update *);
int iasecc_sdo_parse_card_answer(struct sc_context *, unsigned char *, size_t, struct iasecc_sm_card_answer *);
int iasecc_docp_copy(struct sc_context *, struct iasecc_sdo_docp *, struct iasecc_sdo_docp *);
int iasecc_se_get_info(struct sc_card *card, struct iasecc_se_info *se);
int iasecc_sm_external_authentication(struct sc_card *card, unsigned skey_ref, int *tries_left);
int iasecc_sm_pin_verify(struct sc_card *card, unsigned se_num, struct sc_pin_cmd_data *data, int *tries_left);
int iasecc_sm_pin_reset(struct sc_card *card, unsigned se_num, struct sc_pin_cmd_data *data);
int iasecc_sm_update_binary(struct sc_card *card, unsigned se_num, size_t offs, const unsigned char *buff, size_t count);
int iasecc_sm_read_binary(struct sc_card *card, unsigned se_num, size_t offs, unsigned char *buff, size_t count);
int iasecc_sm_create_file(struct sc_card *card, unsigned se_num, unsigned char *fcp, size_t fcp_len);
int iasecc_sm_delete_file(struct sc_card *card, unsigned se_num, unsigned int file_id);
int iasecc_sm_rsa_generate(struct sc_card *card, unsigned se_num, struct iasecc_sdo *sdo);
int iasecc_sm_rsa_update(struct sc_card *card, unsigned se_num, struct iasecc_sdo_rsa_update *udata);
int iasecc_sm_sdo_update(struct sc_card *card, unsigned se_num, struct iasecc_sdo_update *update);
#endif

728
src/libopensc/iasecc-sm.c Normal file
View File

@ -0,0 +1,728 @@
/*
* iasecc.h Support for IAS/ECC smart cards
*
* Copyright (C) 2010 Viktor Tarasov <vtarasov@opentrust.com>
* OpenTrust <www.opentrust.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <string.h>
#include <stdlib.h>
#include "internal.h"
#include "asn1.h"
#include "cardctl.h"
#ifndef ENABLE_OPENSSL
#error "Need OpenSSL"
#endif
#include "sm.h"
#include "iasecc.h"
#include "authentic.h"
#ifdef ENABLE_SM
static int
sm_save_sc_context (struct sc_card *card, struct sm_info *sm_info)
{
struct sc_context *ctx = card->ctx;
struct sc_card_cache *cache = &card->cache;
if (!card || !sm_info)
return SC_ERROR_INVALID_ARGUMENTS;
sc_log(ctx, "SM save context: cache(valid:%i,current_df:%p)", cache->valid, cache->current_df);
if (cache->valid && cache->current_df) {
sm_info->current_path_df = cache->current_df->path;
if (cache->current_df->path.type == SC_PATH_TYPE_DF_NAME) {
if (cache->current_df->path.aid.len) {
sm_info->current_aid = cache->current_df->path.aid;
}
else {
memcpy(sm_info->current_aid.value, cache->current_df->path.value, cache->current_df->path.len);
sm_info->current_aid.len = cache->current_df->path.len;
}
}
}
if (cache->valid && cache->current_ef)
sm_info->current_path_ef = cache->current_ef->path;
return SC_SUCCESS;
}
static int
sm_restore_sc_context(struct sc_card *card, struct sm_info *sm_info)
{
int rv = SC_SUCCESS;
if (sm_info->current_path_df.type == SC_PATH_TYPE_DF_NAME && sm_info->current_path_df.len)
rv = sc_select_file(card, &sm_info->current_path_df, NULL);
if (sm_info->current_path_ef.len && rv == SC_SUCCESS)
rv = sc_select_file(card, &sm_info->current_path_ef, NULL);
memset(&sm_info->current_path_df, 0, sizeof(sm_info->current_path_df));
memset(&sm_info->current_path_ef, 0, sizeof(sm_info->current_path_ef));
return rv;
}
#endif
static int
iasecc_sm_transmit_apdus(struct sc_card *card, struct sc_remote_data *rdata,
unsigned char *out, size_t *out_len)
{
struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
struct sc_remote_apdu *rapdu = rdata->data;
int rv = SC_SUCCESS, offs = 0;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "iasecc_sm_transmit_apdus() rdata-length %i", rdata->length);
while (rapdu) {
sc_log(ctx, "iasecc_sm_transmit_apdus() rAPDU flags 0x%X", rapdu->apdu.flags);
rv = sc_transmit_apdu(card, &rapdu->apdu);
LOG_TEST_RET(ctx, rv, "iasecc_sm_transmit_apdus() failed to execute r-APDU");
rv = sc_check_sw(card, rapdu->apdu.sw1, rapdu->apdu.sw2);
if (rv < 0 && !(rapdu->flags & SC_REMOTE_APDU_FLAG_NOT_FATAL))
LOG_TEST_RET(ctx, rv, "iasecc_sm_transmit_apdus() fatal error %i");
if (out && out_len && (rapdu->flags & SC_REMOTE_APDU_FLAG_RETURN_ANSWER)) {
int len = rapdu->apdu.resplen > (*out_len - offs) ? (*out_len - offs) : rapdu->apdu.resplen;
memcpy(out + offs, rapdu->apdu.resp, len);
offs += len;
/* TODO: decode and gather data answers */
}
rapdu = rapdu->next;
}
if (out_len)
*out_len = offs;
LOG_FUNC_RETURN(ctx, rv);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of SM and External Authentication");
return SC_ERROR_NOT_SUPPORTED;
#endif
}
/* Big TODO: do SM release in all handles, clean the saved card context -- current DF, EF, etc. */
static int
sm_release (struct sc_card *card, struct sc_remote_data *rdata,
unsigned char *out, size_t out_len)
{
struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
struct sm_info *sm_info = &card->sm_ctx.info;
int rv;
LOG_FUNC_CALLED(ctx);
if (!card->sm_ctx.module.ops.finalize)
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
rv = card->sm_ctx.module.ops.finalize(ctx, sm_info, rdata, out, out_len);
sm_restore_sc_context(card, sm_info);
LOG_FUNC_RETURN(ctx, rv);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of SM and External Authentication");
return SC_ERROR_NOT_SUPPORTED;
#endif
}
int
iasecc_sm_external_authentication(struct sc_card *card, unsigned skey_ref, int *tries_left)
{
struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
struct sm_info *sm_info = &card->sm_ctx.info;
struct sc_remote_data rdata;
struct sc_apdu apdu;
unsigned char sbuf[0x100];
int rv, offs;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "iasecc_sm_external_authentication(): SKey ref %i", skey_ref);
if (card->sm_ctx.sm_mode == SM_MODE_NONE)
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Cannot do 'External Authentication' without SM activated ");
strncpy(sm_info->config_section, card->sm_ctx.config_section, sizeof(sm_info->config_section));
sm_info->cmd = SM_CMD_EXTERNAL_AUTH;
sm_info->serialnr = card->serialnr;
sm_info->card_type = card->type;
sm_info->sm_type = SM_TYPE_CWA14890;
sm_info->sm_params.cwa.crt_at.usage = IASECC_UQB_AT_EXTERNAL_AUTHENTICATION;
sm_info->sm_params.cwa.crt_at.algo = IASECC_ALGORITHM_ROLE_AUTH;
sm_info->sm_params.cwa.crt_at.refs[0] = skey_ref;
offs = 0;
sbuf[offs++] = IASECC_CRT_TAG_ALGO;
sbuf[offs++] = 0x01;
sbuf[offs++] = IASECC_ALGORITHM_ROLE_AUTH;
sbuf[offs++] = IASECC_CRT_TAG_REFERENCE;
sbuf[offs++] = 0x01;
sbuf[offs++] = skey_ref;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x81, 0xA4);
apdu.data = sbuf;
apdu.datalen = offs;
apdu.lc = offs;
rv = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(ctx, rv, "iasecc_sm_external_authentication(): APDU transmit failed");
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_TEST_RET(ctx, rv, "iasecc_sm_external_authentication(): set SE error");
rv = sc_get_challenge(card, sm_info->schannel.card_challenge, sizeof(sm_info->schannel.card_challenge));
LOG_TEST_RET(ctx, rv, "iasecc_sm_external_authentication(): set SE error");
sc_remote_data_init(&rdata);
if (!card->sm_ctx.module.ops.initialize)
LOG_TEST_RET(ctx, SC_ERROR_SM_NOT_INITIALIZED, "No SM module");
rv = card->sm_ctx.module.ops.initialize(ctx, sm_info, &rdata);
LOG_TEST_RET(ctx, rv, "SM: INITIALIZE failed");
sc_log(ctx, "sm_iasecc_external_authentication(): rdata length %i\n", rdata.length);
rv = iasecc_sm_transmit_apdus (card, &rdata, NULL, 0);
if (rv == SC_ERROR_PIN_CODE_INCORRECT && tries_left)
*tries_left = (rdata.data + rdata.length - 1)->apdu.sw2 & 0x0F;
LOG_TEST_RET(ctx, rv, "sm_iasecc_external_authentication(): execute failed");
LOG_FUNC_RETURN(ctx, rv);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of SM and External Authentication");
return SC_ERROR_NOT_SUPPORTED;
#endif
}
static int
iasecc_sm_se_mutual_authentication(struct sc_card *card, unsigned se_num)
{
struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
struct sm_info *sm_info = &card->sm_ctx.info;
struct iasecc_se_info se;
struct sc_crt *crt = &sm_info->sm_params.cwa.crt_at;
struct sc_apdu apdu;
unsigned char sbuf[0x100];
int rv, offs;
memset(&se, 0, sizeof(se));
se.reference = se_num;
crt->usage = IASECC_UQB_AT_MUTUAL_AUTHENTICATION;
crt->tag = IASECC_CRT_TAG_AT;
rv = iasecc_se_get_info(card, &se);
LOG_TEST_RET(ctx, rv, "Get SE info error");
rv = iasecc_se_get_crt(card, &se, crt);
LOG_TEST_RET(ctx, rv, "Cannot get authentication CRT");
if (se.df)
sc_file_free(se.df);
/* MSE SET Mutual Authentication SK scheme */
offs = 0;
sbuf[offs++] = IASECC_CRT_TAG_ALGO;
sbuf[offs++] = 0x01;
sbuf[offs++] = crt->algo;
sbuf[offs++] = IASECC_CRT_TAG_REFERENCE;
sbuf[offs++] = 0x01;
sbuf[offs++] = crt->refs[0];
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xC1, 0xA4);
apdu.data = sbuf;
apdu.datalen = offs;
apdu.lc = offs;
rv = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(ctx, rv, "SM set SE mutual auth.: APDU transmit failed");
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_TEST_RET(ctx, rv, "SM set SE mutual auth.: set SE error");
LOG_FUNC_RETURN(ctx, rv);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
return SC_ERROR_NOT_SUPPORTED;
#endif
}
static int
iasecc_sm_get_challenge(struct sc_card *card, unsigned char *out, size_t len)
{
struct sc_context *ctx = card->ctx;
struct sc_apdu apdu;
unsigned char rbuf[SC_MAX_APDU_BUFFER_SIZE];
int rv;
sc_log(ctx, "SM get challenge: length %i",len);
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0, 0);
apdu.le = len;
apdu.resplen = len;
apdu.resp = rbuf;
rv = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(ctx, rv, "APDU transmit failed");
rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
LOG_TEST_RET(ctx, rv, "Command failed");
memcpy(out, rbuf, apdu.resplen);
LOG_FUNC_RETURN(ctx, apdu.resplen);
}
int
iasecc_sm_initialize(struct sc_card *card, unsigned se_num, unsigned cmd)
{
struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
struct sm_info *sm_info = &card->sm_ctx.info;
struct sm_cwa_session *cwa_session = &sm_info->schannel.session.cwa;
struct sc_remote_data rdata;
int rv;
LOG_FUNC_CALLED(ctx);
strncpy(sm_info->config_section, card->sm_ctx.config_section, sizeof(sm_info->config_section));
sm_info->cmd = cmd;
sm_info->serialnr = card->serialnr;
sm_info->card_type = card->type;
sm_info->sm_type = SM_TYPE_CWA14890;
rv = iasecc_sm_se_mutual_authentication(card, se_num);
LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() MUTUAL AUTHENTICATION failed");
rv = iasecc_sm_get_challenge(card, sm_info->schannel.card_challenge, SM_SMALL_CHALLENGE_LEN);
LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() GET CHALLENGE failed");
sc_remote_data_init(&rdata);
rv = sm_save_sc_context(card, sm_info);
LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() cannot save current context");
if (!card->sm_ctx.module.ops.initialize)
LOG_TEST_RET(ctx, SC_ERROR_SM_NOT_INITIALIZED, "iasecc_sm_initialize() no SM module");
rv = card->sm_ctx.module.ops.initialize(ctx, sm_info, &rdata);
LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() INITIALIZE failed");
if (rdata.length == 1) {
rdata.data->flags |= SC_REMOTE_APDU_FLAG_RETURN_ANSWER;
rdata.data->apdu.flags &= ~SC_APDU_FLAGS_NO_GET_RESP;
}
else {
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "TODO: SM init with more then one APDU");
}
cwa_session->mdata_len = sizeof(cwa_session->mdata);
rv = iasecc_sm_transmit_apdus (card, &rdata, cwa_session->mdata, &cwa_session->mdata_len);
if (rv == SC_ERROR_PIN_CODE_INCORRECT)
sc_log(ctx, "SM initialization failed, %i tries left", (rdata.data + rdata.length - 1)->apdu.sw2 & 0x0F);
LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() trasmit APDUs failed");
rdata.free(&rdata);
sc_log(ctx, "MA data(len:%i) '%s'", cwa_session->mdata_len, sc_dump_hex(cwa_session->mdata, cwa_session->mdata_len));
if (sm_info->schannel.session.cwa.mdata_len != 0x48)
LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "iasecc_sm_initialize() invalid MUTUAL AUTHENTICATE result data");
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
return SC_ERROR_NOT_SUPPORTED;
#endif
}
static int
iasecc_sm_cmd(struct sc_card *card, struct sc_remote_data *rdata)
{
#define AUTH_SM_APDUS_MAX 12
#define ENCODED_APDUS_MAX_LENGTH (AUTH_SM_APDUS_MAX * (SC_MAX_APDU_BUFFER_SIZE * 2 + 64) + 32)
struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
struct sm_info *sm_info = &card->sm_ctx.info;
struct sm_cwa_session *session = &sm_info->schannel.session.cwa;
struct sc_remote_apdu *rapdu = NULL;
int rv;
LOG_FUNC_CALLED(ctx);
if (!card->sm_ctx.module.ops.get_apdus)
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
rv = card->sm_ctx.module.ops.get_apdus(ctx, sm_info, session->mdata, session->mdata_len, rdata);
LOG_TEST_RET(ctx, rv, "iasecc_sm_cmd() 'GET APDUS' failed");
sc_log(ctx, "iasecc_sm_cmd() %i remote APDUs to transmit", rdata->length);
for (rapdu = rdata->data; rapdu; rapdu = rapdu->next) {
struct sc_apdu *apdu = &rapdu->apdu;
sc_log(ctx, "iasecc_sm_cmd() apdu->ins:0x%X, resplen %i", apdu->ins, apdu->resplen);
if (!apdu->ins)
break;
rv = sc_transmit_apdu(card, apdu);
if (rv < 0) {
sc_log(ctx, "iasecc_sm_cmd() APDU transmit error rv:%i", rv);
break;
}
rv = sc_check_sw(card, apdu->sw1, apdu->sw2);
if (rv < 0 && !(rapdu->flags & SC_REMOTE_APDU_FLAG_NOT_FATAL)) {
sc_log(ctx, "iasecc_sm_cmd() APDU error rv:%i", rv);
break;
}
sc_log(ctx, "iasecc_sm_cmd() apdu->resplen %i", apdu->resplen);
}
LOG_FUNC_RETURN(ctx, rv);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
return SC_ERROR_NOT_SUPPORTED;
#endif
}
int
iasecc_sm_rsa_generate(struct sc_card *card, unsigned se_num, struct iasecc_sdo *sdo)
{
struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
struct sm_info *sm_info = &card->sm_ctx.info;
struct sc_remote_data rdata;
int rv;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "iasecc_sm_rsa_generate() SE#%i, SDO(class:%X,ref:%X)", se_num, sdo->sdo_class, sdo->sdo_ref);
rv = iasecc_sm_initialize(card, se_num, SM_CMD_RSA_GENERATE);
LOG_TEST_RET(ctx, rv, "iasecc_sm_rsa_generate() SM initialize failed");
sm_info->cmd_data = sdo;
sc_remote_data_init(&rdata);
rv = iasecc_sm_cmd(card, &rdata);
LOG_TEST_RET(ctx, rv, "iasecc_sm_rsa_generate() SM cmd failed");
rv = sm_release (card, &rdata, NULL, 0);
LOG_TEST_RET(ctx, rv, "iasecc_sm_rsa_generate() SM release failed");
rdata.free(&rdata);
LOG_FUNC_RETURN(ctx, rv);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
return SC_ERROR_NOT_SUPPORTED;
#endif
}
int
iasecc_sm_rsa_update(struct sc_card *card, unsigned se_num, struct iasecc_sdo_rsa_update *udata)
{
struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
struct sm_info *sm_info = &card->sm_ctx.info;
struct sc_remote_data rdata;
int rv;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "SM update RSA: SE#: 0x%X, SDO(class:0x%X:ref:%X)", se_num,
udata->sdo_prv_key->sdo_class, udata->sdo_prv_key->sdo_ref);
rv = iasecc_sm_initialize(card, se_num, SM_CMD_RSA_UPDATE);
LOG_TEST_RET(ctx, rv, "iasecc_sm_rsa_update() SM initialize failed");
sm_info->cmd_data = udata;
sc_remote_data_init(&rdata);
rv = iasecc_sm_cmd(card, &rdata);
LOG_TEST_RET(ctx, rv, "iasecc_sm_rsa_update() SM cmd failed");
rv = sm_release (card, &rdata, NULL, 0);
LOG_TEST_RET(ctx, rv, "iasecc_sm_rsa_update() SM release failed");
rdata.free(&rdata);
LOG_FUNC_RETURN(ctx, rv);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
return SC_ERROR_NOT_SUPPORTED;
#endif
}
int
iasecc_sm_pin_verify(struct sc_card *card, unsigned se_num, struct sc_pin_cmd_data *data, int *tries_left)
{
struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
struct sm_info *sm_info = &card->sm_ctx.info;
struct sc_remote_data rdata;
int rv;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "iasecc_sm_pin_verify() SE#%i, PIN(ref:%i,len:%i)", se_num, data->pin_reference, data->pin1.len);
rv = iasecc_sm_initialize(card, se_num, SM_CMD_PIN_VERIFY);
LOG_TEST_RET(ctx, rv, "iasecc_sm_pin_verify() SM INITIALIZE failed");
sm_info->cmd_data = data;
sc_remote_data_init(&rdata);
rv = iasecc_sm_cmd(card, &rdata);
if (rv && rdata.length && tries_left)
if (rdata.data->apdu.sw1 == 0x63 && (rdata.data->apdu.sw2 & 0xF0) == 0xC0)
*tries_left = rdata.data->apdu.sw2 & 0x0F;
LOG_TEST_RET(ctx, rv, "iasecc_sm_pin_verify() SM 'PIN VERIFY' failed");
rv = sm_release (card, &rdata, NULL, 0);
LOG_TEST_RET(ctx, rv, "iasecc_sm_pin_verify() SM release failed");
rdata.free(&rdata);
LOG_FUNC_RETURN(ctx, rv);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
return SC_ERROR_NOT_SUPPORTED;
#endif
}
int
iasecc_sm_sdo_update(struct sc_card *card, unsigned se_num, struct iasecc_sdo_update *update)
{
struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
struct sm_info *sm_info = &card->sm_ctx.info;
struct sc_remote_data rdata;
int rv;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "iasecc_sm_sdo_update() SE#%i, SDO(class:0x%X,ref:%i)", se_num, update->sdo_class, update->sdo_ref);
rv = iasecc_sm_initialize(card, se_num, SM_CMD_SDO_UPDATE);
LOG_TEST_RET(ctx, rv, "iasecc_sm_sdo_update() SM INITIALIZE failed");
sc_log(ctx, "current DF '%s'", sc_print_path(&sm_info->current_path_df));
sm_info->cmd_data = update;
sc_remote_data_init(&rdata);
rv = iasecc_sm_cmd(card, &rdata);
LOG_TEST_RET(ctx, rv, "iasecc_sm_sdo_update() SM 'SDO UPDATE' failed");
rv = sm_release (card, &rdata, NULL, 0);
LOG_TEST_RET(ctx, rv, "iasecc_sm_sdo_update() SM release failed");
rdata.free(&rdata);
LOG_FUNC_RETURN(ctx, rv);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
return SC_ERROR_NOT_SUPPORTED;
#endif
}
int
iasecc_sm_pin_reset(struct sc_card *card, unsigned se_num, struct sc_pin_cmd_data *data)
{
struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
struct sm_info *sm_info = &card->sm_ctx.info;
struct sc_remote_data rdata;
int rv;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "iasecc_sm_pin_reset() SE#%i, PIN(ref:%i,len:%i)", se_num, data->pin_reference, data->pin2.len);
rv = iasecc_sm_initialize(card, se_num, SM_CMD_PIN_RESET);
LOG_TEST_RET(ctx, rv, "iasecc_sm_pin_reset() SM INITIALIZE failed");
sm_info->cmd_data = data;
sc_remote_data_init(&rdata);
rv = iasecc_sm_cmd(card, &rdata);
LOG_TEST_RET(ctx, rv, "iasecc_sm_pin_reset() SM 'PIN RESET' failed");
rv = sm_release (card, &rdata, NULL, 0);
LOG_TEST_RET(ctx, rv, "iasecc_sm_pin_reset() SM release failed");
rdata.free(&rdata);
LOG_FUNC_RETURN(ctx, rv);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
return SC_ERROR_NOT_SUPPORTED;
#endif
}
int
iasecc_sm_create_file(struct sc_card *card, unsigned se_num, unsigned char *fcp, size_t fcp_len)
{
struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
struct sm_info *sm_info = &card->sm_ctx.info;
struct sc_remote_data rdata;
struct iasecc_sm_cmd_create_file cmd_data;
int rv;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "iasecc_sm_create_file() SE#%i, fcp(%i) '%s'", se_num, fcp_len, sc_dump_hex(fcp, fcp_len));
rv = iasecc_sm_initialize(card, se_num, SM_CMD_FILE_CREATE);
LOG_TEST_RET(ctx, rv, "iasecc_sm_create_file() SM INITIALIZE failed");
cmd_data.data = fcp;
cmd_data.size = fcp_len;
sm_info->cmd_data = &cmd_data;
sc_remote_data_init(&rdata);
rv= iasecc_sm_cmd(card, &rdata);
LOG_TEST_RET(ctx, rv, "iasecc_sm_create_file() SM 'UPDATE BINARY' failed");
rv = sm_release (card, &rdata, NULL, 0);
LOG_TEST_RET(ctx, rv, "iasecc_sm_create_file() SM release failed");
rdata.free(&rdata);
LOG_FUNC_RETURN(ctx, rv);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
return SC_ERROR_NOT_SUPPORTED;
#endif
}
int
iasecc_sm_read_binary(struct sc_card *card, unsigned se_num, size_t offs, unsigned char *buff, size_t count)
{
struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
struct sm_info *sm_info = &card->sm_ctx.info;
struct sc_remote_data rdata;
struct iasecc_sm_cmd_update_binary cmd_data;
int rv;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "SM read binary: acl:%X, offs:%i, count:%i", se_num, offs, count);
rv = iasecc_sm_initialize(card, se_num, SM_CMD_FILE_READ);
LOG_TEST_RET(ctx, rv, "iasecc_sm_read_binary() SM INITIALIZE failed");
cmd_data.offs = offs;
cmd_data.count = count;
sm_info->cmd_data = &cmd_data;
sc_remote_data_init(&rdata);
rv = iasecc_sm_cmd(card, &rdata);
LOG_TEST_RET(ctx, rv, "iasecc_sm_read_binary() SM 'READ BINARY' failed");
sc_log(ctx, "IAS/ECC decode answer() rdata length %i", rdata.length);
rv = sm_release (card, &rdata, buff, count);
LOG_TEST_RET(ctx, rv, "iasecc_sm_read_binary() SM release failed");
rdata.free(&rdata);
LOG_FUNC_RETURN(ctx, rv);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
return SC_ERROR_NOT_SUPPORTED;
#endif
}
int
iasecc_sm_update_binary(struct sc_card *card, unsigned se_num, size_t offs,
const unsigned char *buff, size_t count)
{
struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
struct sm_info *sm_info = &card->sm_ctx.info;
struct sc_remote_data rdata;
struct iasecc_sm_cmd_update_binary cmd_data;
int rv;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "SM update binary: acl:%X, offs:%i, count:%i", se_num, offs, count);
rv = iasecc_sm_initialize(card, se_num, SM_CMD_FILE_UPDATE);
LOG_TEST_RET(ctx, rv, "iasecc_sm_update_binary() SM INITIALIZE failed");
cmd_data.offs = offs;
cmd_data.count = count;
cmd_data.data = buff;
sm_info->cmd_data = &cmd_data;
sc_remote_data_init(&rdata);
rv = iasecc_sm_cmd(card, &rdata);
LOG_TEST_RET(ctx, rv, "iasecc_sm_update_binary() SM 'UPDATE BINARY' failed");
rv = sm_release (card, &rdata, NULL, 0);
LOG_TEST_RET(ctx, rv, "iasecc_sm_update_binary() SM release failed");
rdata.free(&rdata);
LOG_FUNC_RETURN(ctx, count);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
return SC_ERROR_NOT_SUPPORTED;
#endif
}
int
iasecc_sm_delete_file(struct sc_card *card, unsigned se_num, unsigned int file_id)
{
struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
struct sm_info *sm_info = &card->sm_ctx.info;
struct sc_remote_data rdata;
int rv;
LOG_FUNC_CALLED(ctx);
sc_log(ctx, "SM delete file: SE#:%X, file-id:%X", se_num, file_id);
rv = iasecc_sm_initialize(card, se_num, SM_CMD_FILE_DELETE);
LOG_TEST_RET(ctx, rv, "iasecc_sm_delete_file() SM INITIALIZE failed");
sm_info->cmd_data = (void *)file_id;
sc_remote_data_init(&rdata);
rv = iasecc_sm_cmd(card, &rdata);
LOG_TEST_RET(ctx, rv, "iasecc_sm_delete_file() SM 'FILE DELETE' failed");
rv = sm_release (card, &rdata, NULL, 0);
LOG_TEST_RET(ctx, rv, "iasecc_sm_delete_file() SM release failed");
rdata.free(&rdata);
LOG_FUNC_RETURN(ctx, rv);
#else
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
return SC_ERROR_NOT_SUPPORTED;
#endif
}

View File

@ -302,3 +302,14 @@ sc_crc32
sc_pkcs15_convert_prkey
sc_pkcs15_convert_pubkey
sc_perform_pace
iasecc_sdo_encode_update_field
iasecc_sm_create_file
iasecc_sm_delete_file
iasecc_sm_external_authentication
iasecc_sm_pin_reset
iasecc_sm_pin_verify
iasecc_sm_read_binary
iasecc_sm_rsa_generate
iasecc_sm_rsa_update
iasecc_sm_update_binary
iasecc_sm_sdo_update