static int format_data(sc_card_t *card, const struct iso_sm_ctx *ctx, const u8 *data, size_t datalen, struct sc_asn1_entry *formatted_encrypted_data_entry, u8 **formatted_data, size_t *formatted_data_len) { int r; u8 *pad_data = NULL; size_t pad_data_len = 0; if (!ctx || !formatted_data || !formatted_data_len) { r = SC_ERROR_INVALID_ARGUMENTS; goto err; } r = add_padding(ctx, data, datalen, &pad_data); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not add padding to data: %s", sc_strerror(r)); goto err; } pad_data_len = r; bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Data to encrypt", pad_data, pad_data_len); r = ctx->encrypt(card, ctx, pad_data, pad_data_len, formatted_data); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not encrypt the data"); goto err; } bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Cryptogram", *formatted_data, r); r = prefix_buf(ctx->padding_indicator, *formatted_data, r, formatted_data); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not prepend padding indicator to formatted " "data: %s", sc_strerror(r)); goto err; } *formatted_data_len = r; sc_format_asn1_entry(formatted_encrypted_data_entry, *formatted_data, formatted_data_len, SC_ASN1_PRESENT); r = SC_SUCCESS; err: if (pad_data) { sc_mem_clear(pad_data, pad_data_len); free(pad_data); } return r; }
int npa_translate_apdus(sc_card_t *card, FILE *input) { u8 buf[4 + 3 + 0xffff + 3]; char *read = NULL; size_t readlen = 0, apdulen; sc_apdu_t apdu; ssize_t linelen; int r; memset(&apdu, 0, sizeof apdu); while (1) { if (input == stdin) printf("Enter unencrypted C-APDU (empty line to exit)\n"); linelen = getline(&read, &readlen, input); if (linelen <= 1) { if (linelen < 0) { r = SC_ERROR_INTERNAL; sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE_TOOL, "Could not read line"); } else { r = SC_SUCCESS; printf("Thanks for flying with ccid\n"); } break; } read[linelen - 1] = 0; apdulen = sizeof buf; if (sc_hex_to_bin(read, buf, &apdulen) < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE_TOOL, "Could not format binary string"); continue; } if (input != stdin) bin_print(stdout, "Unencrypted C-APDU", buf, apdulen); r = sc_bytes2apdu(card->ctx, buf, apdulen, &apdu); if (r < 0) { bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Invalid C-APDU", buf, apdulen); continue; } apdu.resp = buf; apdu.resplen = sizeof buf; r = sc_transmit_apdu(card, &apdu); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE_TOOL, "Could not send C-APDU: %s", sc_strerror(r)); continue; } printf("Decrypted R-APDU sw1=%02x sw2=%02x\n", apdu.sw1, apdu.sw2); bin_print(stdout, "Decrypted R-APDU response data", apdu.resp, apdu.resplen); printf("======================================================================\n"); } if (read) free(read); return r; }
static int sm_decrypt(const struct iso_sm_ctx *ctx, sc_card_t *card, const sc_apdu_t *sm_apdu, sc_apdu_t *apdu) { int r; struct sc_asn1_entry sm_rapdu[4]; struct sc_asn1_entry my_sm_rapdu[4]; u8 sw[2], mac[8], fdata[SC_MAX_EXT_APDU_BUFFER_SIZE]; size_t sw_len = sizeof sw, mac_len = sizeof mac, fdata_len = sizeof fdata, buf_len, asn1_len; const u8 *buf; u8 *data = NULL, *mac_data = NULL, *asn1 = NULL; sc_copy_asn1_entry(c_sm_rapdu, sm_rapdu); sc_format_asn1_entry(sm_rapdu + 0, fdata, &fdata_len, 0); sc_format_asn1_entry(sm_rapdu + 1, sw, &sw_len, 0); sc_format_asn1_entry(sm_rapdu + 2, mac, &mac_len, 0); r = sc_asn1_decode(card->ctx, sm_rapdu, sm_apdu->resp, sm_apdu->resplen, &buf, &buf_len); if (r < 0) goto err; if (buf_len > 0) { r = SC_ERROR_UNKNOWN_DATA_RECEIVED; goto err; } if (sm_rapdu[2].flags & SC_ASN1_PRESENT) { /* copy from sm_apdu to my_sm_apdu, but leave mac at default */ sc_copy_asn1_entry(sm_rapdu, my_sm_rapdu); sc_copy_asn1_entry(&c_sm_rapdu[2], &my_sm_rapdu[2]); r = sc_asn1_encode(card->ctx, my_sm_rapdu, &asn1, &asn1_len); if (r < 0) goto err; r = add_padding(ctx, asn1, asn1_len, &mac_data); if (r < 0) { goto err; } r = ctx->verify_authentication(card, ctx, mac, mac_len, mac_data, r); if (r < 0) goto err; } else { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Cryptographic Checksum missing"); r = SC_ERROR_ASN1_OBJECT_NOT_FOUND; goto err; } if (sm_rapdu[0].flags & SC_ASN1_PRESENT) { if (ctx->padding_indicator != fdata[0]) { r = SC_ERROR_UNKNOWN_DATA_RECEIVED; goto err; } r = ctx->decrypt(card, ctx, fdata + 1, fdata_len - 1, &data); if (r < 0) goto err; buf_len = r; r = rm_padding(ctx->padding_indicator, data, buf_len); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not remove padding"); goto err; } if (apdu->resplen < r || (r && !apdu->resp)) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Response of SM APDU %u byte%s too long", r-apdu->resplen, r-apdu->resplen < 2 ? "" : "s"); r = SC_ERROR_OUT_OF_MEMORY; goto err; } /* Flawfinder: ignore */ memcpy(apdu->resp, data, r); apdu->resplen = r; } else { apdu->resplen = 0; } if (sm_rapdu[1].flags & SC_ASN1_PRESENT) { if (sw_len != 2) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Length of processing status bytes must be 2"); r = SC_ERROR_ASN1_END_OF_CONTENTS; goto err; } apdu->sw1 = sw[0]; apdu->sw2 = sw[1]; } else { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Authenticated status bytes are missing"); r = SC_ERROR_ASN1_OBJECT_NOT_FOUND; goto err; } sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Decrypted APDU sw1=%02x sw2=%02x", apdu->sw1, apdu->sw2); bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Decrypted APDU response data", apdu->resp, apdu->resplen); r = SC_SUCCESS; err: free(asn1); free(mac_data); if (data) { sc_mem_clear(data, buf_len); free(data); } return r; }
static int sm_encrypt(const struct iso_sm_ctx *ctx, sc_card_t *card, const sc_apdu_t *apdu, sc_apdu_t **psm_apdu) { struct sc_asn1_entry sm_capdu[4]; u8 *p, *le = NULL, *sm_data = NULL, *fdata = NULL, *mac_data = NULL, *asn1 = NULL, *mac = NULL, *resp_data = NULL; size_t sm_data_len, fdata_len, mac_data_len, asn1_len, mac_len, le_len; int r, cse; sc_apdu_t *sm_apdu = NULL; if (!apdu || !ctx || !card || !card->reader || !psm_apdu) { r = SC_ERROR_INVALID_ARGUMENTS; goto err; } if ((apdu->cla & 0x0C) == 0x0C) { r = SC_ERROR_INVALID_ARGUMENTS; sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Given APDU is already protected with some secure messaging"); goto err; } sc_copy_asn1_entry(c_sm_capdu, sm_capdu); sm_apdu = malloc(sizeof(sc_apdu_t)); if (!sm_apdu) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } sm_apdu->control = apdu->control; sm_apdu->flags = apdu->flags; sm_apdu->cla = apdu->cla|0x0C; sm_apdu->ins = apdu->ins; sm_apdu->p1 = apdu->p1; sm_apdu->p2 = apdu->p2; r = format_head(ctx, sm_apdu, &mac_data); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format header of SM apdu"); goto err; } mac_data_len = r; /* get le and data depending on the case of the insecure command */ cse = apdu->cse; if ((apdu->le/ctx->block_length + 1)*ctx->block_length + 18 > 0xff+1) /* for encrypted APDUs we usually get authenticated status bytes (4B), * a MAC (11B) and a cryptogram with padding indicator (3B without * data). The cryptogram is always padded to the block size. */ cse |= SC_APDU_EXT; switch (cse) { case SC_APDU_CASE_1: break; case SC_APDU_CASE_2_SHORT: le_len = 1; r = format_le(apdu->le, sm_capdu + 1, &le, &le_len); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format Le of SM apdu"); goto err; } bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Protected Le (plain)", le, le_len); break; case SC_APDU_CASE_2_EXT: if (card->reader->active_protocol == SC_PROTO_T0) { /* T0 extended APDUs look just like short APDUs */ le_len = 1; r = format_le(apdu->le, sm_capdu + 1, &le, &le_len); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format Le of SM apdu"); goto err; } } else { /* in case of T1 always use 2 bytes for length */ le_len = 2; r = format_le(apdu->le, sm_capdu + 1, &le, &le_len); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format Le of SM apdu"); goto err; } } bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Protected Le (plain)", le, le_len); break; case SC_APDU_CASE_3_SHORT: case SC_APDU_CASE_3_EXT: r = format_data(card, ctx, apdu->data, apdu->datalen, sm_capdu + 0, &fdata, &fdata_len); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format data of SM apdu"); goto err; } bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "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->reader->active_protocol != SC_PROTO_T0) { le_len = 1; r = format_le(apdu->le, sm_capdu + 1, &le, &le_len); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format Le of SM apdu"); goto err; } bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Protected Le (plain)", le, le_len); } r = format_data(card, ctx, apdu->data, apdu->datalen, sm_capdu + 0, &fdata, &fdata_len); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format data of SM apdu"); goto err; } bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Padding-content indicator followed by cryptogram (plain)", fdata, fdata_len); break; case SC_APDU_CASE_4_EXT: if (card->reader->active_protocol == SC_PROTO_T0) { /* again a T0 extended case 4 APDU looks just * like a short APDU, the additional data is * transferred using ENVELOPE and GET RESPONSE */ } else { /* only 2 bytes are use to specify the length of the * expected data */ le_len = 2; r = format_le(apdu->le, sm_capdu + 1, &le, &le_len); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format Le of SM apdu"); goto err; } bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Protected Le (plain)", le, le_len); } r = format_data(card, ctx, apdu->data, apdu->datalen, sm_capdu + 0, &fdata, &fdata_len); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not format data of SM apdu"); goto err; } bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Padding-content indicator followed by cryptogram (plain)", fdata, fdata_len); break; default: sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Unhandled apdu case"); r = SC_ERROR_INVALID_DATA; goto err; } r = sc_asn1_encode(card->ctx, sm_capdu, (u8 **) &asn1, &asn1_len); if (r < 0) { goto err; } if (asn1_len) { p = realloc(mac_data, mac_data_len + asn1_len); if (!p) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } mac_data = p; /* Flawfinder: ignore */ 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, SC_LOG_DEBUG_NORMAL, "Data to authenticate", mac_data, mac_data_len); r = ctx->authenticate(card, ctx, mac_data, mac_data_len, &mac); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not get authentication code"); goto err; } mac_len = r; bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "Cryptographic Checksum (plain)", mac, mac_len); /* format SM apdu */ sc_format_asn1_entry(sm_capdu + 2, mac, &mac_len, SC_ASN1_PRESENT); r = sc_asn1_encode(card->ctx, sm_capdu, (u8 **) &sm_data, &sm_data_len); if (r < 0) goto err; sm_apdu->data = sm_data; sm_apdu->datalen = sm_data_len; sm_apdu->lc = sm_data_len; sm_apdu->le = 0; if (cse & SC_APDU_EXT) { sm_apdu->cse = SC_APDU_CASE_4_EXT; #if OPENSC_NOT_BOGUS_ANYMORE sm_apdu->resplen = 0xffff+1; #else sm_apdu->resplen = SC_MAX_EXT_APDU_BUFFER_SIZE; #endif } else { sm_apdu->cse = SC_APDU_CASE_4_SHORT; #if OPENSC_NOT_BOGUS_ANYMORE sm_apdu->resplen = 0xff+1; #else sm_apdu->resplen = SC_MAX_APDU_BUFFER_SIZE; #endif } resp_data = malloc(sm_apdu->resplen); if (!resp_data) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } sm_apdu->resp = resp_data; bin_log(card->ctx, SC_LOG_DEBUG_NORMAL, "ASN.1 encoded encrypted APDU data", sm_apdu->data, sm_apdu->datalen); *psm_apdu = sm_apdu; err: free(fdata); free(asn1); free(mac_data); free(mac); free(le); if (r < 0) { free(resp_data); free(sm_apdu); free(sm_data); } return r; }