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:
parent
947c3291db
commit
71cdef0ed2
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 },
|
||||
|
|
Loading…
Reference in New Issue