diff --git a/etc/opensc.conf.in b/etc/opensc.conf.in
index 3d00b1b..c432e21 100644
--- a/etc/opensc.conf.in
+++ b/etc/opensc.conf.in
@@ -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
diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am
index 8837952..dfe8ef0 100644
--- a/src/libopensc/Makefile.am
+++ b/src/libopensc/Makefile.am
@@ -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
diff --git a/src/libopensc/Makefile.mak b/src/libopensc/Makefile.mak
index e93ac0c..230ef76 100644
--- a/src/libopensc/Makefile.mak
+++ b/src/libopensc/Makefile.mak
@@ -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
 
diff --git a/src/libopensc/card-cardos.c b/src/libopensc/card-cardos.c
index 555eabe..f6cff9f 100644
--- a/src/libopensc/card-cardos.c
+++ b/src/libopensc/card-cardos.c
@@ -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
diff --git a/src/libopensc/card-itacns.c b/src/libopensc/card-itacns.c
new file mode 100644
index 0000000..ff233f3
--- /dev/null
+++ b/src/libopensc/card-itacns.c
@@ -0,0 +1,487 @@
+/*
+ * card-itacns.c: Support for Italian CNS
+ *
+ * Copyright (C) 2008  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 = {
+	"Carta Nazionale dei Servizi",
+	"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 (and we do not 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();
+}
diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h
index b5d8bda..843a762 100644
--- a/src/libopensc/cards.h
+++ b/src/libopensc/cards.h
@@ -167,6 +167,14 @@ enum {
 	/* Generic JavaCards without supported applet */
 	SC_CARD_TYPE_JAVACARD_BASE = 23000,
 	SC_CARD_TYPE_JAVACARD,
+
+	/* Italian CNS cards */
+	SC_CARD_TYPE_ITACNS_BASE = 24000,
+	SC_CARD_TYPE_ITACNS_GENERIC,
+	SC_CARD_TYPE_ITACNS_CNS,
+	SC_CARD_TYPE_ITACNS_CIE_V2,
+	SC_CARD_TYPE_ITACNS_CIE_V1,
+
 };
 
 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
 }
diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c
index 4158d87..becd065 100644
--- a/src/libopensc/ctx.c
+++ b/src/libopensc/ctx.c
@@ -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 },
diff --git a/src/libopensc/iso7816.c b/src/libopensc/iso7816.c
index 9d826ad..52d10af 100644
--- a/src/libopensc/iso7816.c
+++ b/src/libopensc/iso7816.c
@@ -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,
diff --git a/src/libopensc/itacns.h b/src/libopensc/itacns.h
new file mode 100644
index 0000000..742627b
--- /dev/null
+++ b/src/libopensc/itacns.h
@@ -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 */
diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h
index 7d95488..796cef0 100644
--- a/src/libopensc/opensc.h
+++ b/src/libopensc/opensc.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
diff --git a/src/libopensc/pkcs15-itacns.c b/src/libopensc/pkcs15-itacns.c
new file mode 100644
index 0000000..83fd6b0
--- /dev/null
+++ b/src/libopensc/pkcs15-itacns.c
@@ -0,0 +1,638 @@
+/*
+ * 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";
+static const char path_personal_data[] = "11001102";
+
+/* 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 weird 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 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);
+	}
+	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);
+		}
+	}
+
+	/*** 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!");
+
+	/* Data files */
+	r = itacns_add_data_files(p15card);
+	SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r, "Could not add data files");
+
+	/* 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);
+}
diff --git a/src/libopensc/pkcs15-syn.c b/src/libopensc/pkcs15-syn.c
index d107cba..81bf45e 100644
--- a/src/libopensc/pkcs15-syn.c
+++ b/src/libopensc/pkcs15-syn.c
@@ -63,6 +63,8 @@ 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;
 	int			(*handler)(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
@@ -73,6 +75,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	},

