[pkg-opensc-commit] [opensc] 122/295: dnie: changes to include DNIe 3.0 (PIN channel)

Eric Dorland eric at moszumanska.debian.org
Sat Jun 24 21:11:22 UTC 2017


This is an automated email from the git hooks/post-receive script.

eric pushed a commit to branch master
in repository opensc.

commit 1d051dba6a78f67c2e644708f952906890864000
Author: ricky <rickyepoderi at yahoo.es>
Date:   Sat Oct 22 11:57:30 2016 +0200

    dnie: changes to include DNIe 3.0 (PIN channel)
---
 src/libopensc/card-dnie.c |  32 ++++--
 src/libopensc/cwa-dnie.c  | 259 ++++++++++++++++++++++++++++++++++++++++++----
 src/libopensc/cwa-dnie.h  |   8 ++
 src/libopensc/cwa14890.c  |  52 ++++++----
 src/libopensc/cwa14890.h  |   1 +
 5 files changed, 298 insertions(+), 54 deletions(-)

diff --git a/src/libopensc/card-dnie.c b/src/libopensc/card-dnie.c
index eb57b75..b461c31 100644
--- a/src/libopensc/card-dnie.c
+++ b/src/libopensc/card-dnie.c
@@ -59,7 +59,6 @@
 /* default titles */
 #define USER_CONSENT_TITLE "Confirm"
 
-extern cwa_provider_t *dnie_get_cwa_provider(sc_card_t * card);
 extern int dnie_read_file(
 	sc_card_t * card, 
 	const sc_path_t * path, 
@@ -749,10 +748,6 @@ int dnie_match_card(struct sc_card *card)
 	LOG_FUNC_CALLED(card->ctx);
 	matched = _sc_match_atr(card, dnie_atrs, &card->type);
 	result = (matched >= 0) ? 1 : 0;
-	if (result && card->atr.value[15] >= 0x04) {
-		/* exclude DNIe 3.0 */
-		result = 0;
-	}
 	LOG_FUNC_RETURN(card->ctx, result);
 }
 
@@ -769,13 +764,15 @@ static int dnie_sm_free_wrapped_apdu(struct sc_card *card,
 		LOG_FUNC_RETURN(ctx, SC_SUCCESS);
 
 	if ((*sm_apdu) != plain) {
-		plain->resp = (*sm_apdu)->resp;
-		plain->resplen = (*sm_apdu)->resplen;
-		plain->sw1 = (*sm_apdu)->sw1;
-		plain->sw2 = (*sm_apdu)->sw2;
+		if (plain) {
+			plain->resp = (*sm_apdu)->resp;
+			plain->resplen = (*sm_apdu)->resplen;
+			plain->sw1 = (*sm_apdu)->sw1;
+			plain->sw2 = (*sm_apdu)->sw2;
+			if (((*sm_apdu)->data) != plain->data)
+				free((unsigned char *) (*sm_apdu)->data);
+		}
 
-		if (((*sm_apdu)->data) != plain->data)
-			free((unsigned char *) (*sm_apdu)->data);
 		free(*sm_apdu);
 	}
 	*sm_apdu = NULL;
@@ -2195,6 +2192,11 @@ static int dnie_pin_verify(struct sc_card *card,
 
 	LOG_FUNC_CALLED(card->ctx);
 	/* ensure that secure channel is established from reset */
+	if (card->atr.value[15] >= DNIE_30_VERSION) {
+		/* the provider should be prepared for using PIN information */
+		sc_log(card->ctx, "DNIe 3.0 detected doing PIN initialization");
+		dnie_change_cwa_provider_to_pin(card);
+	}
 	res = cwa_create_secure_channel(card, GET_DNIE_PRIV_DATA(card)->cwa_provider, CWA_SM_COLD);
 	LOG_TEST_RET(card->ctx, res, "Establish SM failed");
 
@@ -2232,6 +2234,14 @@ static int dnie_pin_verify(struct sc_card *card,
 	/* the end: a bit of Mister Proper and return */
 	dnie_free_apdu_buffers(&apdu, resp, MAX_RESP_BUFFER_SIZE);
 	data->apdu = NULL;
+
+	/* ensure that secure channel is established after a PIN channel in 3.0 */
+	if (card->atr.value[15] >= DNIE_30_VERSION) {
+		sc_log(card->ctx, "DNIe 3.0 detected => re-establish secure channel");
+		dnie_change_cwa_provider_to_secure(card);
+		res = cwa_create_secure_channel(card, GET_DNIE_PRIV_DATA(card)->cwa_provider, CWA_SM_OVER);
+	}
+
 	LOG_FUNC_RETURN(card->ctx, res);
 #else
     LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "built without support of SM and External Authentication");
diff --git a/src/libopensc/cwa-dnie.c b/src/libopensc/cwa-dnie.c
index 6023fe1..6cb78cd 100644
--- a/src/libopensc/cwa-dnie.c
+++ b/src/libopensc/cwa-dnie.c
@@ -1,10 +1,10 @@
 /**
  * cwa-dnie.c: DNIe data provider for CWA SM handling.
- * 
+ *
  * Copyright (C) 2010 Juan Antonio Martinez <jonsito at terra.es>
  *
  * This work is derived from many sources at OpenSC Project site,
- * (see references) and the information made public by Spanish 
+ * (see references) and the information made public by Spanish
  * Direccion General de la Policia y de la Guardia Civil
  *
  * This library is free software; you can redistribute it and/or
@@ -91,6 +91,23 @@ static u8 ifd_modulus[] = {
 };
 
 /**
+ * Terminal (IFD) key modulus for SM channel creation for PIN channel DNIe 3.0
+ */
+static u8 ifd_pin_modulus[] = {
+	0xF4, 0x27, 0x97, 0x8D, 0xA1, 0x59, 0xBA, 0x02, 0x79, 0x30, 0x8A, 0x6C,
+	0x6A, 0x89, 0x50, 0x5A, 0xDA, 0x5A, 0x67, 0xC3, 0xDA, 0x26, 0x79, 0xEA,
+	0xF4, 0xA1, 0xB0, 0x11, 0x9E, 0xDD, 0x4D, 0xF4, 0x6E, 0x78, 0x04, 0x24,
+	0x71, 0xA9, 0xD1, 0x30, 0x1D, 0x3F, 0xB2, 0x8F, 0x38, 0xC5, 0x7D, 0x08,
+	0x89, 0xF7, 0x31, 0xDB, 0x8E, 0xDD, 0xBC, 0x13, 0x67, 0xC1, 0x34, 0xE1,
+	0xE9, 0x47, 0x78, 0x6B, 0x8E, 0xC8, 0xE4, 0xB9, 0xCA, 0x6A, 0xA7, 0xC2,
+	0x4C, 0x86, 0x91, 0xC7, 0xBE, 0x2F, 0xD8, 0xC1, 0x23, 0x66, 0x0E, 0x98,
+	0x65, 0xE1, 0x4F, 0x19, 0xDF, 0xFB, 0xB7, 0xFF, 0x38, 0x08, 0xC9, 0xF2,
+	0x04, 0xE7, 0x97, 0xD0, 0x6D, 0xD8, 0x33, 0x3A, 0xC5, 0x83, 0x86, 0xEE,
+	0x4E, 0xB6, 0x1E, 0x20, 0xEC, 0xA7, 0xEF, 0x38, 0xD5, 0xB0, 0x5E, 0xB1,
+	0x15, 0x96, 0x6A, 0x5A, 0x89, 0xAD, 0x58, 0xA5
+};
+
+/**
  * Terminal (IFD) public exponent for SM channel creation
  */
 static u8 ifd_public_exponent[] = {
@@ -98,6 +115,13 @@ static u8 ifd_public_exponent[] = {
 };
 
 /**
+ * Terminal (IFD) public exponent for SM channel creation for PIN channel DNIe 3.0
+ */
+static u8 ifd_pin_public_exponent[] = {
+	0x01, 0x00, 0x01
+};
+
+/**
  * Terminal (IFD) private exponent for SM channel establishment
  */
 static u8 ifd_private_exponent[] = {
@@ -115,6 +139,23 @@ static u8 ifd_private_exponent[] = {
 };
 
 /**
+ * Terminal (IFD) private exponent for SM channel establishment for PIN channel DNIe 3.0
+ */
+static u8 ifd_pin_private_exponent[] = {
+	0xD2, 0x7A, 0x03, 0x23, 0x7C, 0x72, 0x2E, 0x71, 0x8D, 0x69, 0xF4, 0x1A,
+	0xEC, 0x68, 0xBD, 0x95, 0xE4, 0xE0, 0xC4, 0xCD, 0x49, 0x15, 0x9C, 0x4A,
+	0x99, 0x63, 0x7D, 0xB6, 0x62, 0xFE, 0xA3, 0x02, 0x51, 0xED, 0x32, 0x9C,
+	0xFC, 0x43, 0x89, 0xEB, 0x71, 0x7B, 0x85, 0x02, 0x04, 0xCD, 0xF3, 0x30,
+	0xD6, 0x46, 0xFC, 0x7B, 0x2B, 0x19, 0x29, 0xD6, 0x8C, 0xBE, 0x39, 0x49,
+	0x7B, 0x62, 0x3A, 0x82, 0xC7, 0x64, 0x1A, 0xC3, 0x48, 0x79, 0x57, 0x3D,
+	0xEA, 0x0D, 0xAB, 0xC7, 0xCA, 0x30, 0x9A, 0xE4, 0xB3, 0xED, 0xDA, 0xFA,
+	0xEE, 0x55, 0xD5, 0x42, 0xF7, 0x80, 0x23, 0x03, 0x51, 0xE7, 0x5E, 0x7F,
+	0x32, 0xDC, 0x65, 0x2E, 0xF1, 0xED, 0x47, 0xA5, 0x1C, 0x18, 0xD9, 0xDF,
+	0x9F, 0xF4, 0x8D, 0x87, 0x8D, 0xB6, 0x22, 0xEA, 0x6E, 0x93, 0x70, 0xE9,
+	0xC6, 0x3B, 0x35, 0x8B, 0x7C, 0x11, 0x5A, 0xA1
+};
+
+/**
  *  Intermediate CA certificate in CVC format (Card verifiable certificate)
  */
 static u8 C_CV_CA_CS_AUT_cert[] = {
@@ -138,7 +179,7 @@ static u8 C_CV_CA_CS_AUT_cert[] = {
 	0x52, 0x44, 0x49, 0x60, 0x00, 0x06
 };
 
-/** 
+/**
  * Terminal (IFD) certificate in CVC format (PK.IFD.AUT)
  */
 static u8 C_CV_IFDUser_AUT_cert[] = {
@@ -163,19 +204,43 @@ static u8 C_CV_IFDUser_AUT_cert[] = {
 };
 
 /**
+ * Terminal (IFD) certificate in CVC format (PK.IFD.AUT) for the PIN channel in DNIe 3.0
+ */
+static u8 C_CV_IFDUser_AUT_pin_cert[] = {
+	0x7f, 0x21, 0x81, 0xcd, 0x5f, 0x37, 0x81, 0x80, 0x69, 0xc4, 0xe4, 0x94,
+	0xf0, 0x08, 0xe2, 0x42, 0x14, 0xb1, 0xc1, 0x31, 0xb6, 0x1f, 0xce, 0x9c,
+	0x15, 0xfa, 0x3c, 0xb0, 0x61, 0xdd, 0x6f, 0x02, 0xd8, 0xa2, 0xcd, 0x30,
+	0xd7, 0x2f, 0xb6, 0xdf, 0x89, 0x9a, 0xf1, 0x5b, 0x71, 0x78, 0x21, 0xbf,
+	0xb1, 0xaf, 0x7d, 0x75, 0x85, 0x01, 0x6d, 0x8c, 0x36, 0xaf, 0x4a, 0xc2,
+	0xa0, 0xb0, 0xc5, 0x2a, 0xd6, 0x5b, 0x69, 0x25, 0x67, 0x31, 0xc3, 0x4d,
+	0x59, 0x02, 0x0e, 0x87, 0xab, 0x73, 0xa2, 0x30, 0xfa, 0x69, 0xee, 0x82,
+	0xb3, 0x3a, 0x31, 0xdf, 0x04, 0x0c, 0xe9, 0x0f, 0x0a, 0xfc, 0x3a, 0x11,
+	0x1d, 0x35, 0xda, 0x95, 0x66, 0xa8, 0xcd, 0xab, 0xea, 0x0e, 0x3f, 0x75,
+	0x94, 0xc4, 0x40, 0xd3, 0x74, 0x50, 0x7a, 0x94, 0x35, 0x57, 0x59, 0xb3,
+	0x9e, 0xc5, 0xe5, 0xfc, 0xb8, 0x03, 0x8d, 0x79, 0x3d, 0x5f, 0x9b, 0xa8,
+	0xb5, 0xb1, 0x0b, 0x70, 0x5f, 0x38, 0x3c, 0x4c, 0x86, 0x91, 0xc7, 0xbe,
+	0x2f, 0xd8, 0xc1, 0x23, 0x66, 0x0e, 0x98, 0x65, 0xe1, 0x4f, 0x19, 0xdf,
+	0xfb, 0xb7, 0xff, 0x38, 0x08, 0xc9, 0xf2, 0x04, 0xe7, 0x97, 0xd0, 0x6d,
+	0xd8, 0x33, 0x3a, 0xc5, 0x83, 0x86, 0xee, 0x4e, 0xb6, 0x1e, 0x20, 0xec,
+	0xa7, 0xef, 0x38, 0xd5, 0xb0, 0x5e, 0xb1, 0x15, 0x96, 0x6a, 0x5a, 0x89,
+	0xad, 0x58, 0xa5, 0x00, 0x01, 0x00, 0x01, 0x42, 0x08, 0x65, 0x73, 0x53,
+	0x44, 0x49, 0x60, 0x00, 0x06
+};
+
+/**
  * Root CA card key reference
  */
 static u8 root_ca_keyref[] = { 0x02, 0x0f };
 
 
 /**
- * ICC card private key reference 
+ * ICC card private key reference
  */
 static u8 icc_priv_keyref[] = { 0x02, 0x1f };
 
 /**
  * Intermediate CA card key reference
- */ 
+ */
 static u8 cvc_intca_keyref[] =
     { 0x65, 0x73, 0x53, 0x44, 0x49, 0x60, 0x00, 0x06 };
 
@@ -186,11 +251,22 @@ static u8 cvc_ifd_keyref[] =
     { 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
 
 /**
+ * In memory key reference for selecting IFD sent certificate in PIN channel DNIe 3.0
+ */
+static u8 cvc_ifd_keyref_pin[] =
+    { 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
+
+/**
  * Serial number for IFD Terminal application
  */
 static u8 sn_ifd[] = { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
 
 /**
+ * Serial number for IFD Terminal application in PIN channel DNIe 3.0
+ */
+static u8 sn_ifd_pin[] = { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
+
+/**
  * Serial number for ICC card.
  * This buffer is to be filled at runtime
  */
@@ -286,12 +362,12 @@ int dnie_read_file(sc_card_t * card,
  * Read SM required certificates from card.
  *
  * This function uses received path to read a certificate file from
- * card. 
+ * card.
  * No validation is done except that received data is effectively a certificate
  * @param card Pointer to card driver structure
  * @param certpat path to requested certificate
  * @param cert where to store resultig data
- * @return SC_SUCCESS if ok, else error code 
+ * @return SC_SUCCESS if ok, else error code
  */
 static int dnie_read_certificate(sc_card_t * card, char *certpath, X509 ** cert)
 {
@@ -426,19 +502,46 @@ static int dnie_get_cvc_ifd_cert(sc_card_t * card, u8 ** cert, size_t * length)
 }
 
 /**
- * Get IFD (Terminal) private key data.
- * 
- * As this is a local (in memory) provider, just get data specified in
- * DNIe's manual and compose an OpenSSL private key structure
+ * Retrieve IFD (application) CVC certificate and length for
+ * the PIN channel.
  *
- * Notice that resulting data should be keept in memory as little as possible
- * Erasing them once used
+ * Returns a byte array with the application's certificate
+ * (in CardVerifiable Certificate format) to be sent to the
+ * card in External Authentication process
+ * As this is local provider, just points to provided static data,
+ * and allways return success
+ *
+ * @param card Pointer to card driver Certificate
+ * @param cert Where to store resulting byte array
+ * @param length len of returned byte array
+ * @return SC_SUCCESS if ok; else error code
+ */
+static int dnie_get_cvc_ifd_cert_pin(sc_card_t * card, u8 ** cert, size_t * length)
+{
+	LOG_FUNC_CALLED(card->ctx);
+	*cert = C_CV_IFDUser_AUT_pin_cert;
+	*length = sizeof(C_CV_IFDUser_AUT_pin_cert);
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+/**
+ * Get IFD (Terminal) private key data passing the three
+ * arguments (modulus, public and private exponent).
  *
  * @param card pointer to card driver structure
  * @param ifd_privkey where to store IFD private key
+ * @param modulus the byte array used as the modulus of the key
+ * @param modulus_len the length of the modulus
+ * @param public_exponent the byte array for the public exponent
+ * @param public_exponent_len the length of the public exponent
+ * @param private_exponent the byte array for the private exponent
+ * @param private_exponent_len the length of the private exponent
  * @return SC_SUCCESS if ok; else error code
  */
-static int dnie_get_ifd_privkey(sc_card_t * card, EVP_PKEY ** ifd_privkey)
+static int dnie_get_privkey(sc_card_t * card, EVP_PKEY ** ifd_privkey,
+                            u8 * modulus, int modulus_len,
+                            u8 * public_exponent, int public_exponent_len,
+                            u8 * private_exponent, int private_exponent_len)
 {
 	RSA *ifd_rsa=NULL;
 	BIGNUM *ifd_rsa_n, *ifd_rsa_e, *ifd_rsa_d = NULL;
@@ -477,6 +580,40 @@ static int dnie_get_ifd_privkey(sc_card_t * card, EVP_PKEY ** ifd_privkey)
 }
 
 /**
+ * Get IFD (Terminal) private key data
+ *
+ * As this is a local (in memory) provider, just get data specified in
+ * DNIe's manual and compose an OpenSSL private key structure
+ *
+ * @param card pointer to card driver structure
+ * @param ifd_privkey where to store IFD private key
+ * @return SC_SUCCESS if ok; else error code
+ */
+static int dnie_get_ifd_privkey(sc_card_t * card, EVP_PKEY ** ifd_privkey)
+{
+	return dnie_get_privkey(card, ifd_privkey, ifd_modulus, sizeof(ifd_modulus),
+				ifd_public_exponent, sizeof(ifd_public_exponent),
+				ifd_private_exponent, sizeof(ifd_private_exponent));
+}
+
+/**
+ * Get IFD (Terminal) private key data for the PIN channel DNIe 3.0
+ *
+ * As this is a local (in memory) provider, just get data specified in
+ * DNIe's manual and compose an OpenSSL private key structure
+ *
+ * @param card pointer to card driver structure
+ * @param ifd_privkey where to store IFD private key
+ * @return SC_SUCCESS if ok; else error code
+ */
+static int dnie_get_ifd_privkey_pin(sc_card_t * card, EVP_PKEY ** ifd_privkey)
+{
+        return dnie_get_privkey(card, ifd_privkey, ifd_pin_modulus, sizeof(ifd_pin_modulus),
+                                ifd_pin_public_exponent, sizeof(ifd_pin_public_exponent),
+                                ifd_pin_private_exponent, sizeof(ifd_pin_private_exponent));
+}
+
+/**
  * Get ICC intermediate CA Certificate from card.
  *
  * @param card Pointer to card driver structure
@@ -556,11 +693,31 @@ static int dnie_get_ifd_pubkey_ref(sc_card_t * card, u8 ** buf, size_t * len)
 }
 
 /**
+ *  Retrieve public key reference for IFD certificate for the PIN channel.
+ *
+ * This tells the card with in memory key reference is to be used
+ * when CVC cert is sent for external auth procedure
+ * As this driver is for local SM authentication SC_SUCCESS is allways returned
+ *
+ * @param card pointer to card driver structure
+ * @param buf where to store data to be sent
+ * @param len where to store data length
+ * @return SC_SUCCESS if ok; else error code
+ */
+static int dnie_get_ifd_pubkey_ref_pin(sc_card_t * card, u8 ** buf, size_t * len)
+{
+	LOG_FUNC_CALLED(card->ctx);
+	*buf = cvc_ifd_keyref_pin;
+	*len = sizeof(cvc_ifd_keyref_pin);
+	return SC_SUCCESS;
+}
+
+/**
  * Retrieve key reference for ICC privkey.
- * 
- * In local SM stablishment, just retrieve key reference from static 
+ *
+ * In local SM stablishment, just retrieve key reference from static
  * data tables and just return success
- * 
+ *
  * @param card pointer to card driver structure
  * @param buf where to store data
  * @param len where to store data length
@@ -589,6 +746,24 @@ static int dnie_get_sn_ifd(sc_card_t * card, u8 ** buf)
 	return SC_SUCCESS;
 }
 
+/**
+ * Retrieve SN.IFD (8 bytes left padded with zeroes if required)
+ * for the PIN channel DNIe 3.0.
+ *
+ * In DNIe local SM procedure, just read it from static data and
+ * return SC_SUCCESS
+ *
+ * @param card pointer to card structure
+ * @param buf where to store result (8 bytes)
+ * @return SC_SUCCESS if ok; else error
+ */
+static int dnie_get_sn_ifd_pin(sc_card_t * card, u8 ** buf)
+{
+	LOG_FUNC_CALLED(card->ctx);
+	*buf = sn_ifd_pin;
+	return SC_SUCCESS;
+}
+
 /* Retrieve SN.ICC (8 bytes left padded with zeroes if needed).
  *
  * As DNIe reads serial number at startup, no need to read again
@@ -617,11 +792,11 @@ static int dnie_get_sn_icc(sc_card_t * card, u8 ** buf)
  * CWA-14890 SM stablisment pre-operations.
  *
  * DNIe needs to get icc serial number at the begin of the sm creation
- * (to avoid breaking key references) so get it an store into serialnr 
+ * (to avoid breaking key references) so get it an store into serialnr
  * cache here.
  *
  * In this way if get_sn_icc is called(), we make sure that no APDU
- * command is to be sent to card, just retrieve it from cache 
+ * command is to be sent to card, just retrieve it from cache
  *
  * @param card pointer to card driver structure
  * @param provider pointer to SM data provider for DNIe
@@ -639,18 +814,22 @@ static int dnie_create_pre_ops(sc_card_t * card, cwa_provider_t * provider)
 	return sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
 }
 
+/**
+ * Now in DNIe the channel mode is changed to SM_MODE_TRANSMIT
+ * after CWA initialization to be consistent with OpenSC
+ */
 static int dnie_create_post_ops(sc_card_t * card, cwa_provider_t * provider)
 {
-        card->sm_ctx.sm_mode = SM_MODE_TRANSMIT;
+	card->sm_ctx.sm_mode = SM_MODE_TRANSMIT;
 
-        return SC_SUCCESS;
+	return SC_SUCCESS;
 }
 
 /**
  * Main entry point for DNIe CWA14890 SM data provider.
  *
  * Return a pointer to DNIe data provider with proper function pointers
- * 
+ *
  * @param card pointer to card driver data structure
  * @return cwa14890 DNIe data provider if success, null on error
  */
@@ -705,6 +884,40 @@ cwa_provider_t *dnie_get_cwa_provider(sc_card_t * card)
 	return res;
 }
 
+/**
+ * Changes the provider to use the common secure (DNIe 2.0)
+ * channel.
+ *
+ * @param card the card to change the cwa provider for
+ */
+void dnie_change_cwa_provider_to_secure(sc_card_t * card)
+{
+	cwa_provider_t * res = GET_DNIE_PRIV_DATA(card)->cwa_provider;
+
+	/* redefine different IFD data for secure channel */
+	res->cwa_get_cvc_ifd_cert = dnie_get_cvc_ifd_cert;
+	res->cwa_get_ifd_privkey = dnie_get_ifd_privkey;
+	res->cwa_get_ifd_pubkey_ref = dnie_get_ifd_pubkey_ref;
+	res->cwa_get_sn_ifd = dnie_get_sn_ifd;
+}
+
+/**
+ * Changes the provider to use the new PIN (DNIe 3.0)
+ * channel.
+ *
+ * @param card the card to change the cwa provider for
+ */
+void dnie_change_cwa_provider_to_pin(sc_card_t * card)
+{
+	cwa_provider_t * res = GET_DNIE_PRIV_DATA(card)->cwa_provider;
+
+	/* redefine different IFD data for PIN channel */
+	res->cwa_get_cvc_ifd_cert = dnie_get_cvc_ifd_cert_pin;
+	res->cwa_get_ifd_privkey = dnie_get_ifd_privkey_pin;
+	res->cwa_get_ifd_pubkey_ref = dnie_get_ifd_pubkey_ref_pin;
+	res->cwa_get_sn_ifd = dnie_get_sn_ifd_pin;
+}
+
 int dnie_transmit_apdu(sc_card_t * card, sc_apdu_t * apdu)
 {
 	int res = SC_SUCCESS;
@@ -719,7 +932,7 @@ int dnie_transmit_apdu(sc_card_t * card, sc_apdu_t * apdu)
 		res = cwa_decode_response(card, provider, apdu);
 		LOG_TEST_RET(ctx, res, "Error in cwa_decode_response process");
 	}
-	else 
+	else
 		res = sc_transmit_apdu(card, apdu);
 	return res;
 }
diff --git a/src/libopensc/cwa-dnie.h b/src/libopensc/cwa-dnie.h
index ffd16d7..bb272c2 100644
--- a/src/libopensc/cwa-dnie.h
+++ b/src/libopensc/cwa-dnie.h
@@ -61,6 +61,14 @@ struct cwa_provider_st;
 #define GET_DNIE_PRIV_DATA(card) ((dnie_private_data_t *) ((card)->drv_data))
 #define GET_DNIE_UI_CTX(card) (((dnie_private_data_t *) ((card)->drv_data))->ui_ctx)
 
+#define DNIE_30_VERSION 0x04
+
+cwa_provider_t *dnie_get_cwa_provider(sc_card_t * card);
+
+void dnie_change_cwa_provider_to_pin(sc_card_t * card);
+
+void dnie_change_cwa_provider_to_secure(sc_card_t * card);
+
 int dnie_transmit_apdu(sc_card_t * card, sc_apdu_t * apdu);
 
 void dnie_format_apdu(sc_card_t *card, sc_apdu_t *apdu,
diff --git a/src/libopensc/cwa14890.c b/src/libopensc/cwa14890.c
index 62a847c..624cbbc 100644
--- a/src/libopensc/cwa14890.c
+++ b/src/libopensc/cwa14890.c
@@ -41,9 +41,10 @@
 #include <openssl/x509.h>
 #include <openssl/des.h>
 #include <openssl/rand.h>
+#include "cwa14890.h"
 #include "cwa-dnie.h"
 
-#include "cwa14890.h"
+#define MAX_RESP_BUFFER_SIZE 2048
 
 /**
  * Structure used to compose BER-TLV encoded data
@@ -435,6 +436,7 @@ static int cwa_verify_cvc_certificate(sc_card_t * card,
 	sc_apdu_t apdu;
 	int result = SC_SUCCESS;
 	sc_context_t *ctx = NULL;
+	u8 resp[MAX_RESP_BUFFER_SIZE];
 
 	/* safety check */
 	if (!card || !card->ctx)
@@ -445,8 +447,8 @@ static int cwa_verify_cvc_certificate(sc_card_t * card,
 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
 
 	/* compose apdu for Perform Security Operation (Verify cert) cmd */
-	dnie_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x2A, 0x00, 0xAE, 0, len,
-					NULL, 0, cert, len);
+	dnie_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x00, 0xAE, 255, len,
+					resp, MAX_RESP_BUFFER_SIZE, cert, len);
 
 	/* send composed apdu and parse result */
 	result = dnie_transmit_apdu(card, &apdu);
@@ -475,6 +477,7 @@ static int cwa_set_security_env(sc_card_t * card,
 	sc_apdu_t apdu;
 	int result = SC_SUCCESS;
 	sc_context_t *ctx = NULL;
+	u8 resp[MAX_RESP_BUFFER_SIZE];
 
 	/* safety check */
 	if (!card || !card->ctx)
@@ -485,8 +488,8 @@ static int cwa_set_security_env(sc_card_t * card,
 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
 
 	/* compose apdu for Manage Security Environment cmd */
-	dnie_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, p1, p2, 0, length,
-					NULL, 0, buffer, length);
+	dnie_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x22, p1, p2, 255, length,
+					resp, MAX_RESP_BUFFER_SIZE, buffer, length);
 
 	/* send composed apdu and parse result */
 	result = dnie_transmit_apdu(card, &apdu);
@@ -721,6 +724,7 @@ static int cwa_external_auth(sc_card_t * card, cwa_sm_status_t * sm)
 	sc_apdu_t apdu;
 	int result = SC_SUCCESS;
 	sc_context_t *ctx = NULL;
+	u8 resp[MAX_RESP_BUFFER_SIZE];
 
 	/* safety check */
 	if (!card || !card->ctx)
@@ -730,7 +734,7 @@ static int cwa_external_auth(sc_card_t * card, cwa_sm_status_t * sm)
 
 	/* compose apdu for External Authenticate cmd */
 	dnie_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x82, 0x00, 0x00, 0, sizeof(sm->sig),
-					NULL, 0, sm->sig, sizeof(sm->sig));
+					resp, MAX_RESP_BUFFER_SIZE, sm->sig, sizeof(sm->sig));
 
 	/* send composed apdu and parse result */
 	result = dnie_transmit_apdu(card, &apdu);
@@ -1081,7 +1085,15 @@ int cwa_create_secure_channel(sc_card_t * card,
 			LOG_FUNC_RETURN(ctx, SC_SUCCESS);
 		}
 	case CWA_SM_COLD:	/* force sm initialization process */
-		sc_log(ctx, "CWA SM initialization requested");
+		sc_log(ctx, "CWA SM initialization requested => reset and re-initialize");
+		sc_reset(card, 0);
+		provider->status.session.state = CWA_SM_INPROGRESS;
+		break;
+	case CWA_SM_OVER:	/* create another channel over an existing one */
+		if (provider->status.session.state != CWA_SM_ACTIVE) {
+			sc_log(ctx, "CWA SM over requested => not in active state");
+			LOG_FUNC_RETURN(ctx, SC_ERROR_SM_INVALID_LEVEL);
+		}
 		break;
 	default:
 		sc_log(ctx, "Invalid provided SM initialization flag");
@@ -1090,13 +1102,6 @@ int cwa_create_secure_channel(sc_card_t * card,
 
 	/* OK: lets start process */
 
-	/* reset card (warm reset, do not unpower card) */
-	sc_log(ctx, "Resseting card");
-	sc_reset(card, 0);
-
-	/* mark SM status as in progress */
-	provider->status.session.state = CWA_SM_INPROGRESS;
-
 	/* call provider pre-operation method */
 	sc_log(ctx, "CreateSecureChannel pre-operations");
 	if (provider->cwa_create_pre_ops) {
@@ -1421,7 +1426,7 @@ int cwa_encode_apdu(sc_card_t * card,
 		    cwa_provider_t * provider, sc_apdu_t * from, sc_apdu_t * to)
 {
 	u8 *apdubuf = NULL;		/* to store resulting apdu */
-	size_t apdulen;
+	size_t apdulen, tlv_len;
 	u8 *ccbuf = NULL;		/* where to store data to eval cryptographic checksum CC */
 	size_t cclen = 0;
 	u8 macbuf[8];		/* to store and compute CC */
@@ -1529,13 +1534,17 @@ int cwa_encode_apdu(sc_card_t * card,
 			msg = "Error in compose tag 8x87 TLV";
 			goto encode_end;
 		}
-	}
+	} else if ((0xff & from->le) > 0) {
 
 	/* if le byte is declared, compose and add Le TLV */
 	/* FIXME: For DNIe we must not send the le bytes
 	  when le == 256 but this goes against the standard
 	  and might break other cards reusing this code */
-	if ((0xff & from->le) > 0) {
+        /* NOTE: In FNMT MultiPKCS11 code this is an if, i.e.,
+           the le is only sent if no data (lc) is set.
+           In DNIe 3.0 pin verification sending both TLV return
+           69 88 "SM Data Object incorrect". For the moment it is
+           fixed sendind le=0 in pin verification apdu */
 	    u8 le = 0xff & from->le;
 	    res = cwa_compose_tlv(card, 0x97, 1, &le, &ccbuf, &cclen);
 	    if (res != SC_SUCCESS) {
@@ -1574,7 +1583,9 @@ int cwa_encode_apdu(sc_card_t * card,
 			 &k1, &k2, DES_ENCRYPT);
 
 	/* compose and add computed MAC TLV to result buffer */
-	res = cwa_compose_tlv(card, 0x8E, 4, macbuf, &apdubuf, &apdulen);
+        tlv_len = (card->atr.value[15] >= DNIE_30_VERSION)? 8 : 4;
+	sc_log(ctx, "Using TLV lenght: %d", tlv_len);
+	res = cwa_compose_tlv(card, 0x8E, tlv_len, macbuf, &apdubuf, &apdulen);
 	if (res != SC_SUCCESS) {
 		msg = "Encode APDU compose_tlv(0x87) failed";
 		goto encode_end;
@@ -1620,7 +1631,7 @@ int cwa_decode_response(sc_card_t * card,
 			cwa_provider_t * provider,
 			sc_apdu_t * apdu)
 {
-	size_t i, j;
+	size_t i, j, tlv_len;
 	cwa_tlv_t tlv_array[4];
 	cwa_tlv_t *p_tlv = &tlv_array[0];	/* to store plain data (Tag 0x81) */
 	cwa_tlv_t *e_tlv = &tlv_array[1];	/* to store pad encoded data (Tag 0x87) */
@@ -1706,7 +1717,8 @@ int cwa_decode_response(sc_card_t * card,
 		res = SC_ERROR_INVALID_DATA;
 		goto response_decode_end;
 	}
-	if (m_tlv->len != 4) {
+        tlv_len = (card->atr.value[15] >= DNIE_30_VERSION)? 8 : 4;
+	if (m_tlv->len != tlv_len) {
 		msg = "Invalid MAC TAG Length";
 		res = SC_ERROR_INVALID_DATA;
 		goto response_decode_end;
diff --git a/src/libopensc/cwa14890.h b/src/libopensc/cwa14890.h
index b55d3b5..e53bec6 100644
--- a/src/libopensc/cwa14890.h
+++ b/src/libopensc/cwa14890.h
@@ -36,6 +36,7 @@
 #define CWA_SM_OFF        0x00	/** Disable SM channel */
 #define CWA_SM_COLD       0x01	/** force creation of a new SM channel */
 #define CWA_SM_WARM       0x02	/** Create new SM channel only if state is NONE */
+#define CWA_SM_OVER       0x03	/** Create new SM channel only over another channel */
 
 /* TAGS for encoded APDU's */
 #define CWA_SM_PLAIN_TAG  0x81	/** Plain value (to be protected by CC) */

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-opensc/opensc.git



More information about the pkg-opensc-commit mailing list