- completed mac verification. sm with pace is now fully functional.
- made pace_test more fault tolerant. git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@72 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
176
ccid/pace.c
176
ccid/pace.c
@@ -159,6 +159,17 @@ int pace_sm_decrypt(sc_card_t *card, struct *sm_ctx,
|
|||||||
{
|
{
|
||||||
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED);
|
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED);
|
||||||
}
|
}
|
||||||
|
int pace_sm_authenticate(sc_card_t *card, const struct sm_ctx *ctx,
|
||||||
|
const u8 *data, size_t datalen, u8 **macdata)
|
||||||
|
{
|
||||||
|
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
int pace_sm_verify_authentication(sc_card_t *card, struct sm_ctx *ctx,
|
||||||
|
const u8 *mac, size_t maclen,
|
||||||
|
const u8 *macdata, size_t macdatalen)
|
||||||
|
{
|
||||||
|
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_ERROR_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
@@ -763,6 +774,7 @@ int EstablishPACEChannel(sc_card_t *card, const __u8 *in,
|
|||||||
sctx->authenticate = pace_sm_authenticate;
|
sctx->authenticate = pace_sm_authenticate;
|
||||||
sctx->encrypt = pace_sm_encrypt;
|
sctx->encrypt = pace_sm_encrypt;
|
||||||
sctx->decrypt = pace_sm_decrypt;
|
sctx->decrypt = pace_sm_decrypt;
|
||||||
|
sctx->verify_authentication = pace_sm_verify_authentication;
|
||||||
sctx->padding_indicator = SM_ISO_PADDING;
|
sctx->padding_indicator = SM_ISO_PADDING;
|
||||||
sctx->block_length = EVP_CIPHER_block_size(pctx->cipher);
|
sctx->block_length = EVP_CIPHER_block_size(pctx->cipher);
|
||||||
sctx->authentication_ctx = pace_sm_ctx_create(k_mac,
|
sctx->authentication_ctx = pace_sm_ctx_create(k_mac,
|
||||||
@@ -772,7 +784,7 @@ int EstablishPACEChannel(sc_card_t *card, const __u8 *in,
|
|||||||
r = SC_ERROR_OUT_OF_MEMORY;
|
r = SC_ERROR_OUT_OF_MEMORY;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
r = reset_ssc(sctx);
|
r = reset_ssc(sctx->authentication_ctx);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
if (ef_cardaccess)
|
if (ef_cardaccess)
|
||||||
@@ -833,6 +845,7 @@ int pace_test(sc_card_t *card)
|
|||||||
size_t outlen;
|
size_t outlen;
|
||||||
struct sm_ctx sctx;
|
struct sm_ctx sctx;
|
||||||
sc_apdu_t apdu;
|
sc_apdu_t apdu;
|
||||||
|
int r;
|
||||||
|
|
||||||
memset(&sctx, 0, sizeof(sctx));
|
memset(&sctx, 0, sizeof(sctx));
|
||||||
memset(&apdu, 0, sizeof(apdu));
|
memset(&apdu, 0, sizeof(apdu));
|
||||||
@@ -866,9 +879,10 @@ int pace_test(sc_card_t *card)
|
|||||||
apdu.resp = buf;
|
apdu.resp = buf;
|
||||||
apdu.resplen = sizeof buf;
|
apdu.resplen = sizeof buf;
|
||||||
apdu.cse = SC_APDU_CASE_4_SHORT;
|
apdu.cse = SC_APDU_CASE_4_SHORT;
|
||||||
|
r = pace_transmit_apdu(&sctx, card, &apdu);
|
||||||
SC_TEST_RET(card->ctx, pace_transmit_apdu(&sctx, card, &apdu),
|
if (r < 0)
|
||||||
"Could not select EF.CardSecurity");
|
sc_error(card->ctx, "Could not select EF.CardSecurity: %s",
|
||||||
|
sc_strerror(r));
|
||||||
|
|
||||||
/* read CardSecurity */
|
/* read CardSecurity */
|
||||||
apdu.cla = 0x00;
|
apdu.cla = 0x00;
|
||||||
@@ -876,20 +890,26 @@ int pace_test(sc_card_t *card)
|
|||||||
apdu.p1 = 0x02;
|
apdu.p1 = 0x02;
|
||||||
apdu.p2 = 0x00;
|
apdu.p2 = 0x00;
|
||||||
apdu.le = 0x00;
|
apdu.le = 0x00;
|
||||||
|
apdu.resp = buf;
|
||||||
|
apdu.resplen = sizeof buf;
|
||||||
apdu.cse = SC_APDU_CASE_2_SHORT;
|
apdu.cse = SC_APDU_CASE_2_SHORT;
|
||||||
|
r = pace_transmit_apdu(&sctx, card, &apdu);
|
||||||
|
if (r < 0)
|
||||||
|
sc_error(card->ctx, "Could not read EF.CardSecurity: %s",
|
||||||
|
sc_strerror(r));
|
||||||
|
|
||||||
/* reset retry counter */
|
/* reset retry counter */
|
||||||
apdu.cla = 0x00;
|
apdu.cla = 0x00;
|
||||||
apdu.ins = 0x2C;
|
apdu.ins = 0x2C;
|
||||||
apdu.p1 = 0x03;
|
apdu.p1 = 0x03;
|
||||||
apdu.p2 = 0x02;
|
apdu.p2 = 0x02;
|
||||||
|
apdu.resp = buf;
|
||||||
|
apdu.resplen = sizeof buf;
|
||||||
apdu.cse = SC_APDU_CASE_1;
|
apdu.cse = SC_APDU_CASE_1;
|
||||||
|
r = pace_transmit_apdu(&sctx, card, &apdu);
|
||||||
SC_TEST_RET(card->ctx, pace_transmit_apdu(&sctx, card, &apdu),
|
if (r < 0)
|
||||||
"Could not reset retry counter of CAN");
|
sc_error(card->ctx, "Could not reset retry counter of CAN: %s",
|
||||||
|
sc_strerror(r));
|
||||||
SC_TEST_RET(card->ctx, pace_transmit_apdu(&sctx, card, &apdu),
|
|
||||||
"Could not read EF.CardSecurity");
|
|
||||||
|
|
||||||
return SC_SUCCESS;
|
return SC_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -927,18 +947,17 @@ encode_ssc(const BIGNUM *ssc, const PACE_CTX *ctx, u8 **encoded)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
update_iv(struct sm_ctx *ctx)
|
update_iv(struct pace_sm_ctx *psmctx)
|
||||||
{
|
{
|
||||||
if (!ctx || !ctx->cipher_ctx)
|
|
||||||
return SC_ERROR_INVALID_ARGUMENTS;
|
|
||||||
|
|
||||||
BUF_MEM *sscbuf = NULL, *ivbuf = NULL;
|
BUF_MEM *sscbuf = NULL, *ivbuf = NULL;
|
||||||
const EVP_CIPHER *ivcipher = NULL, *oldcipher;
|
const EVP_CIPHER *ivcipher = NULL, *oldcipher;
|
||||||
u8 *ssc = NULL;
|
u8 *ssc = NULL;
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
struct pace_sm_ctx *psmctx = ctx->cipher_ctx;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
if (!psmctx)
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
switch (EVP_CIPHER_nid(psmctx->ctx->cipher)) {
|
switch (EVP_CIPHER_nid(psmctx->ctx->cipher)) {
|
||||||
case NID_aes_128_cbc:
|
case NID_aes_128_cbc:
|
||||||
if (!ivcipher)
|
if (!ivcipher)
|
||||||
@@ -1002,28 +1021,36 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
increment_ssc(struct sm_ctx *ctx)
|
increment_ssc(struct pace_sm_ctx *psmctx)
|
||||||
{
|
{
|
||||||
if (!ctx || !ctx->cipher_ctx)
|
if (!psmctx)
|
||||||
return SC_ERROR_INVALID_ARGUMENTS;
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
struct pace_sm_ctx *psmctx = ctx->cipher_ctx;
|
|
||||||
|
|
||||||
BN_add_word(psmctx->ssc, 1);
|
BN_add_word(psmctx->ssc, 1);
|
||||||
|
|
||||||
return update_iv(ctx);
|
return update_iv(psmctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
reset_ssc(struct sm_ctx *ctx)
|
decrement_ssc(struct pace_sm_ctx *psmctx)
|
||||||
{
|
{
|
||||||
if (!ctx || !ctx->cipher_ctx)
|
if (!psmctx)
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
|
BN_sub_word(psmctx->ssc, 1);
|
||||||
|
|
||||||
|
return update_iv(psmctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
reset_ssc(struct pace_sm_ctx *psmctx)
|
||||||
|
{
|
||||||
|
if (!psmctx)
|
||||||
return SC_ERROR_INVALID_ARGUMENTS;
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
struct pace_sm_ctx *psmctx = ctx->cipher_ctx;
|
|
||||||
BN_zero(psmctx->ssc);
|
BN_zero(psmctx->ssc);
|
||||||
|
|
||||||
return update_iv(ctx);
|
return update_iv(psmctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pace_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx,
|
int pace_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx,
|
||||||
@@ -1174,14 +1201,105 @@ err:
|
|||||||
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r);
|
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pace_transmit_apdu(struct sm_ctx *sctx, sc_card_t *card,
|
int pace_sm_verify_authentication(sc_card_t *card, const struct sm_ctx *ctx,
|
||||||
|
const u8 *mac, size_t maclen,
|
||||||
|
const u8 *macdata, size_t macdatalen)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
char *p;
|
||||||
|
BUF_MEM authdata, *my_mac = NULL;
|
||||||
|
authdata.data = NULL;
|
||||||
|
|
||||||
|
if (!ctx || !ctx->cipher_ctx) {
|
||||||
|
r = SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
goto incerr;
|
||||||
|
}
|
||||||
|
struct pace_sm_ctx *psmctx = ctx->cipher_ctx;
|
||||||
|
|
||||||
|
r = increment_ssc(psmctx);
|
||||||
|
if (r < 0)
|
||||||
|
goto incerr;
|
||||||
|
|
||||||
|
r = encode_ssc(psmctx->ssc, psmctx->ctx, (u8 **) &authdata.data);
|
||||||
|
if (r < 0)
|
||||||
|
goto err;
|
||||||
|
authdata.length = r;
|
||||||
|
|
||||||
|
p = realloc(authdata.data, authdata.length + macdatalen);
|
||||||
|
if (!p) {
|
||||||
|
r = SC_ERROR_OUT_OF_MEMORY;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
authdata.data = p;
|
||||||
|
memcpy(authdata.data + authdata.length, macdata, macdatalen);
|
||||||
|
authdata.length += macdatalen;
|
||||||
|
bin_log(card->ctx, "Authentication data to verify (PACE)",
|
||||||
|
(u8 *) authdata.data, authdata.length);
|
||||||
|
|
||||||
|
authdata.max = authdata.length;
|
||||||
|
my_mac = PACE_authenticate(psmctx->ctx, psmctx->key_mac, &authdata);
|
||||||
|
if (!my_mac) {
|
||||||
|
r = SC_ERROR_INTERNAL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (my_mac->length != maclen ||
|
||||||
|
memcmp(my_mac->data, mac, maclen) != 0) {
|
||||||
|
r = SC_ERROR_OBJECT_NOT_VALID;
|
||||||
|
sc_debug(card->ctx, "Authentication data not verified");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc_debug(card->ctx, "Authentication data verified");
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (authdata.data)
|
||||||
|
free(authdata.data);
|
||||||
|
if (my_mac)
|
||||||
|
BUF_MEM_free(my_mac);
|
||||||
|
if (r >= 0)
|
||||||
|
decrement_ssc(psmctx);
|
||||||
|
else
|
||||||
|
r = decrement_ssc(psmctx);
|
||||||
|
|
||||||
|
incerr:
|
||||||
|
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pace_transmit_apdu(struct sm_ctx *ctx, sc_card_t *card,
|
||||||
sc_apdu_t *apdu)
|
sc_apdu_t *apdu)
|
||||||
{
|
{
|
||||||
increment_ssc(sctx);
|
int r;
|
||||||
SC_TEST_RET(card->ctx, sm_transmit_apdu(sctx, card, apdu),
|
|
||||||
"Could not send SM APDU");
|
|
||||||
|
|
||||||
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_SUCCESS);
|
if (!ctx || !ctx->cipher_ctx) {
|
||||||
|
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, SC_ERROR_INVALID_ARGUMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SW1 and SW2 are used to determine if really something has been sent and
|
||||||
|
* received. Only if this is the case, the send sequence counter needs to
|
||||||
|
* be incremented. */
|
||||||
|
|
||||||
|
apdu->sw1 = 0;
|
||||||
|
apdu->sw2 = 0;
|
||||||
|
|
||||||
|
SC_TEST_RET(card->ctx, increment_ssc(ctx->cipher_ctx),
|
||||||
|
"Could not increment send sequence counter");
|
||||||
|
|
||||||
|
r = sm_transmit_apdu(ctx, card, apdu);
|
||||||
|
|
||||||
|
if (apdu->sw1 || apdu->sw2) {
|
||||||
|
if (r < 0) {
|
||||||
|
if (increment_ssc(ctx->cipher_ctx) < 0)
|
||||||
|
sc_error(card->ctx,
|
||||||
|
"Could not increment send sequence counter");
|
||||||
|
} else
|
||||||
|
r = increment_ssc(ctx->cipher_ctx);
|
||||||
|
} else
|
||||||
|
if (decrement_ssc(ctx->cipher_ctx) < 0)
|
||||||
|
sc_error(card->ctx,
|
||||||
|
"Could not decrement send sequence counter");
|
||||||
|
|
||||||
|
SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_DEBUG, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -58,8 +58,9 @@ pace_sm_ctx_free(struct pace_sm_ctx *ctx);
|
|||||||
void
|
void
|
||||||
pace_sm_ctx_clear_free(struct pace_sm_ctx *ctx);
|
pace_sm_ctx_clear_free(struct pace_sm_ctx *ctx);
|
||||||
|
|
||||||
int reset_ssc(struct sm_ctx *ctx);
|
int increment_ssc(struct pace_sm_ctx *psmctx);
|
||||||
int increment_ssc(struct sm_ctx *ctx);
|
int decrement_ssc(struct pace_sm_ctx *psmctx);
|
||||||
|
int reset_ssc(struct pace_sm_ctx *psmctx);
|
||||||
|
|
||||||
int pace_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx,
|
int pace_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx,
|
||||||
const u8 *data, size_t datalen, u8 **enc);
|
const u8 *data, size_t datalen, u8 **enc);
|
||||||
@@ -67,6 +68,9 @@ int pace_sm_decrypt(sc_card_t *card, const struct sm_ctx *ctx,
|
|||||||
const u8 *enc, size_t enclen, u8 **data);
|
const u8 *enc, size_t enclen, u8 **data);
|
||||||
int pace_sm_authenticate(sc_card_t *card, const struct sm_ctx *ctx,
|
int pace_sm_authenticate(sc_card_t *card, const struct sm_ctx *ctx,
|
||||||
const u8 *data, size_t datalen, u8 **outdata);
|
const u8 *data, size_t datalen, u8 **outdata);
|
||||||
|
int pace_sm_verify_authentication(sc_card_t *card, const struct sm_ctx *ctx,
|
||||||
|
const u8 *mac, size_t maclen,
|
||||||
|
const u8 *macdata, size_t macdatalen);
|
||||||
|
|
||||||
int GetReadersPACECapabilities(sc_card_t *card, const __u8
|
int GetReadersPACECapabilities(sc_card_t *card, const __u8
|
||||||
*in, __u8 **out, size_t *outlen);
|
*in, __u8 **out, size_t *outlen);
|
||||||
|
|||||||
@@ -487,13 +487,10 @@ static int sm_decrypt(const struct sm_ctx *ctx, sc_card_t *card,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* XXX */
|
|
||||||
r = ctx->verify_authentication(card, ctx, mac, mac_len,
|
r = ctx->verify_authentication(card, ctx, mac, mac_len,
|
||||||
mac_data, r);
|
mac_data, r);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto err;
|
goto err;
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
r = SC_ERROR_ASN1_OBJECT_NOT_FOUND;
|
r = SC_ERROR_ASN1_OBJECT_NOT_FOUND;
|
||||||
goto err;
|
goto err;
|
||||||
|
|||||||
Reference in New Issue
Block a user