dnie: changes to include DNIe 3.0 (PIN channel)

This commit is contained in:
ricky 2016-10-22 11:57:30 +02:00 committed by Viktor Tarasov
parent 65090e814e
commit 1d051dba6a
5 changed files with 298 additions and 54 deletions

View File

@ -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");

View File

@ -1,10 +1,10 @@
/**
* cwa-dnie.c: DNIe data provider for CWA SM handling.
*
*
* Copyright (C) 2010 Juan Antonio Martinez <jonsito@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
@ -90,6 +90,23 @@ static u8 ifd_modulus[] = {
0x6a, 0xe2, 0x36, 0x59, 0x00, 0x16, 0xba, 0x69
};
/**
* 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
*/
@ -97,6 +114,13 @@ static u8 ifd_public_exponent[] = {
0x01, 0x00, 0x01
};
/**
* 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
*/
@ -114,6 +138,23 @@ static u8 ifd_private_exponent[] = {
0xbd, 0x9b, 0x00, 0x31, 0x3c, 0x0f, 0x46, 0xed
};
/**
* 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)
*/
@ -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[] = {
@ -162,6 +203,30 @@ static u8 C_CV_IFDUser_AUT_cert[] = {
0x44, 0x49, 0x60, 0x00, 0x06
};
/**
* 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
*/
@ -169,13 +234,13 @@ 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 };
@ -185,11 +250,22 @@ static u8 cvc_intca_keyref[] =
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;
@ -476,6 +579,40 @@ static int dnie_get_ifd_privkey(sc_card_t * card, EVP_PKEY ** ifd_privkey)
LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
/**
* 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.
*
@ -555,12 +692,32 @@ static int dnie_get_ifd_pubkey_ref(sc_card_t * card, u8 ** buf, size_t * len)
return SC_SUCCESS;
}
/**
* 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;
}

View File

@ -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,

View File

@ -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;

View File

@ -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) */