New card driver: Italian CNS/CIE (eID)

git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4627 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
ep 2010-08-16 00:56:27 +00:00
parent 947c3291db
commit 71cdef0ed2
12 changed files with 1380 additions and 13 deletions

View File

@ -275,7 +275,7 @@ app default {
# enable_builtin_emulation = no;
#
# List of the builtin pkcs15 emulators to test
# Default: esteid, openpgp, tcos, starcert, infocamere, postecert, actalis, atrust-acos, gemsafeGPK, gemsafeV1, tccardos, PIV-II;
# Default: esteid, openpgp, tcos, starcert, itacns, infocamere, postecert, actalis, atrust-acos, gemsafeGPK, gemsafeV1, tccardos, PIV-II;
# builtin_emulators = openpgp;
# additional settings per driver

View File

@ -37,12 +37,13 @@ libopensc_la_SOURCES = \
card-incrypto34.c card-piv.c card-muscle.c card-acos5.c \
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-javacard.c card-itacns.c \
\
pkcs15-openpgp.c pkcs15-infocamere.c pkcs15-starcert.c \
pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafeGPK.c \
pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c pkcs15-piv.c \
pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c pkcs15-oberthur.c \
pkcs15-itacns.c \
compression.c p15card-helper.c \
libopensc.exports
if WIN32

View File

@ -21,12 +21,13 @@ OBJECTS = \
card-incrypto34.obj card-piv.obj card-muscle.obj card-acos5.obj \
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-javacard.obj card-itacns.obj \
\
pkcs15-openpgp.obj pkcs15-infocamere.obj pkcs15-starcert.obj \
pkcs15-tcos.obj pkcs15-esteid.obj pkcs15-postecert.obj pkcs15-gemsafeGPK.obj \
pkcs15-actalis.obj pkcs15-atrust-acos.obj pkcs15-tccardos.obj pkcs15-piv.obj \
pkcs15-esinit.obj pkcs15-westcos.obj pkcs15-pteid.obj pkcs15-oberthur.obj \
pkcs15-itacns.obj \
compression.obj p15card-helper.obj \
$(TOPDIR)\win32\versioninfo.res

View File

@ -30,6 +30,8 @@
#include "asn1.h"
#include "cardctl.h"
#define MAX_LE 240
static const struct sc_card_operations *iso_ops = NULL;
static struct sc_card_operations cardos_ops;
@ -813,7 +815,9 @@ cardos_compute_signature(sc_card_t *card, const u8 *data, size_t datalen,
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
if (outlen < datalen)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_BUFFER_TOO_SMALL);
outlen = datalen;
if (outlen > MAX_LE)
outlen = MAX_LE;
/* XXX As we don't know what operations are allowed with a
* certain key, let's try RSA_PURE etc. and see which operation

498
src/libopensc/card-itacns.c Normal file
View File

@ -0,0 +1,498 @@
/*
* card-itacns.c: Support for Italian CNS
*
* Copyright (C) 2008-2010 Emanuele Pucciarelli <ep@acm.org>
* Copyright (C) 2005 ST Incard srl, Giuseppe Amato <giuseppe dot amato at st dot com>, <midori3@gmail.com>
* Copyright (C) 2002 Andreas Jellinghaus <aj@dungeon.inka.de>
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
*
* 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
*/
/*
* Specifications for the development of this driver come from:
* http://www.cnipa.gov.it/html/docs/CNS%20Functional%20Specification%201.1.5_11012010.pdf
*/
#include "internal.h"
#include "cardctl.h"
#include "itacns.h"
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#define ITACNS_MAX_PAYLOAD 0xff
static const struct sc_card_operations *default_ops = NULL;
static struct sc_card_operations itacns_ops;
static struct sc_card_driver itacns_drv = {
"Italian CNS",
"itacns",
&itacns_ops,
NULL, 0, NULL
};
/*
* Card matching
*/
/* List of ATR's for "hard" matching. */
static struct sc_atr_table itacns_atrs[] = {
{ "3b:f4:18:00:ff:81:31:80:55:00:31:80:00:c7", NULL, NULL,
SC_CARD_TYPE_ITACNS_CIE_V1, 0, NULL},
{ NULL, NULL, NULL, 0, 0, NULL}
};
/* Output debug info */
#define matchdebug(idx, c) do { \
sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, \
"Matching %x against atr[%d] == %x", c, idx, atr[idx]); \
} while(0);
/* Check that we are not looking at values beyond the ATR's length.
* If we are, then the card does not match. */
#define itacns_atr_l(idx) do {if (idx >= card->atr_len) return 0;} while(0);
/* Match byte exactly and increment index. */
#define itacns_atr_match(idx, c) do { \
itacns_atr_l(idx); \
matchdebug(idx, c); \
if (((u8)atr[idx]) != c) return 0; \
idx++; \
} while(0);
/* Match masked bits and increment index. */
#define itacns_atr_mmatch(idx, c, mask) do { \
itacns_atr_l(idx); \
if ((((u8)atr[idx]) & mask) != c) return 0; \
idx ++; \
} while(0);
/* Macro to access private driver data. */
#define DRVDATA(card) ((itacns_drv_data_t *) card->drv_data)
int itacns_match_cns_card(sc_card_t *card, int i)
{
unsigned char *atr = card->atr;
sc_context_t *ctx;
ctx = card->ctx;
itacns_atr_match(i, 0x01); /* H7 */
i += 2; /* H8, H9 */
itacns_atr_match(i, 'C'); /* H10 */
itacns_atr_match(i, 'N'); /* H11 */
itacns_atr_match(i, 'S'); /* H12 */
/* H13 */
/* Version byte: h.l, h in the high nibble, l in the low nibble. */
if(card->driver) {
DRVDATA(card)->cns_version = atr[i];
}
/* Warn if the version is not 1.0. */
if(atr[i] != 0x10) {
char version[8];
snprintf(version, sizeof(version), "%d.%d", (atr[i] >> 4) & 0x0f, atr[i] & 0x0f);
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "CNS card version %s; no official specifications "
"are published. Proceeding anyway.\n", version);
}
i++;
itacns_atr_match(i, 0x31); /* H14 */
itacns_atr_match(i, 0x80); /* H15 */
card->type = SC_CARD_TYPE_ITACNS_CNS;
return 1;
}
int itacns_match_cie_card(sc_card_t *card, int i)
{
unsigned char *atr = card->atr;
sc_context_t *ctx;
ctx = card->ctx;
itacns_atr_match(i, 0x02); /* H7 */
itacns_atr_match(i, 'I'); /* H8 */
itacns_atr_match(i, 'T'); /* H9 */
itacns_atr_match(i, 'I'); /* H10 */
itacns_atr_match(i, 'D'); /* H11 */
itacns_atr_match(i, 0x20); /* H12 */
itacns_atr_match(i, 0x20); /* H13 */
itacns_atr_match(i, 0x31); /* H14 */
itacns_atr_match(i, 0x80); /* H15 */
card->type = SC_CARD_TYPE_ITACNS_CIE_V2;
return 1;
}
int itacns_match_card(sc_card_t *card)
{
int i = 0, r;
unsigned char *atr = card->atr;
sc_context_t *ctx;
ctx = card->ctx;
/* Try table first */
r = _sc_match_atr(card, itacns_atrs, &card->type);
if(r >= 0) return 1;
/* The ATR was not recognized; try to match it
according to the official specs. */
/* Check ATR up to byte H6 */
itacns_atr_match(i, 0x3b); /* TS */
itacns_atr_mmatch(i, 0x8f, 0x8f); /* T0 */
/* TA1, TB1, TC1 */
if(atr[1] & 0x40) i++;
if(atr[1] & 0x20) i++;
if(atr[1] & 0x10) i++;
/* TD1 */
int td1_idx = i;
itacns_atr_mmatch(i, 0x81, 0x8f);
/* TA2, TB2, TC2 */
if(atr[td1_idx] & 0x40) i++;
if(atr[td1_idx] & 0x20) i++;
if(atr[td1_idx] & 0x10) i++;
/* TD2 */
itacns_atr_match(i, 0x31);
i += 2; /* TA3, TB3 */
itacns_atr_match(i, 0x00); /* H1 */
itacns_atr_match(i, 0x6b); /* H2 */
/* Store interesting data */
if(card->driver) {
DRVDATA(card)->ic_manufacturer_code = card->atr[i];
DRVDATA(card)->mask_manufacturer_code = card->atr[i+1];
DRVDATA(card)->os_version_h = card->atr[i+2];
DRVDATA(card)->os_version_l = card->atr[i+3];
}
i += 4; /* H3, H4, H5, H6 */
/* Check final part. */
if (itacns_match_cns_card(card, i)) return 1;
if (itacns_match_cie_card(card, i)) return 1;
/* No card type was matched. */
return 0;
}
/*
* Initialization and termination
*/
static int itacns_init(sc_card_t *card)
{
SC_FUNC_CALLED(card->ctx, 1);
unsigned long flags;
card->name = "CNS card";
card->cla = 0x00;
card->drv_data = calloc(1, sizeof(itacns_drv_data_t));
/* Match ATR again to find the card data. */
itacns_match_card(card);
/* Set up algorithm info. */
flags = SC_ALGORITHM_NEED_USAGE
| SC_ALGORITHM_RSA_RAW
| SC_ALGORITHM_RSA_HASHES
;
_sc_card_add_rsa_alg(card, 1024, flags, 0);
return 0;
}
static int itacns_finish(struct sc_card *card)
{
if(card->drv_data) {
free(card->drv_data);
}
return 0;
}
/*
* Restore the indicated SE
*/
static int itacns_restore_security_env(sc_card_t *card, int se_num)
{
sc_apdu_t apdu;
int r;
SC_FUNC_CALLED(card->ctx, 1);
/*
* The Italian CNS requires a 0-valued Lc byte at the end of the APDU
* (see paragraph 13.14 of the Functional Specification), but since
* it is invalid, we "cheat" and pretend it's a Le byte.
*
* For this workaround, we must allocate and supply a response buffer,
* even though we know it will not be used (we don't even check it).
*/
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x22, 0xF3, se_num);
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
apdu.le = 0;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Card returned error");
SC_FUNC_RETURN(card->ctx, 1, r);
}
/*
* Set the security context
* Things get a little messy here. It seems you cannot do any
* crypto without a security environment - but there isn't really
* a way to specify the security environment in PKCS15.
* What I'm doing here (for now) is to assume that for a key
* object with ID 0xNN there is always a corresponding SE object
* with the same ID.
* XXX Need to find out how the Aladdin drivers do it.
*/
static int itacns_set_security_env(sc_card_t *card,
const sc_security_env_t *env, int se_num)
{
sc_apdu_t apdu;
u8 data[3];
int key_id, r;
assert(card != NULL && env != NULL);
if (!(env->flags & SC_SEC_ENV_KEY_REF_PRESENT)
|| env->key_ref_len != 1) {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
"No or invalid key reference\n");
return SC_ERROR_INVALID_ARGUMENTS;
}
key_id = env->key_ref[0];
/* CIE v1 cards need to restore security environment 0x30; all the others
so far want 0x03. */
r = itacns_restore_security_env(card,
(card->type == SC_CARD_TYPE_ITACNS_CIE_V1 ? 0x30 : 0x03));
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xF1, 0);
switch (env->operation) {
case SC_SEC_OPERATION_DECIPHER:
apdu.p2 = 0xB8;
break;
case SC_SEC_OPERATION_SIGN:
apdu.p2 = 0xB6;
break;
case SC_SEC_OPERATION_AUTHENTICATE:
apdu.p2 = 0xA4;
break;
default:
return SC_ERROR_INVALID_ARGUMENTS;
}
sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE,
"Setting sec env for key_id=%d\n", key_id);
data[0] = 0x83;
data[1] = 0x01;
data[2] = key_id;
apdu.lc = apdu.datalen = 3;
apdu.data = data;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Card returned error");
SC_FUNC_RETURN(card->ctx, 1, r);
}
/*
* The 0x80 thing tells the card it's okay to search parent
* directories as well for the referenced object.
* This is necessary for some Italian CNS cards, and to be avoided
* for others. Right now it seems that it is only needed with
* cards by STIncard.
*/
static int
itacns_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
int *tries_left)
{
data->flags |= SC_PIN_CMD_NEED_PADDING;
/* Enable backtracking for STIncard cards. */
if(DRVDATA(card)->mask_manufacturer_code == ITACNS_MASKMAN_STINCARD) {
data->pin_reference |= 0x80;
}
/* FIXME: the following values depend on what pin length was
* used when creating the BS objects */
if (data->pin1.max_length == 0)
data->pin1.max_length = 8;
if (data->pin2.max_length == 0)
data->pin2.max_length = 8;
return default_ops->pin_cmd(card, data, tries_left);
}
static int itacns_read_binary(sc_card_t *card,
unsigned int idx, u8 *buf, size_t count,
unsigned long flags)
{
size_t already_read = 0;
size_t requested;
int r;
while(1) {
requested = count - already_read;
if(requested > ITACNS_MAX_PAYLOAD)
requested = ITACNS_MAX_PAYLOAD;
r = default_ops->read_binary(card, idx+already_read,
&buf[already_read], requested, flags);
if(r < 0) return r;
already_read += r;
if (r == 0 || r < requested || already_read == count) {
/* We have finished */
return already_read;
}
}
}
static int itacns_list_files(sc_card_t *card, u8 *buf, size_t buflen) {
struct sc_card_operations *list_ops;
if (DRVDATA(card) && (DRVDATA(card)->mask_manufacturer_code
== ITACNS_MASKMAN_SIEMENS)) {
list_ops = sc_get_cardos_driver()->ops;
} else {
list_ops = sc_get_incrypto34_driver()->ops;
}
return list_ops->list_files(card, buf, buflen);
}
static void add_acl_entry(sc_file_t *file, int op, u8 byte)
{
unsigned int method, key_ref = SC_AC_KEY_REF_NONE;
switch (byte) {
case 0x00:
method = SC_AC_NONE;
break;
case 0xFF:
case 0x66:
method = SC_AC_NEVER;
break;
default:
if (byte > 0x1F) {
method = SC_AC_UNKNOWN;
} else {
method = SC_AC_CHV;
key_ref = byte;
}
break;
}
sc_file_add_acl_entry(file, op, method, key_ref);
}
static const int df_acl[9] = {
-1, /* LCYCLE (life cycle change) */
SC_AC_OP_UPDATE, /* UPDATE Objects */
SC_AC_OP_WRITE, /* APPEND Objects */
SC_AC_OP_INVALIDATE, /* DF */
SC_AC_OP_REHABILITATE, /* DF */
SC_AC_OP_DELETE, /* DF */
SC_AC_OP_WRITE, /* ADMIN DF */
SC_AC_OP_CREATE, /* Files */
-1 /* Reserved */
};
static const int ef_acl[9] = {
SC_AC_OP_READ, /* Data */
SC_AC_OP_UPDATE, /* Data (write file content) */
SC_AC_OP_WRITE, /* */
SC_AC_OP_INVALIDATE, /* EF */
SC_AC_OP_REHABILITATE, /* EF */
SC_AC_OP_ERASE, /* (delete) EF */
/* XXX: ADMIN should be an ACL type of its own, or mapped
* to erase */
SC_AC_OP_ERASE, /* ADMIN EF (modify meta information?) */
-1, /* INC (-> cylic fixed files) */
-1 /* DEC */
};
static void parse_sec_attr(sc_file_t *file, const u8 *buf, size_t len)
{
size_t i;
const int *idx;
idx = (file->type == SC_FILE_TYPE_DF) ? df_acl : ef_acl;
/* acl defaults to 0xFF if unspecified */
for (i = 0; i < 9; i++) {
if (idx[i] != -1) {
add_acl_entry(file, idx[i],
(u8)((i < len) ? buf[i] : 0xFF));
}
}
}
static int itacns_select_file(sc_card_t *card,
const sc_path_t *in_path,
sc_file_t **file)
{
int r;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
r = default_ops->select_file(card, in_path, file);
if (r >= 0 && file) {
parse_sec_attr((*file), (*file)->sec_attr,
(*file)->sec_attr_len);
}
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
}
static struct sc_card_driver * sc_get_driver(void)
{
if (!default_ops)
default_ops = sc_get_iso7816_driver()->ops;
itacns_ops = *default_ops;
itacns_ops.match_card = itacns_match_card;
itacns_ops.init = itacns_init;
itacns_ops.finish = itacns_finish;
itacns_ops.set_security_env = itacns_set_security_env;
itacns_ops.restore_security_env = itacns_restore_security_env;
itacns_ops.pin_cmd = itacns_pin_cmd;
itacns_ops.read_binary = itacns_read_binary;
itacns_ops.list_files = itacns_list_files;
itacns_ops.select_file = itacns_select_file;
return &itacns_drv;
}
struct sc_card_driver * sc_get_itacns_driver(void)
{
return sc_get_driver();
}

View File

@ -164,9 +164,17 @@ enum {
SC_CARD_TYPE_IAS_BASE = 22000,
SC_CARD_TYPE_IAS_PTEID,
/* Italian CNS cards */
SC_CARD_TYPE_ITACNS_BASE = 23000,
SC_CARD_TYPE_ITACNS_GENERIC,
SC_CARD_TYPE_ITACNS_CNS,
SC_CARD_TYPE_ITACNS_CIE_V2,
SC_CARD_TYPE_ITACNS_CIE_V1,
/* Generic JavaCards without supported applet */
SC_CARD_TYPE_JAVACARD_BASE = 23000,
SC_CARD_TYPE_JAVACARD_BASE = 24000,
SC_CARD_TYPE_JAVACARD,
};
extern sc_card_driver_t *sc_get_default_driver(void);
@ -198,6 +206,7 @@ extern sc_card_driver_t *sc_get_westcos_driver(void);
extern sc_card_driver_t *sc_get_myeid_driver(void);
extern sc_card_driver_t *sc_get_ias_driver(void);
extern sc_card_driver_t *sc_get_javacard_driver(void);
extern sc_card_driver_t *sc_get_itacns_driver(void);
#ifdef __cplusplus
}

View File

@ -93,7 +93,7 @@ static const struct _sc_driver_entry internal_card_drivers[] = {
#endif
/* javacard without supported applet - last before default */
{ "javacard", (void *(*)(void)) sc_get_javacard_driver },
{ "itacns", (void *(*)(void)) sc_get_itacns_driver },
/* The default driver should be last, as it handles all the
* unrecognized cards. */
{ "default", (void *(*)(void)) sc_get_default_driver },

View File

@ -520,6 +520,23 @@ static int iso7816_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
return 0;
}
/* This belongs to ETSI TS 101 206-3, not to ISO 7816. */
static int iso7816_give_random(sc_card_t *card, u8 *rnd, size_t len)
{
int r;
sc_apdu_t apdu;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT,
0x86, 0x00, 0x00);
apdu.cla = 0x80;
apdu.data = rnd;
apdu.lc = apdu.datalen = len;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
return sc_check_sw(card, apdu.sw1, apdu.sw2);
}
static int iso7816_construct_fci(sc_card_t *card, const sc_file_t *file,
u8 *out, size_t *outlen)
{
@ -1001,6 +1018,7 @@ static struct sc_card_operations iso_ops = {
iso7816_select_file,
iso7816_get_response,
iso7816_get_challenge,
iso7816_give_random,
NULL, /* verify */
NULL, /* logout */
iso7816_restore_security_env,

15
src/libopensc/itacns.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef _OPENSC_ITACNS_H
#define _OPENSC_ITACNS_H
typedef struct {
u8 ic_manufacturer_code;
u8 mask_manufacturer_code;
u8 os_version_h;
u8 os_version_l;
u8 cns_version;
} itacns_drv_data_t;
#define ITACNS_MASKMAN_SIEMENS 0x08
#define ITACNS_MASKMAN_STINCARD 0x09
#endif /* _OPENSC_ITACNS_H */

View File

@ -441,6 +441,8 @@ struct sc_card_operations {
struct sc_file **file_out);
int (*get_response)(struct sc_card *card, size_t *count, u8 *buf);
int (*get_challenge)(struct sc_card *card, u8 * buf, size_t count);
/* This belongs to ETSI TS 101 206-3, not to ISO 7816. */
int (*give_random)(struct sc_card *card, u8 * buf, size_t count);
/*
* ISO 7816-8 functions

View File

@ -0,0 +1,815 @@
/*
* PKCS15 emulation layer for Italian CNS.
*
* Copyright (C) 2008, Emanuele Pucciarelli <ep@acm.org>
* Many snippets have been taken out from other PKCS15 emulation layer
* modules in this directory; their copyright is their authors'.
*
* 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
*/
/*
* Specifications for the development of this driver come from:
* http://www.servizidemografici.interno.it/sitoCNSD/documentazioneRicerca.do?metodo=contenutoDocumento&servizio=documentazione&ID_DOCUMENTO=1043
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "pkcs15.h"
#include "log.h"
#include "cards.h"
#include "itacns.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "common/compat_strlcpy.h"
#ifdef ENABLE_OPENSSL
#include <openssl/x509v3.h>
#endif
int sc_pkcs15emu_itacns_init_ex(sc_pkcs15_card_t *,
sc_pkcs15emu_opt_t *);
static const char path_serial[] = "10001003";
/* Manufacturers */
char * itacns_mask_manufacturers[] = {
"Unknown",
"Kaitech",
"Gemplus",
"Ghirlanda",
"Giesecke & Devrient",
"Oberthur Card Systems",
"Orga",
"Axalto",
"Siemens",
"STIncard",
"GEP",
"EPS Corp",
"Athena"
};
char * iso7816_ic_manufacturers[] = {
"Unknown",
"Motorola",
"STMicroelectronics",
"Hitachi",
"Philips Semiconductors",
"Siemens",
"Cylinc",
"Texas Instruments",
"Fujitsu",
"Matsushita",
"NEC",
"Oki",
"Toshiba",
"Mitsubishi",
"Samsung",
"Hyundai",
"LG"
};
/* Data files */
static const struct {
char *label;
char *path;
int cie_only;
} itacns_data_files[] = {
{ "EF_DatiProcessore", "3F0010001002", 0 },
{ "EF_IDCarta", "3F0010001003", 0 },
{ "EF_DatiSistema", "3F0010001004", 1 },
{ "EF_DatiPersonali", "3F0011001102", 0 },
{ "EF_DatiPersonali_Annotazioni", "3F0011001103", 1 },
{ "EF_Impronte", "3F0011001104", 1 },
{ "EF_Foto", "3F0011001104", 1 },
{ "EF_DatiPersonaliAggiuntivi", "3F0012001201", 0 },
{ "EF_MemoriaResidua", "3F0012001202", 0 },
{ "EF_ServiziInstallati", "3F0012001203", 0 },
{ "EF_INST_FILE", "3F0012004142", 0 },
{ "EF_CardStatus", "3F003F02", 0 },
{ "EF_GDO", "3F002F02", 0 },
{ "EF_RootInstFile", "3F000405", 0 }
};
/*
* Utility functions
*/
static void set_string(char **strp, const char *value)
{
if (*strp)
free(*strp);
*strp = value ? strdup(value) : NULL;
}
static int loadFile(const sc_pkcs15_card_t *p15card, const sc_path_t *path,
u8 *buf, const size_t buflen)
{
SC_FUNC_CALLED(p15card->card->ctx, 1);
int sc_res;
sc_res = sc_select_file(p15card->card, path, NULL);
if(sc_res != SC_SUCCESS)
return sc_res;
sc_res = sc_read_binary(p15card->card, 0, buf, buflen, 0);
return sc_res;
}
/*
* The following functions add objects to the card emulator.
*/
static int itacns_add_cert(sc_pkcs15_card_t *p15card,
int type, int authority, const sc_path_t *path,
const sc_pkcs15_id_t *id, const char *label, int obj_flags,
int *ext_info_ok, int *key_usage, int *x_key_usage)
{
SC_FUNC_CALLED(p15card->card->ctx, 1);
int r;
*ext_info_ok = 0;
/* const char *label = "Certificate"; */
sc_pkcs15_cert_info_t info;
sc_pkcs15_object_t obj;
memset(&info, 0, sizeof(info));
memset(&obj, 0, sizeof(obj));
info.id = *id;
info.authority = authority;
if (path)
info.path = *path;
strlcpy(obj.label, label, sizeof(obj.label));
obj.flags = obj_flags;
r = sc_pkcs15emu_add_x509_cert(p15card, &obj, &info);
SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r,
"Could not add X.509 certificate");
/* If we have OpenSSL, read keyUsage */
#ifdef ENABLE_OPENSSL
X509 *x509;
sc_pkcs15_cert_t *cert;
r = sc_pkcs15_read_certificate(p15card, &info, &cert);
SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r,
"Could not read X.509 certificate");
const u8 *throwaway = cert->data;
x509 = d2i_X509(NULL, &throwaway, cert->data_len);
sc_pkcs15_free_certificate(cert);
if (!x509) return SC_SUCCESS;
X509_check_purpose(x509, -1, 0);
if(x509->ex_flags & EXFLAG_KUSAGE) {
*ext_info_ok = 1;
*key_usage = x509->ex_kusage;
*x_key_usage = x509->ex_xkusage;
}
OPENSSL_free(x509);
return SC_SUCCESS;
#else /* ENABLE_OPENSSL */
return SC_SUCCESS;
#endif /* ENABLE_OPENSSL */
}
static int itacns_add_pubkey(sc_pkcs15_card_t *p15card,
const sc_path_t *path, const sc_pkcs15_id_t *id, const char *label,
int usage, int ref, int obj_flags, int *modulus_len_out)
{
SC_FUNC_CALLED(p15card->card->ctx, 1);
int r;
sc_pkcs15_pubkey_info_t info;
sc_pkcs15_object_t obj;
memset(&info, 0, sizeof(info));
memset(&obj, 0, sizeof(obj));
info.id = *id;
if (path)
info.path = *path;
info.usage = usage;
info.key_reference = ref;
strlcpy(obj.label, label, sizeof(obj.label));
obj.flags = obj_flags;
/*
* This is hard-coded, unless unforeseen versions of the CNS
* turn up sometime.
*/
info.modulus_length = 1024;
*modulus_len_out = info.modulus_length;
r = sc_pkcs15emu_add_rsa_pubkey(p15card, &obj, &info);
SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r,
"Could not add pub key");
return r;
}
static int itacns_add_prkey(sc_pkcs15_card_t *p15card,
const sc_pkcs15_id_t *id,
const char *label,
int type, unsigned int modulus_length, int usage,
int algo_flags, const sc_path_t *path, int ref,
const sc_pkcs15_id_t *auth_id, int obj_flags)
{
SC_FUNC_CALLED(p15card->card->ctx, 1);
sc_pkcs15_prkey_info_t info;
sc_pkcs15_object_t obj;
memset(&info, 0, sizeof(info));
memset(&obj, 0, sizeof(obj));
info.id = *id;
info.modulus_length = modulus_length;
info.usage = usage;
info.native = 1;
info.key_reference = ref;
info.access_flags =
SC_PKCS15_PRKEY_ACCESS_SENSITIVE
| SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE
| SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE
| SC_PKCS15_PRKEY_ACCESS_LOCAL;
if (path)
info.path = *path;
obj.flags = obj_flags;
strlcpy(obj.label, label, sizeof(obj.label));
if (auth_id != NULL)
obj.auth_id = *auth_id;
return sc_pkcs15emu_add_rsa_prkey(p15card, &obj, &info);
}
static int itacns_add_pin(sc_pkcs15_card_t *p15card,
char *label,
int id,
int auth_id,
int reference,
sc_path_t *path,
int flags)
{
SC_FUNC_CALLED(p15card->card->ctx, 1);
struct sc_pkcs15_pin_info pin_info;
struct sc_pkcs15_object pin_obj;
memset(&pin_info, 0, sizeof(pin_info));
pin_info.auth_id.len = 1;
pin_info.auth_id.value[0] = id;
pin_info.reference = reference;
pin_info.flags = flags;
pin_info.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
pin_info.min_length = 5;
pin_info.stored_length = 8;
pin_info.max_length = 8;
pin_info.pad_char = 0xff;
if(path)
pin_info.path = *path;
memset(&pin_obj, 0, sizeof(pin_obj));
strlcpy(pin_obj.label, label, sizeof(pin_obj.label));
pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE |
(auth_id ? SC_PKCS15_CO_FLAG_MODIFIABLE : 0);
if (auth_id) {
pin_obj.auth_id.len = 1;
pin_obj.auth_id.value[0] = auth_id;
} else
pin_obj.auth_id.len = 0;
return sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
}
static int hextoint(unsigned char *src, int len)
{
char hex[16];
if(len >= sizeof(hex))
return -1;
strncpy(hex, src, len+1);
hex[len] = '\0';
char *end;
int res = strtol(hex, &end, 0x10);
if(end != (char*)&hex[len])
return -1;
return res;
}
static int get_name_from_EF_DatiPersonali(unsigned char *EFdata,
char name[], int name_len)
{
/*
* Bytes 0-5 contain the ASCII encoding of the following TLV
* strcture's total size, in base 16.
*/
const unsigned int EF_personaldata_maxlen = 400;
const tlv_length_size = 6;
unsigned char *file = &EFdata[tlv_length_size];
int file_size = hextoint(EFdata, tlv_length_size);
if(file_size < 0)
return -1;
/*
* This shouldn't happen, but let us be protected against wrong
* or malicious cards
*/
if(file_size > EF_personaldata_maxlen - tlv_length_size)
file_size = EF_personaldata_maxlen - tlv_length_size;
enum {
f_issuer_code = 0,
f_issuing_date,
f_expiry_date,
f_last_name,
f_first_name,
f_birth_date,
f_sex,
f_height,
f_codice_fiscale,
f_citizenship_code,
f_birth_township_code,
f_birth_country,
f_birth_certificate,
f_residence_township_code,
f_residence_address,
f_expat_notes
};
struct {
int len;
char value[256];
} fields[f_first_name+1];
memset(fields, 0, sizeof(fields));
/* Read the fields up to f_first_name */
int i=0; /* offset inside the file */
int f; /* field number */
for(f=0; f<f_first_name+1; f++) {
// Don't read beyond the allocated buffer
if(i > file_size)
return -1;
int field_size = hextoint(&file[i], 2);
if((field_size < 0) || (field_size+i > file_size))
return -1;
i += 2;
if(field_size >= sizeof(fields[f].value))
return -1;
fields[f].len = field_size;
strncpy(fields[f].value, &file[i], field_size);
fields[f].value[field_size] = '\0';
i += field_size;
}
if (fields[f_first_name].len + fields[f_last_name].len + 1 >= name_len)
return -1;
snprintf(name, name_len, "%s %s",
fields[f_first_name].value, fields[f_last_name].value);
return 0;
}
static int itacns_add_data_files(sc_pkcs15_card_t *p15card)
{
const size_t list_size =
sizeof(itacns_data_files)/sizeof(itacns_data_files[0]);
int i;
int r;
for(i=0; i < list_size; i++) {
if(itacns_data_files[i].cie_only &&
p15card->card->type != SC_CARD_TYPE_ITACNS_CIE_V2)
continue;
sc_path_t path;
sc_format_path(itacns_data_files[i].path, &path);
sc_pkcs15_data_info_t data;
sc_pkcs15_object_t obj;
memset(&data, 0, sizeof(data));
memset(&obj, 0, sizeof(obj));
strlcpy(data.app_label, itacns_data_files[i].label,
sizeof(data.app_label));
strlcpy(obj.label, itacns_data_files[i].label,
sizeof(obj.label));
data.path = path;
r = sc_pkcs15emu_add_data_object(p15card, &obj, &data);
}
/*
* If we got this far, we can read the Personal Data file and glean
* the user's full name. Thus we can use it to put together a
* user-friendlier card name.
*/
sc_pkcs15_data_t *p15_personaldata = NULL;
sc_pkcs15_data_info_t dinfo;
memset(&dinfo, 0, sizeof(dinfo));
strcpy(dinfo.app_label, "EF_DatiPersonali");
// Find EF_DatiPersonali
struct sc_pkcs15_object *objs[32];
int rv = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_DATA_OBJECT,
objs, 32);
if(rv < 0) {
sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL,
"Data enumeration failed");
return SC_SUCCESS;
}
struct sc_pkcs15_data_info *cinfo;
for(i=0; i<32; i++) {
cinfo = (struct sc_pkcs15_data_info *) objs[i]->data;
if(!strcmp("EF_DatiPersonali", objs[i]->label))
break;
}
if(i>=32) {
sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL,
"Could not find EF_DatiPersonali: "
"keeping generic card name");
return SC_SUCCESS;
}
rv = sc_pkcs15_read_data_object(p15card, cinfo, &p15_personaldata);
if (rv) {
sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL,
"Could not read EF_DatiPersonali: "
"keeping generic card name");
}
char fullname[160];
if(get_name_from_EF_DatiPersonali(p15_personaldata->data, fullname,
sizeof(fullname))) {
sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL,
"Could not parse EF_DatiPersonali: "
"keeping generic card name");
return SC_SUCCESS;
}
set_string(&p15card->label, fullname);
sc_pkcs15_free_data_object(p15_personaldata);
return SC_SUCCESS;
}
static int itacns_add_keyset(sc_pkcs15_card_t *p15card,
const char *label, int sec_env, sc_pkcs15_id_t *cert_id,
const char *pubkey_path, const char *prkey_path,
unsigned int pubkey_usage_flags, unsigned int prkey_usage_flags,
u8 pin_ref, int needs_enc)
{
int r;
sc_path_t path;
/* This is hard-coded, for the time being. */
int modulus_length = 1024;
/* Access flags; these depend on whether the private keys use PSO_ENC
or PSO_CDS for signing. */
const int enc_algo_flags = SC_ALGORITHM_NEED_USAGE
| SC_ALGORITHM_RSA_RAW
| SC_ALGORITHM_RSA_HASH_NONE;
const int cds_algo_flags = SC_ALGORITHM_NEED_USAGE
| SC_ALGORITHM_RSA_PAD_PKCS1
| SC_ALGORITHM_RSA_HASH_NONE;
/* Public key; not really needed */
/* FIXME: set usage according to the certificate. */
if (pubkey_path) {
sc_format_path(pubkey_path, &path);
r = itacns_add_pubkey(p15card, &path, cert_id, label,
pubkey_usage_flags, sec_env, 0, &modulus_length);
SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r,
"Could not add public key");
}
/*
* FIXME: usage should be inferred from the X.509 certificate, and not
* from whether the key needs Secure Messaging.
*/
sc_path_t *private_path = NULL;
if (prkey_path) {
sc_format_path(prkey_path, &path);
private_path = &path;
}
r = itacns_add_prkey(p15card, cert_id, label, SC_PKCS15_TYPE_PRKEY_RSA,
modulus_length,
prkey_usage_flags,
(needs_enc ? enc_algo_flags : cds_algo_flags),
private_path, sec_env, cert_id, SC_PKCS15_CO_FLAG_PRIVATE);
SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r,
"Could not add private key");
/* PIN and PUK */
char pinlabel[16];
strncpy(pinlabel, "PIN ", sizeof(pinlabel));
strncat(pinlabel, label, sizeof(pinlabel));
/* We are making up ID 0x90+ to link the PIN and the PUK. */
int fake_puk_authid = 0x90 + pin_ref;
int pin_flags = SC_PKCS15_PIN_FLAG_CASE_SENSITIVE
| SC_PKCS15_PIN_FLAG_INITIALIZED;
r = itacns_add_pin(p15card, pinlabel, sec_env, fake_puk_authid, pin_ref,
private_path, pin_flags);
SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r,
"Could not add PIN");
strncpy(pinlabel, "PUK ", sizeof(pinlabel));
strncat(pinlabel, label, sizeof(pinlabel));
/*
* Looking at pkcs15-tcos.c and pkcs15-framework.c, it seems that the
* right thing to do here is to define a PUK as a SO PIN. Can anybody
* comment on this?
*/
pin_flags |= SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN
| SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED;
r = itacns_add_pin(p15card, pinlabel, fake_puk_authid, 0, pin_ref+1,
private_path, pin_flags);
SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r,
"Could not add PUK");
return 0;
}
/*
* itacns_check_and_add_keyset() checks for the existence and correctness
* of an X.509 certificate. If it is all right, it adds the related keys;
* otherwise it aborts.
*/
static int itacns_check_and_add_keyset(sc_pkcs15_card_t *p15card,
const char *label, int sec_env, size_t cert_offset,
const char *cert_path, const char *pubkey_path, const char *prkey_path,
u8 pin_ref, int needs_enc, int *found_certificates)
{
int r;
sc_path_t path;
sc_pkcs15_id_t cert_id;
cert_id.len = 1;
cert_id.value[0] = sec_env;
*found_certificates = 0;
/* Usage flags */
const int auth_pubkey_usage_flags = SC_PKCS15_PRKEY_USAGE_ENCRYPT
| SC_PKCS15_PRKEY_USAGE_DECRYPT
| SC_PKCS15_PRKEY_USAGE_WRAP
| SC_PKCS15_PRKEY_USAGE_VERIFY;
const int auth_prkey_usage_flags = SC_PKCS15_PRKEY_USAGE_DECRYPT
| SC_PKCS15_PRKEY_USAGE_UNWRAP
| SC_PKCS15_PRKEY_USAGE_SIGN;
const int sig_pubkey_usage_flags = SC_PKCS15_PRKEY_USAGE_VERIFY;
const int sig_prkey_usage_flags = SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
/* Certificate */
if (!cert_path) {
sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL,
"We cannot use keys without a matching certificate");
return SC_ERROR_NOT_SUPPORTED;
}
sc_format_path(cert_path, &path);
r = sc_select_file(p15card->card, &path, NULL);
if (r == SC_ERROR_FILE_NOT_FOUND)
return 0;
if (r != SC_SUCCESS) {
sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL,
"Could not find certificate for %s", label);
return r;
}
/*
* Infocamere 1204 (and others?) store a more complex structure. We
* are going to read the first bytes to guess its length, and invoke
* itacns_add_cert so that it only reads the certificate.
*/
if (cert_offset) {
u8 certlen[3];
r = loadFile(p15card, &path, certlen, sizeof(certlen));
SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r,
"Could not read certificate file");
path.index = cert_offset;
path.count = (certlen[1] << 8) + certlen[2];
/* If those bytes are 00, then we are probably dealign with an
* empty file. */
if (path.count == 0)
return 0;
}
int ext_info_ok;
int ku, xku;
r = itacns_add_cert(p15card, SC_PKCS15_TYPE_CERT_X509, 0,
&path, &cert_id, label, 0, &ext_info_ok, &ku, &xku);
if (r == SC_ERROR_INVALID_ASN1_OBJECT)
return 0;
SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r,
"Could not add certificate");
(*found_certificates)++;
/* Set usage flags */
int pubkey_usage_flags = 0, prkey_usage_flags = 0;
if(ext_info_ok) {
#ifdef ENABLE_OPENSSL
if (ku & KU_DIGITAL_SIGNATURE) {
pubkey_usage_flags |= SC_PKCS15_PRKEY_USAGE_VERIFY;
prkey_usage_flags |= SC_PKCS15_PRKEY_USAGE_SIGN;
}
if (ku & KU_NON_REPUDIATION) {
pubkey_usage_flags |= SC_PKCS15_PRKEY_USAGE_VERIFY;
prkey_usage_flags |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
}
if (ku & KU_KEY_ENCIPHERMENT || ku & KU_KEY_AGREEMENT
|| xku & XKU_SSL_CLIENT) {
pubkey_usage_flags |= SC_PKCS15_PRKEY_USAGE_WRAP;
prkey_usage_flags |= SC_PKCS15_PRKEY_USAGE_UNWRAP;
}
if (ku & KU_DATA_ENCIPHERMENT || xku & XKU_SMIME) {
pubkey_usage_flags |= SC_PKCS15_PRKEY_USAGE_ENCRYPT;
prkey_usage_flags |= SC_PKCS15_PRKEY_USAGE_DECRYPT;
}
#else /* ENABLE_OPENSSL */
sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL,
"Extended certificate info retrieved without OpenSSL. "
"How is this possible?");
return SC_ERROR_INTERNAL;
#endif /* ENABLE_OPENSSL */
} else {
/* Certificate info not retrieved; fall back onto defaults */
pubkey_usage_flags =
SC_PKCS15_PRKEY_USAGE_VERIFY
| SC_PKCS15_PRKEY_USAGE_WRAP;
prkey_usage_flags =
SC_PKCS15_PRKEY_USAGE_SIGN
| SC_PKCS15_PRKEY_USAGE_UNWRAP;
}
r = itacns_add_keyset(p15card, label, sec_env, &cert_id,
pubkey_path, prkey_path, pubkey_usage_flags, prkey_usage_flags,
pin_ref, needs_enc);
SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r,
"Could not add keys for this certificate");
return r;
}
/* Initialization. */
static int itacns_init(sc_pkcs15_card_t *p15card)
{
SC_FUNC_CALLED(p15card->card->ctx, 1);
int r;
sc_path_t path;
int certificate_count = 0;
int found_certs;
set_string(&p15card->label, p15card->card->name);
if(p15card->card->drv_data) {
int mask_code, ic_code;
char buffer[256];
itacns_drv_data_t *data =
(itacns_drv_data_t*) p15card->card->drv_data;
mask_code = data->mask_manufacturer_code;
if (mask_code >= sizeof(itacns_mask_manufacturers))
mask_code = 0;
ic_code = data->ic_manufacturer_code;
if (ic_code >= sizeof(iso7816_ic_manufacturers))
ic_code = 0;
snprintf(buffer, sizeof(buffer), "IC: %s; mask: %s",
iso7816_ic_manufacturers[ic_code],
itacns_mask_manufacturers[mask_code]);
set_string(&p15card->manufacturer_id, buffer);
p15card->version = (data->os_version_h << 8
| data->os_version_l);
}
/* Read and set serial */
u8 serial[17];
{
int bytes;
sc_format_path(path_serial, &path);
bytes = loadFile(p15card, &path, serial, 16);
if (bytes < 0) return bytes;
if (bytes > 16) return -1;
serial[bytes] = '\0';
set_string(&p15card->serial_number, (char*)serial);
}
/* Is the card a CIE v1? */
int card_is_cie_v1 =
(p15card->card->type == SC_CARD_TYPE_ITACNS_CIE_V1)
|| (p15card->card->type == SC_CARD_TYPE_CARDOS_CIE_V1);
int cns0_secenv = (card_is_cie_v1 ? 0x31 : 0x01);
/* If it's a Siemens CIE v1 card, set algo flags accordingly. */
if (card_is_cie_v1) {
int i;
for (i = 0; i < p15card->card->algorithm_count; i++) {
sc_algorithm_info_t *info =
&p15card->card->algorithms[i];
if (info->algorithm != SC_ALGORITHM_RSA)
continue;
info->flags &= ~(SC_ALGORITHM_RSA_RAW
| SC_ALGORITHM_RSA_HASH_NONE);
info->flags |= (SC_ALGORITHM_RSA_PAD_PKCS1
| SC_ALGORITHM_RSA_HASHES);
}
}
/* Data files */
r = itacns_add_data_files(p15card);
SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r,
"Could not add data files");
/*** Certificate and keys. ***/
/* Standard CNS */
r = itacns_check_and_add_keyset(p15card, "CNS0", cns0_secenv,
0, "3F0011001101", "3F003F01", NULL,
0x10, !card_is_cie_v1, &found_certs);
SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r,
"Could not add CNS0");
certificate_count += found_certs;
/* Infocamere 1204 */
r = itacns_check_and_add_keyset(p15card, "CNS01", 0x21,
5, "3F002FFF8228", NULL, "3F002FFF0000",
0x10, 1, &found_certs);
SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r,
"Could not add CNS01");
certificate_count += found_certs;
/* Digital signature */
r = itacns_check_and_add_keyset(p15card, "CNS1", 0x10,
0, "3F0014009010", "3F00140081108010", "3F0014008110",
0x1a, 0, &found_certs);
SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r,
"Could not add CNS1");
certificate_count += found_certs;
/* Did we find anything? */
if (certificate_count == 0)
sc_debug(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE,
"Warning: no certificates found!");
/* Back to Master File */
sc_format_path("3F00", &path);
r = sc_select_file(p15card->card, &path, NULL);
SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r,
"Could not select master file again");
return r;
}
int sc_pkcs15emu_itacns_init_ex(sc_pkcs15_card_t *p15card,
sc_pkcs15emu_opt_t *opts)
{
sc_card_t *card = p15card->card;
SC_FUNC_CALLED(card->ctx, 1);
/* Check card */
if (!(opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK)) {
if (! (
(card->type > SC_CARD_TYPE_ITACNS_BASE &&
card->type < SC_CARD_TYPE_ITACNS_BASE + 1000)
|| card->type == SC_CARD_TYPE_CARDOS_CIE_V1)
)
return SC_ERROR_WRONG_CARD;
}
/* Init card */
return itacns_init(p15card);
}

View File

@ -55,13 +55,16 @@ extern int sc_pkcs15emu_actalis_init_ex(sc_pkcs15_card_t *p15card,
sc_pkcs15emu_opt_t *opts);
extern int sc_pkcs15emu_atrust_acos_init_ex(sc_pkcs15_card_t *p15card,
sc_pkcs15emu_opt_t *opts);
extern int sc_pkcs15emu_tccardos_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
extern int sc_pkcs15emu_entersafe_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
extern int sc_pkcs15emu_pteid_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
extern int sc_pkcs15emu_oberthur_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
extern int sc_pkcs15emu_tccardos_init_ex(sc_pkcs15_card_t *,
sc_pkcs15emu_opt_t *);
extern int sc_pkcs15emu_entersafe_init_ex(sc_pkcs15_card_t *,
sc_pkcs15emu_opt_t *);
extern int sc_pkcs15emu_pteid_init_ex(sc_pkcs15_card_t *,
sc_pkcs15emu_opt_t *);
extern int sc_pkcs15emu_oberthur_init_ex(sc_pkcs15_card_t *,
sc_pkcs15emu_opt_t *);
extern int sc_pkcs15emu_itacns_init_ex(sc_pkcs15_card_t *,
sc_pkcs15emu_opt_t *);
static struct {
const char * name;
@ -73,6 +76,7 @@ static struct {
{ "starcert", sc_pkcs15emu_starcert_init_ex },
{ "tcos", sc_pkcs15emu_tcos_init_ex },
{ "esteid", sc_pkcs15emu_esteid_init_ex },
{ "itacns", sc_pkcs15emu_itacns_init_ex },
{ "postecert", sc_pkcs15emu_postecert_init_ex },
{ "PIV-II", sc_pkcs15emu_piv_init_ex },
{ "gemsafeGPK", sc_pkcs15emu_gemsafeGPK_init_ex },