diff --git a/ccid/pace.c b/ccid/pace.c index 87c5ab7..6a60643 100644 --- a/ccid/pace.c +++ b/ccid/pace.c @@ -737,18 +737,19 @@ int EstablishPACEChannel(sc_card_t *card, const __u8 *in, /* XXX parse CHAT to check role of terminal */ - sctx->authentication_ctx = pace_sm_ctx_create(info->protocol, k_mac, - k_enc, pctx); - if (!sctx->authentication_ctx) { - r = SC_ERROR_INTERNAL; - goto err; - } sctx->authenticate = pace_sm_authenticate; - sctx->cipher_ctx = sctx->authentication_ctx; sctx->encrypt = pace_sm_encrypt; sctx->decrypt = pace_sm_decrypt; sctx->padding_indicator = SM_ISO_PADDING; sctx->block_length = EVP_CIPHER_block_size(pctx->cipher); + sctx->authentication_ctx = pace_sm_ctx_create(info->protocol, k_mac, + k_enc, pctx); + sctx->cipher_ctx = sctx->authentication_ctx; + if (!sctx->authentication_ctx) { + r = SC_ERROR_OUT_OF_MEMORY; + goto err; + } + r = reset_ssc(sctx); err: if (info) @@ -844,31 +845,36 @@ int pace_test(sc_card_t *card) return SC_SUCCESS; } -static BUF_MEM * -encoded_ssc(const uint16_t ssc, const PACE_CTX *ctx) +static int +encode_ssc(const BIGNUM *ssc, const PACE_CTX *ctx, u8 **encoded) { - BUF_MEM * out = NULL; - size_t len; + u8 *p; + size_t en_len, bn_len; if (!ctx) - goto err; + return SC_ERROR_INVALID_ARGUMENTS; - len = EVP_CIPHER_block_size(ctx->cipher); - out = BUF_MEM_create(len); - if (!out || len < sizeof ssc) - goto err; + en_len = EVP_CIPHER_block_size(ctx->cipher); + p = realloc(*encoded, en_len); + if (!p) + return SC_ERROR_OUT_OF_MEMORY; + *encoded = p; - /* Copy SSC to the end of buffer and fill the rest with 0 */ - memset(out->data, 0, len); - memcpy(out->data + len - sizeof ssc, &ssc, sizeof ssc); + bn_len = BN_num_bytes(ssc); - return out; + if (bn_len <= en_len) { + memset(*encoded, 0, en_len - bn_len); + BN_bn2bin(ssc, *encoded + en_len - bn_len); + } else { + p = malloc(bn_len); + if (!p) + return SC_ERROR_OUT_OF_MEMORY; + BN_bn2bin(ssc, p); + memcpy(*encoded, p + bn_len - en_len, en_len); + free(p); + } -err: - if (out) - BUF_MEM_free(out); - - return NULL; + return en_len; } static int @@ -878,6 +884,7 @@ update_iv(struct sm_ctx *ctx) return SC_ERROR_INVALID_ARGUMENTS; BUF_MEM *sscbuf = NULL, *ivbuf = NULL; + u8 *ssc = NULL; unsigned char *p; struct pace_sm_ctx *psmctx = ctx->cipher_ctx; int r; @@ -897,7 +904,14 @@ update_iv(struct sm_ctx *ctx) case NID_id_PACE_ECDH_IM_AES_CBC_CMAC_256: /* For AES decryption the IV is not needed, * so we always set it to the encryption IV=E(K_Enc, SSC) */ - sscbuf = encoded_ssc(psmctx->ssc, psmctx->ctx); + r = encode_ssc(psmctx->ssc, psmctx->ctx, &ssc); + if (r < 0) + goto err; + sscbuf = BUF_MEM_create_init(ssc, r); + if (!sscbuf) { + r = SC_ERROR_OUT_OF_MEMORY; + goto err; + } ivbuf = PACE_encrypt(psmctx->ctx, psmctx->key_enc, sscbuf); if (!ivbuf) { r = SC_ERROR_INTERNAL; @@ -908,8 +922,8 @@ update_iv(struct sm_ctx *ctx) r = SC_ERROR_OUT_OF_MEMORY; goto err; } - memcpy(p, ivbuf->data, ivbuf->length); psmctx->ctx->iv = p; + memcpy(psmctx->ctx->iv, ivbuf->data, ivbuf->length); break; case NID_id_PACE_DH_GM_3DES_CBC_CBC: case NID_id_PACE_DH_IM_3DES_CBC_CBC: @@ -942,10 +956,10 @@ increment_ssc(struct sm_ctx *ctx) struct pace_sm_ctx *psmctx = ctx->cipher_ctx; - if (psmctx->ssc == 0) { - psmctx->ssc = 2; + if (BN_is_zero(psmctx->ssc)) { + BN_set_word(psmctx->ssc, 2); } else { - psmctx->ssc++; + BN_add_word(psmctx->ssc, 1); } return update_iv(ctx); @@ -958,7 +972,7 @@ reset_ssc(struct sm_ctx *ctx) return SC_ERROR_INVALID_ARGUMENTS; struct pace_sm_ctx *psmctx = ctx->cipher_ctx; - psmctx->ssc = 0; + BN_zero(psmctx->ssc); return update_iv(ctx); } @@ -995,9 +1009,8 @@ int pace_sm_encrypt(sc_card_t *card, const struct sm_ctx *ctx, r = SC_ERROR_OUT_OF_MEMORY; goto err; } - memcpy(p, encbuf->data, encbuf->length); - *enc = p; + memcpy(*enc, encbuf->data, encbuf->length); r = encbuf->length; err: @@ -1036,9 +1049,8 @@ int pace_sm_decrypt(sc_card_t *card, const struct sm_ctx *ctx, r = SC_ERROR_OUT_OF_MEMORY; goto err; } - memcpy(p, databuf->data, databuf->length); - *data = p; + memcpy(*data, databuf->data, databuf->length); r = databuf->length; err: @@ -1056,9 +1068,8 @@ int pace_sm_authenticate(sc_card_t *card, const struct sm_ctx *ctx, const u8 *data, size_t datalen, u8 **macdata) { BUF_MEM *databuf = NULL, *macbuf = NULL; - u8 *p = NULL; + u8 *p = NULL, *ssc = NULL; int r; - size_t oldlen; if (!ctx || !ctx->cipher_ctx) { r = SC_ERROR_INVALID_ARGUMENTS; @@ -1066,22 +1077,29 @@ int pace_sm_authenticate(sc_card_t *card, const struct sm_ctx *ctx, } struct pace_sm_ctx *psmctx = ctx->cipher_ctx; - databuf = encoded_ssc(psmctx->ssc, psmctx->ctx); + r = encode_ssc(psmctx->ssc, psmctx->ctx, &ssc); + if (r < 0) { + sc_error(card->ctx, "Could not get send sequence counter\n"); + goto err; + } + bin_log(card->ctx, "Encoded Send Sequence Counter", + ssc, r); + + databuf = BUF_MEM_create(r + datalen); if (!databuf) { - r = SC_ERROR_INTERNAL; + r = SC_ERROR_OUT_OF_MEMORY; goto err; } - oldlen = databuf->length; - if (!BUF_MEM_grow(databuf, oldlen + datalen)) { - r = SC_ERROR_INTERNAL; - goto err; - } - memcpy(databuf->data + oldlen, data, datalen); - databuf->length = oldlen + datalen; + memcpy(databuf->data, ssc, r); + memcpy(databuf->data + r, data, datalen); + databuf->length = r + datalen; + bin_log(card->ctx, "Data to authenticate (PACE)", + (u8 *) databuf->data, databuf->length); macbuf = PACE_authenticate(psmctx->ctx, psmctx->protocol, psmctx->key_mac, databuf); if (!macbuf) { + sc_error(card->ctx, "Could not get MAC\n"); r = SC_ERROR_INTERNAL; goto err; } @@ -1091,9 +1109,8 @@ int pace_sm_authenticate(sc_card_t *card, const struct sm_ctx *ctx, r = SC_ERROR_OUT_OF_MEMORY; goto err; } - memcpy(p, macbuf->data, macbuf->length); - *macdata = p; + memcpy(*macdata, macbuf->data, macbuf->length); r = macbuf->length; err: @@ -1103,6 +1120,8 @@ err: } if (macbuf) BUF_MEM_free(macbuf); + if (ssc) + free(ssc); SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, r); } diff --git a/ccid/pace.h b/ccid/pace.h index 2b7455b..451d7c5 100644 --- a/ccid/pace.h +++ b/ccid/pace.h @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -44,7 +45,7 @@ extern "C" { struct pace_sm_ctx { int protocol; /* XXX SSC is up to 16 Bytes long, not only 16 Bits */ - uint16_t ssc; + BIGNUM *ssc; const BUF_MEM *key_mac; const BUF_MEM *key_enc; PACE_CTX *ctx; diff --git a/ccid/pace_lib.c b/ccid/pace_lib.c index b9f259f..ab85e33 100644 --- a/ccid/pace_lib.c +++ b/ccid/pace_lib.c @@ -28,6 +28,12 @@ pace_sm_ctx_create(int protocol, const BUF_MEM *key_mac, if (!out) return NULL; + out->ssc = BN_new(); + if (!out->ssc) { + free(out); + return NULL; + } + out->key_enc = key_enc; out->key_mac = key_mac; out->protocol = protocol; @@ -40,6 +46,8 @@ void pace_sm_ctx_free(struct pace_sm_ctx *ctx) { if (ctx) { + if (ctx->ssc) + BN_clear_free(ctx->ssc); free(ctx); } } diff --git a/ccid/sm.c b/ccid/sm.c index c7d3c80..643f768 100644 --- a/ccid/sm.c +++ b/ccid/sm.c @@ -26,11 +26,11 @@ static const struct sc_asn1_entry c_sm_capdu[] = { { "Padding-content indicator followed by cryptogram", - SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x07, SC_ASN1_OPTIONAL , NULL, NULL }, + SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x07, SC_ASN1_OPTIONAL, NULL, NULL }, { "Protected Le", - SC_ASN1_INTEGER , SC_ASN1_CTX|0x17, SC_ASN1_OPTIONAL|SC_ASN1_UNSIGNED, NULL, NULL }, + SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x17, SC_ASN1_OPTIONAL, NULL, NULL }, { "Cryptographic Checksum", - SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x0E, SC_ASN1_OPTIONAL , NULL, NULL }, + SC_ASN1_OCTET_STRING, SC_ASN1_CTX|0x0E, SC_ASN1_OPTIONAL, NULL, NULL }, { NULL , 0 , 0 , 0 , NULL , NULL } }; @@ -49,9 +49,9 @@ void bin_log(sc_context_t *ctx, const char *label, const u8 *data, size_t len) char buf[1024]; sc_hex_dump(ctx, data, len, buf, sizeof buf); - sc_debug(ctx, "%s (%u bytes):\n%s" + sc_debug(ctx, "%s (%u byte%s):\n%s" "======================================================================", - label, len, buf); + label, len, len==1?"":"s", buf); } int @@ -73,12 +73,12 @@ add_iso_pad(const u8 *data, size_t datalen, int block_size, u8 **padded) if (*padded != data) memcpy(p, data, datalen); + *padded = p; + /* now add iso padding */ memset(p + datalen, 0x80, 1); memset(p + datalen + 1, 0, p_len - datalen - 1); - *padded = p; - return p_len; } @@ -94,8 +94,8 @@ add_padding(const struct sm_ctx *ctx, const u8 *data, size_t datalen, p = realloc(*padded, datalen); if (!p) return SC_ERROR_OUT_OF_MEMORY; - memcpy(p, data, datalen); *padded = p; + memcpy(*padded, data, datalen); } return datalen; case SM_ISO_PADDING: @@ -131,32 +131,39 @@ int no_padding(u8 padding_indicator, const u8 *data, size_t datalen) return len; } -static u8 * format_le(size_t le_len, size_t le, struct sc_asn1_entry *le_entry) +static int format_le(size_t le, struct sc_asn1_entry *le_entry, + u8 **lebuf, size_t *le_len) { - u8 * lebuf = malloc(le_len); - if (lebuf) { - switch (le_len) { - case 1: - lebuf[0] = le; - break; - case 2: - lebuf[0] = htons(le) >> 8; - lebuf[1] = htons(le) & 0xff; - break; - case 3: - lebuf[0] = 0x00; - lebuf[1] = htons(le) >> 8; - lebuf[2] = htons(le) & 0xff; - break; - default: - free(lebuf); - return NULL; - } + u8 *p; - sc_format_asn1_entry(le_entry, lebuf, &le_len, SC_ASN1_PRESENT); + if (!lebuf || !le_len) + return SC_ERROR_INVALID_ARGUMENTS; + + p = realloc(*lebuf, *le_len); + if (!p) + return SC_ERROR_OUT_OF_MEMORY; + + switch (*le_len) { + case 1: + p[0] = le; + break; + case 2: + p[0] = htons(le) >> 8; + p[1] = htons(le) & 0xff; + break; + case 3: + p[0] = 0x00; + p[1] = htons(le) >> 8; + p[2] = htons(le) & 0xff; + break; + default: + return SC_ERROR_INVALID_ARGUMENTS; } + *lebuf = p; - return lebuf; + sc_format_asn1_entry(le_entry, *lebuf, le_len, SC_ASN1_PRESENT); + + return SC_SUCCESS; } static int prefix_buf(u8 prefix, u8 *buf, size_t buflen, u8 **cat) @@ -198,7 +205,6 @@ static int format_data(sc_card_t *card, const struct sm_ctx *ctx, goto err; pad_data_len = r; - printf("%d\n", pad_data_len); r = ctx->encrypt(card, ctx, pad_data, pad_data_len, formatted_data); if (r < 0) { sc_error(card->ctx, "Could not encrypt the data"); @@ -211,7 +217,7 @@ static int format_data(sc_card_t *card, const struct sm_ctx *ctx, *formatted_data_len = r; sc_format_asn1_entry(formatted_encrypted_data_entry, - formatted_data, formatted_data_len, SC_ASN1_PRESENT); + *formatted_data, formatted_data_len, SC_ASN1_PRESENT); r = SC_SUCCESS; @@ -249,7 +255,7 @@ static int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, struct sc_asn1_entry sm_capdu[4]; u8 *p, *le = NULL, *sm_data = NULL, *fdata = NULL, *mac_data = NULL, *asn1 = NULL, *mac = NULL; - size_t sm_data_len, fdata_len, mac_data_len, asn1_len, mac_len; + size_t sm_data_len, fdata_len, mac_data_len, asn1_len, mac_len, le_len; int r; if (!apdu || !ctx || !card || !card->slot || !sm_apdu) { @@ -280,31 +286,33 @@ static int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, case SC_APDU_CASE_1: break; case SC_APDU_CASE_2_SHORT: - le = format_le(1, apdu->le, sm_capdu + 1); - if (!le) { + le_len = 1; + r = format_le(apdu->le, sm_capdu + 1, &le, &le_len); + if (r < 0) { sc_error(card->ctx, "Could not format Le of SM apdu"); - r = SC_ERROR_WRONG_LENGTH; goto err; } + bin_log(card->ctx, "Protected Le (plain)", le, le_len); break; case SC_APDU_CASE_2_EXT: if (card->slot->active_protocol == SC_PROTO_T0) { /* T0 extended APDUs look just like short APDUs */ - le = format_le(1, apdu->le, sm_capdu + 1); - if (!le) { + le_len = 1; + r = format_le(apdu->le, sm_capdu + 1, &le, &le_len); + if (r < 0) { sc_error(card->ctx, "Could not format Le of SM apdu"); - r = SC_ERROR_WRONG_LENGTH; goto err; } } else { /* in case of T1 always use 3 bytes for length */ - le = format_le(3, apdu->le, sm_capdu + 1); - if (!le) { + le_len = 3; + r = format_le(apdu->le, sm_capdu + 1, &le, &le_len); + if (r < 0) { sc_error(card->ctx, "Could not format Le of SM apdu"); - r = SC_ERROR_WRONG_LENGTH; goto err; } } + bin_log(card->ctx, "Protected Le (plain)", le, le_len); break; case SC_APDU_CASE_3_SHORT: case SC_APDU_CASE_3_EXT: @@ -314,16 +322,19 @@ static int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, sc_error(card->ctx, "Could not format data of SM apdu"); goto err; } + bin_log(card->ctx, "Padding-content indicator followed by cryptogram (plain)", + fdata, fdata_len); break; case SC_APDU_CASE_4_SHORT: /* in case of T0 no Le byte is added */ if (card->slot->active_protocol != SC_PROTO_T0) { - le = format_le(1, apdu->le, sm_capdu + 1); - if (!le) { + le_len = 1; + r = format_le(apdu->le, sm_capdu + 1, &le, &le_len); + if (r < 0) { sc_error(card->ctx, "Could not format Le of SM apdu"); - r = SC_ERROR_WRONG_LENGTH; goto err; } + bin_log(card->ctx, "Protected Le (plain)", le, le_len); } r = format_data(card, ctx, apdu->data, apdu->datalen, @@ -332,6 +343,8 @@ static int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, sc_error(card->ctx, "Could not format data of SM apdu"); goto err; } + bin_log(card->ctx, "Padding-content indicator followed by cryptogram (plain)", + fdata, fdata_len); break; case SC_APDU_CASE_4_EXT: if (card->slot->active_protocol == SC_PROTO_T0) { @@ -341,12 +354,13 @@ static int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, } else { /* only 2 bytes are use to specify the length of the * expected data */ - le = format_le(2, apdu->le, sm_capdu + 1); - if (!le) { + le_len = 2; + r = format_le(apdu->le, sm_capdu + 1, &le, &le_len); + if (r < 0) { sc_error(card->ctx, "Could not format Le of SM apdu"); - r = SC_ERROR_WRONG_LENGTH; goto err; } + bin_log(card->ctx, "Protected Le (plain)", le, le_len); } r = format_data(card, ctx, apdu->data, apdu->datalen, @@ -355,6 +369,8 @@ static int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, sc_error(card->ctx, "Could not format data of SM apdu"); goto err; } + bin_log(card->ctx, "Padding-content indicator followed by cryptogram (plain)", + fdata, fdata_len); break; default: sc_error(card->ctx, "Unhandled apdu case"); @@ -376,6 +392,12 @@ static int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, memcpy(mac_data + mac_data_len, asn1, asn1_len); mac_data_len += asn1_len; r = add_padding(ctx, mac_data, mac_data_len, &mac_data); + if (r < 0) { + goto err; + } + mac_data_len = r; + bin_log(card->ctx, "Data to authenticate", mac_data, mac_data_len); + r = ctx->authenticate(card, ctx, mac_data, mac_data_len, &mac); if (r < 0) { @@ -383,9 +405,9 @@ static int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, goto err; } mac_len = r; - bin_log(card->ctx, "mac", mac, mac_len); sc_format_asn1_entry(sm_capdu + 2, mac, &mac_len, SC_ASN1_PRESENT); + bin_log(card->ctx, "Cryptographic Checksum (plain)", mac, mac_len); /* format SM apdu */ @@ -397,7 +419,7 @@ static int sm_encrypt(const struct sm_ctx *ctx, sc_card_t *card, sm_apdu->lc = sm_apdu->datalen; sm_apdu->le = 0; sm_apdu->cse = SC_APDU_CASE_4; - bin_log(card->ctx, "sm apdu data", sm_apdu->data, sm_apdu->datalen); + bin_log(card->ctx, "ASN.1 encoded APDU data", sm_apdu->data, sm_apdu->datalen); err: if (fdata) { @@ -483,9 +505,14 @@ static int sm_decrypt(const struct sm_ctx *ctx, sc_card_t *card, apdu->resp = data; apdu->resplen = r; } else { - apdu->resplen = r; + apdu->resplen = 0; } + sc_debug(card->ctx, "Decrypted APDU sw1=%02x sw2=%02x", + apdu->sw1, apdu->sw2); + bin_log(card->ctx, "Decrypted APDU response data", + apdu->resp, apdu->resplen); + /* XXX verify mac */ r = SC_SUCCESS; @@ -509,7 +536,6 @@ int sm_transmit_apdu(const struct sm_ctx *sctx, sc_card_t *card, SC_TEST_RET(card->ctx, sm_encrypt(sctx, card, apdu, &sm_apdu), "Could not encrypt APDU."); - bin_log(card->ctx, "SM APDU data", sm_apdu.data, sm_apdu.datalen); sm_apdu.resplen = sizeof *buf; sm_apdu.resp = buf; @@ -520,7 +546,6 @@ int sm_transmit_apdu(const struct sm_ctx *sctx, sc_card_t *card, "Card returned error."); SC_TEST_RET(card->ctx, sm_decrypt(sctx, card, &sm_apdu, apdu), "Could not decrypt APDU."); - bin_log(card->ctx, "SM APDU response", apdu->resp, apdu->resplen); SC_FUNC_RETURN(card->ctx, SC_LOG_TYPE_ERROR, SC_SUCCESS); }